felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r1570227 - in /felix/sandbox/marrs/dependencymanager-prototype/dm: src/dm/ src/dm/impl/ test/test/
Date Thu, 20 Feb 2014 15:31:22 GMT
Author: marrs
Date: Thu Feb 20 15:31:22 2014
New Revision: 1570227

URL: http://svn.apache.org/r1570227
Log:
Added configuration dependencies and some tests.

Added:
    felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ConfigurationDependencyImpl.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ConfigurationTest.java
Modified:
    felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Dependency.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/DependencyImpl.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/SerialExecutorTest.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ServiceRaceTest.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/TestBase.java

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Dependency.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Dependency.java?rev=1570227&r1=1570226&r2=1570227&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Dependency.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Dependency.java Thu Feb 20 15:31:22
2014
@@ -23,6 +23,10 @@ public interface Dependency {
 
 	public boolean isInstanceBound();
 	public void setInstanceBound(boolean instanceBound);
+	
+	/** Does this dependency need the component instances to determine if the dependency is
available or not */
+	public boolean needsInstance();
+	
 	public void setCallbacks(String add, String remove);
 	public void setCallbacks(String add, String change, String remove);
 	

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java?rev=1570227&r1=1570226&r2=1570227&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java Thu
Feb 20 15:31:22 2014
@@ -2,7 +2,6 @@ package dm.impl;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
@@ -15,8 +14,8 @@ public class ComponentImpl implements Co
     private static final Class[] VOID = new Class[] {};
 	private final SerialExecutor m_executor = new SerialExecutor(new Logger(null));
 	private ComponentState m_state = ComponentState.INACTIVE;
-	private List<Dependency> m_dependencies = new CopyOnWriteArrayList<>();
-	private List<ComponentStateListener> m_listeners = new CopyOnWriteArrayList<>();
+	private final List<Dependency> m_dependencies = new CopyOnWriteArrayList<>();
+	private final List<ComponentStateListener> m_listeners = new CopyOnWriteArrayList<>();
 	private boolean m_isStarted;
 	
 	private Object m_componentDefinition;
@@ -149,11 +148,23 @@ public class ComponentImpl implements Co
 		return available;
 	}
 
+    private boolean someDependenciesNeedInstance() {
+        for (Dependency d : m_dependencies) {
+            if (d.needsInstance()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 	/** Perform all the actions associated with state transitions. Returns true if a transition
was performed. */
 	private boolean performTransition(ComponentState oldState, ComponentState newState) {
 //		System.out.println("transition from " + oldState + " to " + newState);
 		if (oldState == ComponentState.INACTIVE && newState == ComponentState.WAITING_FOR_REQUIRED)
{
 			for (Dependency d : m_dependencies) {
+			    if (d.needsInstance()) {
+			        instantiateComponent();
+			    }
 				d.start();
 			}
 			notifyListeners(newState);
@@ -182,13 +193,16 @@ public class ComponentImpl implements Co
 			invoke("destroy");
 			invokeRemoveRequiredDependencies();
 			notifyListeners(newState);
-			destroyComponent();
+			if (! someDependenciesNeedInstance()) {
+                destroyComponent();
+            }
 			return true;
 		}
 		if (oldState == ComponentState.WAITING_FOR_REQUIRED && newState == ComponentState.INACTIVE)
{
 			for (Dependency d : m_dependencies) {
 				d.stop();
 			}
+            destroyComponent();
 			notifyListeners(newState);
 			return true;
 		}
@@ -197,17 +211,19 @@ public class ComponentImpl implements Co
 	
 	private void instantiateComponent() {
 		// TODO add more complex factory instantiations of one or more components in a composition
here
-		if (m_componentDefinition instanceof Class) {
-			try {
-				m_componentInstance = createInstance((Class) m_componentDefinition);
-			}
-			catch (Exception e) {
-				e.printStackTrace();
-			}
-		}
-		else {
-			m_componentInstance = m_componentDefinition;
-		}
+	    if (m_componentInstance == null) {
+            if (m_componentDefinition instanceof Class) {
+                try {
+                    m_componentInstance = createInstance((Class) m_componentDefinition);
+                }
+                catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+            else {
+                m_componentInstance = m_componentDefinition;
+            }
+	    }
 	}
 	
 	private void destroyComponent() {

Added: felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ConfigurationDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ConfigurationDependencyImpl.java?rev=1570227&view=auto
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ConfigurationDependencyImpl.java
(added)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ConfigurationDependencyImpl.java
Thu Feb 20 15:31:22 2014
@@ -0,0 +1,135 @@
+package dm.impl;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Dictionary;
+
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+import dm.Event;
+
+public class ConfigurationDependencyImpl extends DependencyImpl implements ManagedService
{
+    private Dictionary m_settings;
+    private String m_callback = "updated";
+
+    public ConfigurationDependencyImpl() {
+        setRequired(true);
+    }
+
+    public ConfigurationDependencyImpl setCallback(String callback) {
+        m_callback = callback;
+        return this;
+    }
+
+    @Override
+    public boolean needsInstance() {
+        return true;
+    }
+
+    @Override
+    public void start() {
+        super.start();
+        // Register our managed service in the service registry
+    }
+
+    @Override
+    public void stop() {
+        super.stop();
+        // Unregister our managed service from the service registry
+    }
+
+    @Override
+    public void updated(Dictionary settings) throws ConfigurationException {
+        Dictionary<?,?> oldSettings = null;
+        synchronized (this) {
+            oldSettings = m_settings;
+        }
+
+        if (oldSettings == null && settings == null) {
+            // CM has started but our configuration is not still present in the CM database:
ignore
+            return;
+        }
+
+        // If this is initial settings, or a configuration update, we handle it synchronously.
+        // We'll conclude that the dependency is available only if invoking updated did not
cause
+        // any ConfigurationException.
+        if (settings != null) {
+            Object[] instances = m_component.getInstances();
+            if (instances != null) {
+                invokeUpdated(settings);
+            }
+        }
+        
+        // At this point, we have accepted the configuration.
+        synchronized (this) {
+            m_settings = settings;
+        }
+
+        if ((oldSettings == null) && (settings != null)) {
+            // Notify the component that our dependency is available.
+            add(new EventImpl());
+        }
+        else if ((oldSettings != null) && (settings != null)) {
+            // Notify the component that our dependency has changed.
+            change(new EventImpl());
+        }
+        else if ((oldSettings != null) && (settings == null)) {
+            // Notify the component that our dependency has been removed.
+            // Notice that the component will be stopped, and then all required dependencies
will be unbound
+            // (including our configuration dependency).
+            remove(new EventImpl());
+        }
+    }
+
+    public void invokeAdd() {
+        // We already did that synchronously, from our updated method
+    }
+
+    public void invokeChange() {
+        // We already did that synchronously, from our updated method
+    }
+
+    public void invokeRemove() {
+        // The configuration has gone, so, the state machine has stopped the component,
+        // and all required dependencies must now be removed, including our configuration

+        // dependency.
+        try {
+            invokeUpdated(null);
+        } catch (ConfigurationException e) {
+            e.printStackTrace(); // FIXME use a LogService
+        }
+    }
+    
+    private void invokeUpdated(Dictionary settings) throws ConfigurationException {
+        Object[] instances = m_component.getInstances();
+        if (instances != null) {
+            for (int i = 0; i < instances.length; i++) {
+                try {
+                    InvocationUtil.invokeCallbackMethod(instances[i], m_callback, 
+                        new Class[][] { { Dictionary.class }, {} }, 
+                        new Object[][] { { settings }, {} });
+                }
+
+                catch (InvocationTargetException e) {
+                    // The component has thrown an exception during it's callback invocation.
+                    if (e.getTargetException() instanceof ConfigurationException) {
+                        // the callback threw an OSGi ConfigurationException: just re-throw
it.
+                        throw (ConfigurationException) e.getTargetException();
+                    }
+                    else {
+                        // wrap the callback exception into a ConfigurationException.
+                        throw new ConfigurationException(null, "Configuration update failed",
e.getTargetException());
+                    }
+                }
+                catch (NoSuchMethodException e) {
+                    // if the method does not exist, ignore it
+                }
+                catch (Throwable t) {
+                    // wrap any other exception as a ConfigurationException.
+                    throw new ConfigurationException(null, "Configuration update failed",
t);
+                }
+            }
+        }
+    }
+}

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/DependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/DependencyImpl.java?rev=1570227&r1=1570226&r2=1570227&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/DependencyImpl.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/DependencyImpl.java Thu
Feb 20 15:31:22 2014
@@ -168,4 +168,9 @@ public class DependencyImpl implements D
 	public void setRequired(boolean required) {
 		m_required = required;
 	}
+	
+    @Override
+    public boolean needsInstance() {
+        return false;
+    }
 }

Added: felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ConfigurationTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ConfigurationTest.java?rev=1570227&view=auto
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ConfigurationTest.java (added)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ConfigurationTest.java Thu
Feb 20 15:31:22 2014
@@ -0,0 +1,113 @@
+package test;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.junit.Test;
+import org.osgi.service.cm.ConfigurationException;
+
+import dm.Component;
+import dm.Dependency;
+import dm.impl.ComponentImpl;
+import dm.impl.ConfigurationDependencyImpl;
+import dm.impl.DependencyImpl;
+import dm.impl.EventImpl;
+
+public class ConfigurationTest extends TestBase {
+    @Test
+    public void testConfigurationFailure() throws Throwable {
+        final Ensure e = new Ensure();
+
+        // Create our configuration dependency
+        final ConfigurationDependencyImpl conf = new ConfigurationDependencyImpl();
+        conf.setCallbacks("updated", "updated");
+
+        // Create another required dependency
+        final Dependency requiredDependency = new DependencyImpl();
+        requiredDependency.setRequired(true);
+        requiredDependency.setCallbacks("addDep", null);
+
+        // Create our component, which will fail when handling configuration update
+        Component c = new ComponentImpl();
+
+        c.setImplementation(new Object() {
+            volatile Dictionary m_conf;
+
+            public void updated(Dictionary conf) {
+                debug("updated: conf=%s", conf);
+                m_conf = conf;
+                if ("invalid".equals(conf.get("conf"))) {
+                    // We refuse the first configuration. 
+                    debug("refusing configuration");
+                    e.step(1);
+                    // Set our acceptUpdate flag to true, so next update will be successful
+                    throw new RuntimeException("update failed (expected)");
+                }
+                else {
+                    debug("accepting configuration");
+                    e.step(2);
+                }
+            }
+
+            public void addDep() {
+                if ("invalid".equals(m_conf.get("conf"))) {
+                    e.throwable(new Exception("addDep should not be called"));
+                }
+                e.step(3);
+                debug("addDep");
+            }
+
+            void init(Component c) {
+                if ("invalid".equals(m_conf.get("conf"))) {
+                    e.throwable(new Exception("init should not be called"));
+                }
+                e.step(4);
+                debug("init");
+            }
+
+            void start() {
+                if ("invalid".equals(m_conf.get("conf"))) {
+                    e.throwable(new Exception("start should not be called"));
+                }
+                e.step(5);
+                debug("start");
+            }
+        });
+
+        // Add the dependencies
+        c.add(conf);
+        c.add(requiredDependency);
+
+        // Start our component ("requiredDependency" is not yet available, so we'll stay
in WAITING_FOR_REQUIRED state).
+        c.start();
+        
+        // Enabled "requiredDependency"
+        requiredDependency.add(new EventImpl());
+
+        // Now, act as the configuration admin service and inject a wrong dependency
+        try {
+            Hashtable props = new Hashtable();
+            props.put("conf", "invalid");
+            conf.updated(props);
+        }
+        catch (ConfigurationException err) {
+            warn("got expected configuration error");
+        }
+        e.waitForStep(1, 5000);
+        e.ensure();
+        
+        // Now, inject another valid configuration
+        try {
+            Hashtable props = new Hashtable();
+            props.put("conf", "valid");
+            conf.updated(props);
+        }
+        catch (ConfigurationException err) {
+            warn("got expected configuration error");
+        }
+        
+        // This time, our component should be started properly.
+        e.waitForStep(5, 5000);
+        e.ensure();
+    }
+}

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/SerialExecutorTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/SerialExecutorTest.java?rev=1570227&r1=1570226&r2=1570227&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/SerialExecutorTest.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/SerialExecutorTest.java Thu
Feb 20 15:31:22 2014
@@ -18,7 +18,7 @@ import dm.impl.SerialExecutor;
  */
 public class SerialExecutorTest extends TestBase {
     final Random m_rnd = new Random();
-    final int TESTS = 10000;
+    final int TESTS = 100000;
     
     @Test
     public void testSerialExecutor() {
@@ -96,13 +96,7 @@ public class SerialExecutorTest extends 
                     return;
                 }
             }
-            
-            try {
-                Thread.sleep(m_rnd.nextInt(1));
-            }
-            catch (InterruptedException e) {
-            }
-            
+                        
             if (m_firstExecution) {
                 m_firstExecution = false;
                 m_exec.execute(this); // Our run method must be called immediately

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ServiceRaceTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ServiceRaceTest.java?rev=1570227&r1=1570226&r2=1570227&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ServiceRaceTest.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ServiceRaceTest.java Thu
Feb 20 15:31:22 2014
@@ -1,17 +1,22 @@
 package test;
 
+import java.util.Dictionary;
+import java.util.Hashtable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.osgi.service.cm.ConfigurationException;
 
 import dm.Component;
 import dm.ComponentState;
 import dm.ComponentStateListener;
 import dm.Dependency;
+import dm.Event;
 import dm.impl.ComponentImpl;
+import dm.impl.ConfigurationDependencyImpl;
 import dm.impl.DependencyImpl;
 import dm.impl.EventImpl;
 
@@ -19,13 +24,12 @@ import dm.impl.EventImpl;
  * This test class simulates a client having many dependencies being registered/unregistered
concurrently.
  */
 public class ServiceRaceTest extends TestBase {
-    final static int STEP_WAIT = 10000;
+    final static int STEP_WAIT = 5000;
     final static int DEPENDENCIES = 10;
-    final static int LOOPS = 1000;
+    final static int LOOPS = 10000;
 
     // Executor used to bind/unbind service dependencies.
-    ExecutorService m_execDependencies;
-    
+    ExecutorService m_threadpool;
     // Timestamp used to log the time consumed to execute 100 tests.
     long m_timeStamp;
 
@@ -38,7 +42,7 @@ public class ServiceRaceTest extends Tes
         int cores = Math.max(16, Runtime.getRuntime().availableProcessors());
         info("using " + cores + " cores.");
 
-        m_execDependencies = Executors.newFixedThreadPool(cores);
+        m_threadpool = Executors.newFixedThreadPool(Math.max(cores, DEPENDENCIES + 3 /* start/stop/configure
*/));
 
         try {
             m_timeStamp = System.currentTimeMillis();
@@ -50,7 +54,7 @@ public class ServiceRaceTest extends Tes
             warn("got unexpected exception", t);
         }
         finally {
-            shutdown(m_execDependencies);
+            shutdown(m_threadpool);
         }
     }
 
@@ -62,85 +66,168 @@ public class ServiceRaceTest extends Tes
         catch (InterruptedException e) {
         }
     }
-    
-    void doTest(int loop) throws Exception {
-        debug("loop#%d -------------------------", loop);  
-        
-        final Ensure clientStarted = new Ensure(false);
-        
+
+    void doTest(int loop) throws Throwable {
+        debug("loop#%d -------------------------", loop);
+
+        final Ensure step = new Ensure(false);
+
         // Create one client component, which depends on many service dependencies
-        Component client = new ComponentImpl();
-        
-        // Create a client listener tracking client activation 
-        ComponentStateListener clientListener = new ComponentStateListener() {
-            @Override
-            public void changed(ComponentState state) {
-            	if (state == ComponentState.TRACKING_OPTIONAL) {
-            		clientStarted.step(1); // Our component must be started at most one time.
-            		debug("Client started");
-            	}
-            }
-        };
-        client.add(clientListener);
-                
+        final Component client = new ComponentImpl();
+        final Client theClient = new Client(step);
+        client.setImplementation(theClient);
+
         // Create client service dependencies
         final Dependency[] dependencies = new Dependency[DEPENDENCIES];
         for (int i = 0; i < DEPENDENCIES; i++) {
             dependencies[i] = new DependencyImpl();
             dependencies[i].setRequired(true);
+            dependencies[i].setCallbacks("add", "remove");
             client.add(dependencies[i]);
         }
-        
-        client.start();
-        
+        final ConfigurationDependencyImpl confDependency = new ConfigurationDependencyImpl();
+        client.add(confDependency);
+
+        // Create Configuration (concurrently).
+        // We have to simulate the configuration update, using a component state listener,
which will
+        // trigger an update thread, but only once the component is started.
+        final ComponentStateListener listener = new ComponentStateListener() {
+            private volatile Dictionary m_conf;
+
+            public void changed(ComponentState state) {
+                if (state == ComponentState.WAITING_FOR_REQUIRED && m_conf == null)
{
+                    m_conf = new Hashtable();
+                    m_conf.put("foo", "bar");
+                    m_threadpool.execute(new Runnable() {
+                        public void run() {
+                            try {
+                                confDependency.updated(m_conf);
+                            }
+                            catch (ConfigurationException e) {
+                                warn("configuration failed", e);
+                            }
+                        }
+                    });
+                }
+            }
+        };
+        client.add(listener);
+
         // Activate the client service dependencies concurrently.
         for (int i = 0; i < DEPENDENCIES; i++) {
             final Dependency dep = dependencies[i];
-            m_execDependencies.execute(new Runnable() {
+            final Event added = new EventImpl(i);
+            m_threadpool.execute(new Runnable() {
                 public void run() {
-                    dep.add(new EventImpl());
+                    dep.add(added);
                 }
             });
-        }        
-        
-        // Ensure that client has been started at most one time.
-        clientStarted.waitForStep(1, 10000);
-        
-//        System.out.println("DONE");
-//        System.exit(5);
-        
-        client.remove(clientListener);
+        }
 
-        // Stop the client service dependencies concurrently
-        final Ensure clientStopped = new Ensure(false);
-        clientListener = new ComponentStateListener() {
-            @Override
-            public void changed(ComponentState state) {
-            	if (state == ComponentState.WAITING_FOR_REQUIRED) {
-            		clientStopped.step(1); // Our component must be started at most one time.
-            		debug("Client stopped");
-            	}
+        // Start the client (concurrently)
+        m_threadpool.execute(new Runnable() {
+            public void run() {
+                client.start();
             }
-        };
-        client.add(clientListener);
-        
+        });
+
+        // Ensure that client has been started.
+        int expectedStep = 1 /* conf */ + DEPENDENCIES + 1 /* start */;
+        step.waitForStep(expectedStep, STEP_WAIT);
+        Assert.assertEquals(DEPENDENCIES, theClient.getDependencies());
+        Assert.assertNotNull(theClient.getConfiguration());
+        client.remove(listener);
+
+        // Stop the client and all dependencies concurrently.
         for (int i = 0; i < DEPENDENCIES; i++) {
             final Dependency dep = dependencies[i];
-            m_execDependencies.execute(new Runnable() {
+            final Event removed = new EventImpl(i);
+            m_threadpool.execute(new Runnable() {
                 public void run() {
-                    dep.remove(new EventImpl());
+                    dep.remove(removed);
                 }
             });
-        }        
+        }
+        m_threadpool.execute(new Runnable() {
+            public void run() {
+                client.stop();
+            }
+        });
+        m_threadpool.execute(new Runnable() {
+            public void run() {
+                try {
+                    confDependency.updated(null);
+                }
+                catch (ConfigurationException e) {
+                    warn("error while unconfiguring", e);
+                }
+            }
+        });
+
+        // Ensure that client has been stopped, then destroyed, then unbound from all dependencies
+        expectedStep += 2; // stop/destroy
+        expectedStep += DEPENDENCIES; // removed all dependencies
+        expectedStep += 1; // removed configuration
+        step.waitForStep(expectedStep, STEP_WAIT);
+        step.ensure();
+        Assert.assertEquals(0, theClient.getDependencies());
+        Assert.assertNull(theClient.getConfiguration());
 
-        // Ensure that client has been stopped at most one time.
-        clientStopped.waitForStep(1, 10000);        
-        
         debug("finished one test loop");
         if ((loop + 1) % 100 == 0) {
             long duration = System.currentTimeMillis() - m_timeStamp;
-            warn("Performed 100 tests (total=%d) in %d ms.", loop, duration);
+            warn("Performed 100 tests (total=%d) in %d ms.", (loop + 1), duration);
             m_timeStamp = System.currentTimeMillis();
         }
     }
+
+    public class Client {
+        final Ensure m_step;
+        volatile int m_dependencies;
+        volatile Dictionary m_conf;
+        
+        public Client(Ensure step) {
+            m_step = step;
+        }
+
+        public void updated(Dictionary conf) throws ConfigurationException {
+            m_conf = conf;
+            if (conf != null) {
+                Assert.assertEquals("bar", conf.get("foo"));
+                m_step.step(1);
+            } else {
+                m_step.step();
+            }
+        }
+        
+        void add() {
+            m_step.step();
+            m_dependencies ++;
+        }
+        
+        void remove() {
+            m_step.step();
+            m_dependencies --;
+        }
+                
+        void start() {
+            m_step.step((DEPENDENCIES + 1) /* deps + conf */ + 1 /* start */);
+        }
+
+        void stop() {
+            m_step.step((DEPENDENCIES + 1) /* deps + conf */ + 1 /* start */ + 1 /* stop
*/);
+        }
+        
+        void destroy() {
+            m_step.step((DEPENDENCIES + 1) /* deps + conf */ + 1 /* start */ + 1 /* stop
*/  + 1 /* destroy */);
+        }
+        
+        int getDependencies() {
+            return m_dependencies;
+        }
+        
+        Dictionary getConfiguration() {
+            return m_conf;
+        }
+    }
 }

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/TestBase.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/TestBase.java?rev=1570227&r1=1570226&r2=1570227&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/TestBase.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/TestBase.java Thu Feb 20
15:31:22 2014
@@ -15,7 +15,7 @@ public class TestBase {
     final int DEBUG = 3;
     
     // Set the enabled log level.
-    final int m_level = INFO;
+    final int m_level = WARN;
     
     void debug(String format, Object ... params) {
         if (m_level >= DEBUG) {



Mime
View raw message