Finalized this test before committing my version in the sandbox.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1564974 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ServiceRaceTest.java b/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ServiceRaceTest.java
index baec7ae..5f79c78 100644
--- a/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ServiceRaceTest.java
+++ b/dependencymanager/test/src/test/java/org/apache/felix/dm/test/integration/api/ServiceRaceTest.java
@@ -23,6 +23,7 @@
import java.util.Hashtable;
import java.util.Map;
import java.util.Queue;
+import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
@@ -64,32 +65,30 @@
warn("starting concurrent services");
int cores = Math.max(10, Runtime.getRuntime().availableProcessors());
final DependencyManager dm = new DependencyManager(context);
+ Random rnd = new Random();
try {
m_execServices = Executors.newFixedThreadPool(cores);
m_execAspects = Executors.newFixedThreadPool(cores);
- int aspectPidCounter = 1;
- int aspectCounter = 1;
+ int serviceIdCounter = 1;
long timeStamp = System.currentTimeMillis();
- final int tests = 100000;
+ final int tests = 30000;
for (int loop = 0; loop < tests; loop++) {
debug("loop#%d -------------------------", (loop + 1));
final Ensure clientStarted = new Ensure(false);
final Ensure clientStopped = new Ensure(false);
- final Ensure serviceStarted = new Ensure(false);
- final Ensure serviceStopped = new Ensure(false);
- final Ensure serviceInvoked = new Ensure(false);
- final Ensure aspectStarted = new Ensure(false);
- final Ensure aspectStopped = new Ensure(false);
- final Ensure aspectUpdated = new Ensure(false);
- final Ensure aspectInvoked = new Ensure(false);
+ final Ensure servicesStopped = new Ensure(false);
+ final Ensure servicesInvoked = new Ensure(false);
+ final Ensure aspectsInvoked = new Ensure(false);
+ final Ensure aspectsRemoved = new Ensure(false);
// Create one client depending on many S services
Client client = new Client(clientStarted, clientStopped);
Component c = dm.createComponent().setImplementation(client);
for (int i = 0; i < SERVICES; i++) {
- c.add(dm.createServiceDependency().setService(S.class, "(name=S" + i + ")").setRequired(true).setCallbacks(
+ String filter = "(name=S" + i + "-" + serviceIdCounter + ")";
+ c.add(dm.createServiceDependency().setService(S.class, filter).setRequired(true).setCallbacks(
"add", null, "remove", "swap"));
}
dm.add(c);
@@ -98,15 +97,15 @@
info("registering S services concurrently");
final ConcurrentLinkedQueue<Component> services = new ConcurrentLinkedQueue<Component>();
for (int i = 0; i < SERVICES; i++) {
- final String name = "S" + i;
+ final String name = "S" + i + "-" + serviceIdCounter;
+ Hashtable h = new Hashtable();
+ h.put("name", name);
+ final Component sImpl = dm.createComponent().setImplementation(
+ new SImpl(servicesStopped, servicesInvoked, name)).setInterface(
+ S.class.getName(), h);
+ services.add(sImpl);
m_execServices.execute(new Runnable() {
public void run() {
- Hashtable h = new Hashtable();
- h.put("name", name);
- Component sImpl = dm.createComponent().setImplementation(
- new SImpl(serviceStarted, serviceStopped, serviceInvoked, name)).setInterface(
- S.class.getName(), h);
- services.add(sImpl);
dm.add(sImpl);
}
});
@@ -115,49 +114,63 @@
// Create S aspects concurrently
info("registering aspects concurrently");
final Queue<Component> aspects = new ConcurrentLinkedQueue<Component>();
- final Queue<Configuration> aspectPids = new ConcurrentLinkedQueue<Configuration>();
for (int i = 0; i < SERVICES; i++) {
- final String name = "Aspect" + i + "-" + (aspectCounter++);
- final String filter = "(name=S" + i + ")";
- final String pid = "Aspect" + i + ".pid" + (aspectPidCounter++);
+ final String name = "Aspect" + i + "-" + serviceIdCounter;
+ final String filter = "(name=S" + i + "-" + serviceIdCounter + ")";
+ final String pid = "Aspect" + i + "-" + serviceIdCounter + ".pid";
final int rank = (i+1);
- m_execServices.execute(new Runnable() {
+ SAspect sa = new SAspect(aspectsInvoked, name, rank);
+ debug("Adding aspect " + sa);
+ final Component aspect = dm.createAspectService(S.class, filter, rank).setImplementation(sa).add(
+ dm.createConfigurationDependency().setPid(pid));
+ aspects.add(aspect);
+ m_execAspects.execute(new Runnable() {
public void run() {
- SAspect sa = new SAspect(aspectStarted, aspectStopped, aspectUpdated, aspectInvoked, name, rank);
- debug("Adding aspect " + sa);
- Component aspect = dm.createAspectService(S.class, filter, rank).setImplementation(sa).add(
- dm.createConfigurationDependency().setPid(pid));
- aspects.add(aspect);
dm.add(aspect);
- try {
- Configuration aspectConf = m_ca.getConfiguration(pid, null);
- aspectConf.update(new Hashtable() {
- {
- put("name", name);
- }
- });
- aspectPids.add(aspectConf);
- }
- catch (IOException e) {
- error("could not create pid %s for aspect %s", e, pid, name);
- return;
- }
}
});
}
+
+ // Provide all aspect configuration (asynchronously)
+ final Queue<Configuration> aspectPids = new ConcurrentLinkedQueue<Configuration>();
+ for (int i = 0; i < SERVICES; i++) {
+ final String name = "Aspect" + i + "-" + serviceIdCounter;
+ final String pid = "Aspect" + i + "-" + serviceIdCounter + ".pid";
+ final int rank = (i+1);
+ SAspect sa = new SAspect(aspectsInvoked, name, rank);
+ debug("Adding aspect configuration pid %s for aspect %s", pid, sa);
+ try {
+ Configuration aspectConf = m_ca.getConfiguration(pid, null);
+ aspectConf.update(new Hashtable() {
+ {
+ put("name", name);
+ }
+ });
+ aspectPids.add(aspectConf);
+ }
+ catch (IOException e) {
+ error("could not create pid %s for aspect %s", e, pid, name);
+ }
+ }
+
+ // Increment service id counter, for next iteration.
+ serviceIdCounter ++;
- // Make sure all services and aspects are created
+ // Make sure client is started
clientStarted.waitForStep(1, STEP_WAIT);
- aspectUpdated.waitForStep(SERVICES, STEP_WAIT);
- aspectStarted.waitForStep(SERVICES, STEP_WAIT);
- info("all aspects and services registered");
+ info("all services have been started");
- // Make sure client invoked services and aspects SERVICES * INVOKES times
- serviceInvoked.waitForStep(SERVICES * INVOKES, STEP_WAIT);
- aspectInvoked.waitForStep(SERVICES * INVOKES, STEP_WAIT);
- info("All aspects and services have been properly invoked");
-
- // Unregister services concurrently
+ // Make sure client invoked services SERVICES * INVOKES times
+ servicesInvoked.waitForStep(SERVICES * INVOKES, STEP_WAIT);
+ info("All services have been properly invoked");
+
+ // Now ensure that some random aspects have been randomly invoked.
+ int aspectCount = Math.min(1, rnd.nextInt(SERVICES));
+ int aspectInvocations = Math.min(1, rnd.nextInt(INVOKES));
+ aspectsInvoked.waitForStep(aspectCount * aspectInvocations, STEP_WAIT);
+ info("%d aspects have been properly invoked %d times", aspectCount, aspectInvocations);
+
+ // Unregister services concurrently (at this point, it is possible that we have still some aspects being activating !
info("unregistering services concurrently");
for (final Component sImpl : services) {
m_execServices.execute(new Runnable() {
@@ -167,39 +180,48 @@
});
}
- // Unregister aspects (and configuration) concurrently
+ // unregister aspects concurrently (some aspects can potentially be still activating !)
info("unregistering aspects concurrently");
for (final Component a : aspects) {
m_execAspects.execute(new Runnable() {
public void run() {
debug("removing aspect %s", a);
dm.remove(a);
+ aspectsRemoved.step();
}
});
}
- info("unregistering aspect configuration concurrently");
+
+ info("unregistering aspects configuration concurrently");
for (Configuration aspectConf : aspectPids) {
- aspectConf.delete();
+ aspectConf.delete(); // asynchronous
}
- info("removing client from dm");
+ info("removing client");
dm.remove(c);
- // Wait until all services/aspects have been stopped
- serviceStopped.waitForStep(SERVICES, STEP_WAIT);
- aspectStopped.waitForStep(SERVICES, STEP_WAIT);
+ // Wait until all services have been stopped
+ servicesStopped.waitForStep(SERVICES, STEP_WAIT);
+
+ // Wait until client has been stopped
clientStopped.waitForStep(1, STEP_WAIT);
-
+
+ // Wait until all aspects have been deleted
+ aspectsRemoved.waitForStep(SERVICES, STEP_WAIT);
+
if (super.errorsLogged()) {
throw new IllegalStateException("Race test interrupted (some error occured, see previous logs)");
}
- info("finished one test loop");
+ info("finished one test loop: current components=%d", dm.getComponents().size());
if ((loop + 1) % 100 == 0) {
long duration = System.currentTimeMillis() - timeStamp;
warn("Performed %d tests (total=%d) in %d ms.", (loop + 1), tests, duration);
timeStamp = System.currentTimeMillis();
}
+
+ // Cleanup all remaining components (but all components should have been removed now).
+ dm.clear();
}
}
@@ -228,12 +250,11 @@
}
public class SImpl implements S {
- final Ensure m_started, m_stopped, m_invoked;
+ final Ensure m_stopped, m_invoked;
final String m_name;
- public SImpl(Ensure started, Ensure stopped, Ensure invoked, String name) {
+ public SImpl(Ensure stopped, Ensure invoked, String name) {
m_name = name;
- m_started = started;
m_stopped = stopped;
m_invoked = invoked;
}
@@ -249,7 +270,6 @@
public void start() {
info("started %s", this);
- m_started.step();
}
public void stop() {
@@ -272,10 +292,6 @@
synchronized void swap(ServiceReference prevRef, S prev, ServiceReference nextRef, S next) {
info("client.swap: prev=%s, next=%s", prev, next);
- if (m_services.remove(prevRef.getProperty("name")) == null) {
- throw new IllegalStateException("client being swapped with an unknown old service: oldRef=" + prevRef.getProperty("name") +
- ", newRef=" + nextRef.getProperty("name") + ", current injected services=" + m_services);
- }
m_services.put((String) nextRef.getProperty("name"), next);
}
@@ -286,9 +302,7 @@
synchronized void remove(Map<String, String> props, S s) {
info("client.remove: %s", s);
- if (m_services.remove(props.get("name")) == null) {
- throw new IllegalStateException("client being removed with an unknown old service: " + props.get("name"));
- }
+ m_services.remove(props.get("name"));
}
public synchronized void start() {
@@ -350,13 +364,10 @@
volatile S m_next;
final String m_name;
final int m_rank;
- final Ensure m_invoked, m_started, m_stopped, m_updated;
+ final Ensure m_invoked;
volatile Dictionary<String, String> m_conf;
- SAspect(Ensure started, Ensure stopped, Ensure updated, Ensure invoked, String name, int rank) {
- m_started = started;
- m_stopped = stopped;
- m_updated = updated;
+ SAspect(Ensure invoked, String name, int rank) {
m_invoked = invoked;
m_name = name;
m_rank = rank;
@@ -369,17 +380,14 @@
}
debug("Aspect %s injected with configuration: %s", this, conf);
m_conf = conf;
- m_updated.step();
}
public void start() {
info("started aspect %s", this);
- m_started.step();
}
public void stop() {
info("stopped aspect %s", this);
- m_stopped.step();
}
public void invoke(int prevRank) {