Improve test reliability by adding a stability check on startup

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1477243 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/runtime/core-it/src/it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java b/ipojo/runtime/core-it/src/it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
index 53693c4..faf0e4e 100644
--- a/ipojo/runtime/core-it/src/it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
+++ b/ipojo/runtime/core-it/src/it/ipojo-core-lifecycle-controller-test/src/test/java/org/apache/felix/ipojo/runtime/core/Common.java
@@ -36,8 +36,10 @@
 import org.ops4j.pax.exam.spi.reactors.PerClass;
 import org.ops4j.pax.tinybundles.core.TinyBundle;
 import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
 import org.ow2.chameleon.testing.helpers.IPOJOHelper;
 import org.ow2.chameleon.testing.helpers.OSGiHelper;
 import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
@@ -64,23 +66,9 @@
 
     @Inject
     BundleContext bc;
-
     OSGiHelper osgiHelper;
     IPOJOHelper ipojoHelper;
 
-    @Configuration
-    public Option[] config() throws IOException {
-        Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
-        root.setLevel(Level.INFO);
-
-        return options(
-                ipojoBundles(),
-                junitBundles(),
-                testedBundle(),
-                systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN")
-        );
-    }
-
     public static Option junitAndMockitoBundles() {
         return new DefaultCompositeOption(
                 // Repository required to load harmcrest (OSGi-fied version).
@@ -118,6 +106,18 @@
         );
     }
 
+    @Configuration
+    public Option[] config() throws IOException {
+        Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+        root.setLevel(Level.INFO);
+
+        return options(
+                ipojoBundles(),
+                junitBundles(),
+                testedBundle(),
+                systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN")
+        );
+    }
 
     @Before
     public void commonSetUp() {
@@ -131,6 +131,8 @@
         }
         String version = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VERSION);
         System.out.println("OSGi Framework : " + vendor + " - " + version);
+
+        waitForStability(bc);
     }
 
     @After
@@ -146,7 +148,7 @@
                 // harmcrest-all
                 //mavenBundle("de.twentyeleven.skysail", "org.hamcrest.hamcrest-all-osgi").versionAsInProject(),
                 // configuration admin
-                mavenBundle("org.apache.felix",  "org.apache.felix.configadmin").versionAsInProject()
+                mavenBundle("org.apache.felix", "org.apache.felix.configadmin").versionAsInProject()
         );
     }
 
@@ -165,12 +167,12 @@
         for (File file : files) {
             if (file.isDirectory()) {
                 // By convention we export of .services and .service package
-                if (file.getName().endsWith("services")  || file.getName().endsWith("service")) {
+                if (file.getName().endsWith("services") || file.getName().endsWith("service")) {
                     services.add(file);
                 }
             } else {
                 // We need to compute the path
-                String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() +1);
+                String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() + 1);
                 tested.add(path, file.toURI().toURL());
                 System.out.println(file.getName() + " added to " + path);
             }
@@ -178,8 +180,10 @@
 
         String export = "";
         for (File file : services) {
-            if (export.length() > 0) { export += ", "; }
-            String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() +1);
+            if (export.length() > 0) {
+                export += ", ";
+            }
+            String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() + 1);
             String packageName = path.replace('/', '.');
             export += packageName;
         }
@@ -211,5 +215,77 @@
         fail("Assertion failed : " + s);
     }
 
+    /**
+     * Waits for stability:
+     * <ul>
+     * <li>all bundles are activated
+     * <li>service count is stable
+     * </ul>
+     * If the stability can't be reached after a specified time,
+     * the method throws a {@link IllegalStateException}.
+     *
+     * @param context the bundle context
+     * @throws IllegalStateException when the stability can't be reach after a several attempts.
+     */
+    private void waitForStability(BundleContext context) throws IllegalStateException {
+        // Wait for bundle initialization.
+        boolean bundleStability = getBundleStability(context);
+        int count = 0;
+        while (!bundleStability && count < 500) {
+            try {
+                Thread.sleep(5);
+            } catch (InterruptedException e) {
+                // Interrupted
+            }
+            count++;
+            bundleStability = getBundleStability(context);
+        }
+
+        if (count == 500) {
+            System.err.println("Bundle stability isn't reached after 500 tries");
+            throw new IllegalStateException("Cannot reach the bundle stability");
+        }
+
+        boolean serviceStability = false;
+        count = 0;
+        int count1 = 0;
+        int count2 = 0;
+        while (!serviceStability && count < 500) {
+            try {
+                ServiceReference[] refs = context.getServiceReferences((String) null, null);
+                count1 = refs.length;
+                Thread.sleep(500);
+                refs = context.getServiceReferences((String) null, null);
+                count2 = refs.length;
+                serviceStability = count1 == count2;
+            } catch (Exception e) {
+                System.err.println(e);
+                serviceStability = false;
+                // Nothing to do, while recheck the condition
+            }
+            count++;
+        }
+
+        if (count == 500) {
+            System.err.println("Service stability isn't reached after 500 tries (" + count1 + " != " + count2);
+            throw new IllegalStateException("Cannot reach the service stability");
+        }
+    }
+
+    /**
+     * Are bundle stables.
+     *
+     * @param bc the bundle context
+     * @return <code>true</code> if every bundles are activated.
+     */
+    private boolean getBundleStability(BundleContext bc) {
+        boolean stability = true;
+        Bundle[] bundles = bc.getBundles();
+        for (Bundle bundle : bundles) {
+            stability = stability && (bundle.getState() == Bundle.ACTIVE);
+        }
+        return stability;
+    }
+
 
 }