Cleaned test. Replaced CopyOnWriteArrayList by ConcurrentLinkedQueue. Ensure that aspects are called in the proper order.
Added more checks. This test is now fully operational with my current dm version, which I will commit soon in the sandbox.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1564110 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 3306e57..baec7ae 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
@@ -19,14 +19,12 @@
package org.apache.felix.dm.test.integration.api;
import java.io.IOException;
-import java.util.Collections;
import java.util.Dictionary;
-import java.util.HashMap;
import java.util.Hashtable;
-import java.util.List;
import java.util.Map;
+import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@@ -37,7 +35,6 @@
import org.apache.felix.dm.Component;
import org.apache.felix.dm.DependencyManager;
-import org.apache.felix.dm.ServiceUtil;
import org.apache.felix.dm.test.components.Ensure;
import org.apache.felix.dm.test.integration.common.TestBase;
import org.junit.Test;
@@ -73,9 +70,9 @@
m_execAspects = Executors.newFixedThreadPool(cores);
int aspectPidCounter = 1;
int aspectCounter = 1;
-
long timeStamp = System.currentTimeMillis();
- for (int loop = 0; loop < 30000; loop++) {
+ final int tests = 100000;
+ for (int loop = 0; loop < tests; loop++) {
debug("loop#%d -------------------------", (loop + 1));
final Ensure clientStarted = new Ensure(false);
@@ -99,7 +96,7 @@
// Create S services concurrently
info("registering S services concurrently");
- final List<Component> services = new CopyOnWriteArrayList<Component>();
+ final ConcurrentLinkedQueue<Component> services = new ConcurrentLinkedQueue<Component>();
for (int i = 0; i < SERVICES; i++) {
final String name = "S" + i;
m_execServices.execute(new Runnable() {
@@ -117,17 +114,18 @@
// Create S aspects concurrently
info("registering aspects concurrently");
- final List<Component> aspects = new CopyOnWriteArrayList<Component>();
- final List<Configuration> aspectPids = new CopyOnWriteArrayList<Configuration>();
+ 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 int rank = (i+1);
m_execServices.execute(new Runnable() {
public void run() {
- SAspect sa = new SAspect(aspectStarted, aspectStopped, aspectUpdated, aspectInvoked, name);
+ SAspect sa = new SAspect(aspectStarted, aspectStopped, aspectUpdated, aspectInvoked, name, rank);
debug("Adding aspect " + sa);
- Component aspect = dm.createAspectService(S.class, filter, 1).setImplementation(sa).add(
+ Component aspect = dm.createAspectService(S.class, filter, rank).setImplementation(sa).add(
dm.createConfigurationDependency().setPid(pid));
aspects.add(aspect);
dm.add(aspect);
@@ -199,7 +197,7 @@
info("finished one test loop");
if ((loop + 1) % 100 == 0) {
long duration = System.currentTimeMillis() - timeStamp;
- warn("Performed %d tests in %d ms.", (loop + 1), duration);
+ warn("Performed %d tests (total=%d) in %d ms.", (loop + 1), tests, duration);
timeStamp = System.currentTimeMillis();
}
}
@@ -226,7 +224,7 @@
}
public interface S {
- void invoke();
+ void invoke(int prevAspectId);
}
public class SImpl implements S {
@@ -240,7 +238,8 @@
m_invoked = invoked;
}
- public void invoke() {
+ public void invoke(int prevRank) {
+ Assert.assertTrue(prevRank > 0);
m_invoked.step();
}
@@ -273,6 +272,10 @@
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);
}
@@ -283,7 +286,9 @@
synchronized void remove(Map<String, String> props, S s) {
info("client.remove: %s", s);
- m_services.remove(props.get("name"));
+ if (m_services.remove(props.get("name")) == null) {
+ throw new IllegalStateException("client being removed with an unknown old service: " + props.get("name"));
+ }
}
public synchronized void start() {
@@ -314,7 +319,7 @@
while (m_running) {
for (int i = 0; i < INVOKES; i++) {
for (Map.Entry<String, S> e : m_services.entrySet()) {
- e.getValue().invoke();
+ e.getValue().invoke(Integer.MAX_VALUE); // We are on the top of the aspect list
}
}
}
@@ -323,6 +328,7 @@
public synchronized void stop() {
if (!m_running) {
error("client can't be stopped (not running)");
+ Thread.dumpStack();
return;
}
@@ -343,15 +349,17 @@
public class SAspect implements S {
volatile S m_next;
final String m_name;
+ final int m_rank;
final Ensure m_invoked, m_started, m_stopped, m_updated;
volatile Dictionary<String, String> m_conf;
- SAspect(Ensure started, Ensure stopped, Ensure updated, Ensure invoked, String name) {
+ SAspect(Ensure started, Ensure stopped, Ensure updated, Ensure invoked, String name, int rank) {
m_started = started;
m_stopped = stopped;
m_updated = updated;
m_invoked = invoked;
m_name = name;
+ m_rank = rank;
}
public void updated(Dictionary<String, String> conf) {
@@ -374,7 +382,8 @@
m_stopped.step();
}
- public void invoke() {
+ public void invoke(int prevRank) {
+ Assert.assertTrue(prevRank > m_rank);
if (m_conf == null) {
error("Aspect: %s has not been injected with its configuration", this);
return;
@@ -385,7 +394,7 @@
return;
}
m_invoked.step();
- m_next.invoke();
+ m_next.invoke(m_rank);
}
public String toString() {