SLING-1794 - improve synchronization and split between deferred install and remove...
authorBertrand Delacretaz <bdelacretaz@apache.org>
Tue, 3 Dec 2013 15:51:18 +0000 (15:51 +0000)
committerBertrand Delacretaz <bdelacretaz@apache.org>
Tue, 3 Dec 2013 15:51:18 +0000 (15:51 +0000)
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1547444 13f79535-47bb-0310-9956-ffa450edef68

src/test/java/org/apache/sling/installer/it/ConfigInstallTest.java
src/test/java/org/apache/sling/installer/it/OsgiInstallerTestBase.java

index 28d982d..d886df5 100644 (file)
@@ -20,12 +20,16 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
+import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.event.InstallationEvent;
+import org.apache.sling.installer.api.event.InstallationListener;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -45,7 +49,9 @@ public class ConfigInstallTest extends OsgiInstallerTestBase implements Configur
 
     private final static long TIMEOUT = 5000L;
     private List<ConfigurationEvent> events = new LinkedList<ConfigurationEvent>();
-    private ServiceRegistration serviceRegistration;
+    private List<ServiceRegistration<?>> serviceRegistrations = new ArrayList<ServiceRegistration<?>>();
+    private int installationEvents = 0;
+    private static final AtomicInteger counter = new AtomicInteger();
 
     @org.ops4j.pax.exam.Configuration
     public Option[] config() {
@@ -54,21 +60,34 @@ public class ConfigInstallTest extends OsgiInstallerTestBase implements Configur
     
     @Before
     public void setUp() {
+        installationEvents = 0;
         setupInstaller();
         events.clear();
-        serviceRegistration = bundleContext.registerService(ConfigurationListener.class.getName(), this, null);
+        serviceRegistrations.clear();
+        serviceRegistrations.add(bundleContext.registerService(ConfigurationListener.class.getName(), this, null));
+        
+        final InstallationListener il = new InstallationListener() {
+            public void onEvent(InstallationEvent event) {
+                installationEvents++;
+            }
+        };
+        serviceRegistrations.add(bundleContext.registerService(InstallationListener.class.getName(), il, null));
     }
 
     @Override
     @After
     public void tearDown() {
         super.tearDown();
-        if(serviceRegistration != null) {
-               serviceRegistration.unregister();
-               serviceRegistration = null;
+        for(ServiceRegistration<?> reg : serviceRegistrations) {
+               reg.unregister();
         }
+        serviceRegistrations.clear();
     }
-
+    
+    private String uniqueID() {
+        return counter.incrementAndGet() + "_" + System.currentTimeMillis();
+    }
+    
     /**
      * @see org.osgi.service.cm.ConfigurationListener#configurationEvent(org.osgi.service.cm.ConfigurationEvent)
      */
@@ -82,7 +101,7 @@ public class ConfigInstallTest extends OsgiInstallerTestBase implements Configur
     public void testInstallAndRemoveConfig() throws Exception {
         final Dictionary<String, Object> cfgData = new Hashtable<String, Object>();
         cfgData.put("foo", "bar");
-        final String cfgPid = getClass().getSimpleName() + "." + System.currentTimeMillis();
+        final String cfgPid = getClass().getSimpleName() + "." + uniqueID();
         assertNull("Config " + cfgPid + " must not be found before test", findConfiguration(cfgPid));
 
         // install config
@@ -115,7 +134,7 @@ public class ConfigInstallTest extends OsgiInstallerTestBase implements Configur
        waitForConfigAdmin(true);
 
        // check that configuration is not available
-        final String cfgPid = getClass().getSimpleName() + ".deferred." + System.currentTimeMillis();
+        final String cfgPid = getClass().getSimpleName() + ".deferred." + uniqueID();
         assertNull("Config " + cfgPid + " must not be found before test", findConfiguration(cfgPid));
        // create new configuration object
        final Dictionary<String, Object> cfgData = new Hashtable<String, Object>();
@@ -124,23 +143,52 @@ public class ConfigInstallTest extends OsgiInstallerTestBase implements Configur
        // Configuration installs must be deferred if ConfigAdmin service is stopped
         configAdmin.stop();
        waitForConfigAdmin(false);
+       
        // add new configuration
         final InstallableResource[] rsrc = getInstallableResource(cfgPid, cfgData);
+        installationEvents = 0;
         installer.updateResources(URL_SCHEME, rsrc, null);
-        // let's wait a little bit and restart configuration admin
-        sleep(1000L);
+        waitForInstallationEvents(2);
         configAdmin.start();
        waitForConfigAdmin(true);
         waitForConfiguration("Config must be installed once ConfigurationAdmin restarts",
                 cfgPid, TIMEOUT, true);
 
+        // Remove config and check
+        installer.updateResources(URL_SCHEME, null, new String[] {rsrc[0].getId()});
+        waitForConfiguration("Config must be removed once ConfigurationAdmin restarts",
+                cfgPid, TIMEOUT, false);
+    }
+
+    @Test
+    public void testDeferredConfigRemove() throws Exception {
+        // get config admin bundle and wait for service
+        final Bundle configAdmin = this.getConfigAdminBundle();
+        assertNotNull("ConfigAdmin bundle must be found", configAdmin);
+        waitForConfigAdmin(true);
+
+        // check that configuration is not available
+        final String cfgPid = getClass().getSimpleName() + ".deferred." + uniqueID();
+        assertNull("Config " + cfgPid + " must not be found before test", findConfiguration(cfgPid));
+        
+        // create and install new configuration object, verify
+        final Dictionary<String, Object> cfgData = new Hashtable<String, Object>();
+        cfgData.put("foo", "bar");
+        final InstallableResource[] rsrc = getInstallableResource(cfgPid, cfgData);
+        installationEvents = 0;
+        installer.updateResources(URL_SCHEME, rsrc, null);
+        waitForInstallationEvents(2);
+        waitForConfiguration("Config must be installed before stopping ConfigurationAdmin",
+                cfgPid, TIMEOUT, true);
+
         // Configuration uninstalls must be deferred if ConfigAdmin service is stopped
         configAdmin.stop();
         waitForConfigAdmin(false);
+        
         // remove configuration
+        installationEvents = 0;
         installer.updateResources(URL_SCHEME, null, new String[] {rsrc[0].getId()});
-        // let's wait a little bit and restart configuration admin
-        sleep(1000L);
+        waitForInstallationEvents(2);
         configAdmin.start();
         waitForConfigAdmin(true);
         waitForConfiguration("Config must be removed once ConfigurationAdmin restarts",
@@ -151,7 +199,7 @@ public class ConfigInstallTest extends OsgiInstallerTestBase implements Configur
     public void testReinstallSameConfig() throws Exception {
        final Dictionary<String, Object> cfgData = new Hashtable<String, Object>();
        cfgData.put("foo", "bar");
-       final String cfgPid = getClass().getSimpleName() + ".reinstall." + System.currentTimeMillis();
+       final String cfgPid = getClass().getSimpleName() + ".reinstall." + uniqueID();
        assertNull("Config " + cfgPid + " must not be found before test", findConfiguration(cfgPid));
 
        // Install config directly
@@ -217,4 +265,14 @@ public class ConfigInstallTest extends OsgiInstallerTestBase implements Configur
             return sb.toString();
         }
     }
+    
+    private void waitForInstallationEvents(final int howMany) throws Exception {
+        final Condition c = new Condition() {
+            @Override
+            boolean isTrue() throws Exception {
+                return installationEvents >= howMany;
+            }
+        };
+        waitForCondition("Wait for " + howMany + " installation events", TIMEOUT, c);
+    }
 }
index 8dad5e4..30bfe95 100644 (file)
@@ -40,6 +40,7 @@ import javax.inject.Inject;
 
 import org.apache.sling.installer.api.InstallableResource;
 import org.apache.sling.installer.api.OsgiInstaller;
+import org.junit.Before;
 import org.ops4j.pax.exam.Option;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -60,9 +61,9 @@ import org.osgi.service.packageadmin.PackageAdmin;
 import org.osgi.util.tracker.ServiceTracker;
 
 /** Base class for OsgiInstaller testing */
-class OsgiInstallerTestBase implements FrameworkListener {
-       private final static String POM_VERSION = System.getProperty("osgi.installer.pom.version");
-    private final static String CONFIG_VERSION = System.getProperty("installer.configuration.version");
+public class OsgiInstallerTestBase implements FrameworkListener {
+       private final static String POM_VERSION = System.getProperty("osgi.installer.pom.version", "POM_VERSION_NOT_SET");
+    private final static String CONFIG_VERSION = System.getProperty("installer.configuration.version", "INSTALLER_VERSION_NOT_SET");
 
        public final static String JAR_EXT = ".jar";
        private int packageRefreshEventsCount;
@@ -102,6 +103,12 @@ class OsgiInstallerTestBase implements FrameworkListener {
         installer = getService(OsgiInstaller.class);
     }
 
+    @Before
+    public void setup() {
+        configAdminTracker = new ServiceTracker(bundleContext, ConfigurationAdmin.class.getName(), null);
+        configAdminTracker.open();
+    }
+
     /** Tear down everything. */
     public void tearDown() {
         synchronized (this) {
@@ -203,7 +210,7 @@ class OsgiInstallerTestBase implements FrameworkListener {
                if(c.isTrue()) {
                        return;
                }
-               Thread.sleep(c.getMsecBetweenEvaluations());
+               sleep(c.getMsecBetweenEvaluations());
         } while(System.currentTimeMillis() < end);
 
         if(c.additionalInfo() != null) {
@@ -221,7 +228,7 @@ class OsgiInstallerTestBase implements FrameworkListener {
                if(value.equals(c.getProperties().get(key))) {
                        return;
                }
-               Thread.sleep(100L);
+               sleep(100L);
         } while(System.currentTimeMillis() < end);
         fail("Did not get " + key + "=" + value + " for config " + pid);
     }
@@ -329,12 +336,6 @@ class OsgiInstallerTestBase implements FrameworkListener {
 
     protected ConfigurationAdmin waitForConfigAdmin(final boolean shouldBePresent) {
        ConfigurationAdmin result = null;
-        synchronized (this) {
-            if (configAdminTracker == null) {
-                configAdminTracker = new ServiceTracker(bundleContext, ConfigurationAdmin.class.getName(), null);
-                configAdminTracker.open();
-            }
-        }
 
         final int timeout = 5;
        final long waitUntil = System.currentTimeMillis() + (timeout * 1000L);
@@ -385,7 +386,7 @@ class OsgiInstallerTestBase implements FrameworkListener {
        }
 
        // optional debugging
-       final String paxDebugLevel = System.getProperty("pax.exam.log.level");
+       final String paxDebugLevel = System.getProperty("pax.exam.log.level", "INFO");
        final String paxDebugPort = System.getProperty("pax.exam.debug.port");
        if(paxDebugPort != null && paxDebugPort.length() > 0) {
                vmOpt += " -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=" + paxDebugPort;
@@ -534,9 +535,7 @@ class OsgiInstallerTestBase implements FrameworkListener {
                         }
                     }
                 }
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException ignore) {}
+                sleep(100);
             }
             logInstalledBundles();
             final StringBuilder sb = new StringBuilder();