You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2009/08/25 19:02:11 UTC

svn commit: r807717 - in /sling/trunk/installer/jcr/jcrinstall/src: main/java/org/apache/sling/jcr/jcrinstall/impl/ test/java/org/apache/sling/jcr/jcrinstall/impl/ test/java/org/apache/sling/jcr/jcrinstall/jcr/

Author: bdelacretaz
Date: Tue Aug 25 17:02:11 2009
New Revision: 807717

URL: http://svn.apache.org/viewvc?rev=807717&view=rev
Log:
SLING-1078 - RegisteredResourceTest re-implemented (and much simpler ;-)

Added:
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ResourceDetectionTest.java
      - copied, changed from r807661, sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.java
Removed:
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/
Modified:
    sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java
    sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java
    sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java

Modified: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java?rev=807717&r1=807716&r2=807717&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/JcrInstaller.java Tue Aug 25 17:02:11 2009
@@ -180,9 +180,9 @@
     	// Scan watchedFolders and register resources with installer
     	final List<InstallableResource> resources = new LinkedList<InstallableResource>();
     	for(WatchedFolder f : watchedFolders) {
-    		final Collection<InstallableResource> c = f.scan();
-    		log.debug("Startup: {} provides resources {}", f, c);
-    		resources.addAll(c);
+    		final WatchedFolder.ScanResult r = f.scan();
+    		log.debug("Startup: {} provides resources {}", f, r.toAdd);
+    		resources.addAll(r.toAdd);
     	}
     	
     	log.info("Registering {} resources with OSGi installer", resources.size());
@@ -315,6 +315,21 @@
             try {
                 // TODO rendezvous with installer if any folder has been deleted
                 addAndDeleteFolders();
+
+                // Rescan WatchedFolders if needed
+                if(System.currentTimeMillis() > WatchedFolder.getNextScanTime()) {
+                    for(WatchedFolder wf : watchedFolders) {
+                        final WatchedFolder.ScanResult sr = wf.scan();
+                        for(InstallableResource r : sr.toRemove) {
+                            log.info("Removing resource from OSGi installer: {}",r);
+                            installer.removeResource(r);
+                        }
+                        for(InstallableResource r : sr.toAdd) {
+                            log.info("Adding resource to OSGi installer: {}",r);
+                            installer.addResource(r);
+                        }
+                    }
+                }
                 cyclesCount++;
 
                 // TODO wait for events from our listeners, and/or WatchedFolder scan time

Modified: sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java?rev=807717&r1=807716&r2=807717&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/main/java/org/apache/sling/jcr/jcrinstall/impl/WatchedFolder.java Tue Aug 25 17:02:11 2009
@@ -18,9 +18,12 @@
  */
 package org.apache.sling.jcr.jcrinstall.impl;
 
+import java.io.ByteArrayInputStream;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.jcr.Item;
 import javax.jcr.Node;
@@ -48,6 +51,14 @@
     private final Collection <JcrInstaller.NodeConverter> converters;
     protected final Logger log = LoggerFactory.getLogger(getClass());
     
+    static class ScanResult {
+        List<InstallableResource> toAdd = new ArrayList<InstallableResource>(); 
+        List<InstallableResource> toRemove = new ArrayList<InstallableResource>();
+    };
+    
+    /** Store the digests of the last returned resources, keyed by path, to detect changes */
+    private final Map<String, String> digests = new HashMap<String, String>();
+    
     // WatchedFolders that need a rescan will be scanned
     // once no JCR events have been received for this amount of time.
     public static final long SCAN_DELAY_MSEC = 500L;
@@ -101,12 +112,12 @@
     	return needsScan;
     }
     
-    long getNextScanTime() {
+    static long getNextScanTime() {
     	return nextScanTime;
     }
     
     /** Scan the contents of our folder and return the corresponding InstallableResource */
-    List<InstallableResource> scan() throws Exception {
+    ScanResult scan() throws Exception {
         log.debug("Scanning {}", path);
         
         Node folder = null;
@@ -123,20 +134,40 @@
         }
         
         // Return an InstallableResource for all child nodes for which we have a NodeConverter
-        final List<InstallableResource> result = new ArrayList<InstallableResource>();
+        final ScanResult result = new ScanResult();
         final NodeIterator it = folder.getNodes();
         while(it.hasNext()) {
         	final Node n = it.nextNode();
         	for(JcrInstaller.NodeConverter nc : converters) {
         		final InstallableResource r = nc.convertNode(urlScheme, n);
         		if(r != null) {
-        			r.setPriority(priority);
-        			result.add(r);
+        		    final String oldDigest = digests.get(r.getUrl());
+        		    if(r.getDigest().equals(oldDigest)) {
+        		        // Already returned that resource, ignore
+        		        digests.remove(r.getUrl());
+        		    } else {
+                        r.setPriority(priority);
+                        result.toAdd.add(r);
+        		    }
         			break;
         		}
         	}
         }
         
+        // Resources left in the digests map have been deleted since last scan, 
+        // need to be removed from OsgiInstaller
+        final ByteArrayInputStream emptyStream = new ByteArrayInputStream("".getBytes());
+        for(Map.Entry<String, String> e : digests.entrySet()) {
+            InstallableResource r = new InstallableResource(e.getKey(), emptyStream, e.getValue());
+            result.toRemove.add(r);
+        }
+        
+        // Store digests of the resources that we're adding, for next time
+        digests.clear();
+        for(InstallableResource r : result.toAdd) {
+            digests.put(r.getUrl(), r.getDigest());
+        }
+        
         return result;
     }
 }

Modified: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java?rev=807717&r1=807716&r2=807717&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ContentHelper.java Tue Aug 25 17:02:11 2009
@@ -18,13 +18,19 @@
  */
 package org.apache.sling.jcr.jcrinstall.impl;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.Calendar;
+import java.util.Map;
 
+import javax.jcr.NamespaceRegistry;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
+import org.apache.sling.commons.testing.jcr.RepositoryUtil;
+
 /** Utility class used to create test content */
 class ContentHelper {
     public static final String NT_FOLDER = "nt:folder";
@@ -47,10 +53,34 @@
         "/apps/noninstall"
     };
     
+    final String [] FAKE_RESOURCES = {
+        "/libs/foo/bar/install/bundle1.jar",
+        "/libs/foo/bar/install/cfg3.cfg",
+        "/libs/foo/wii/install/bundle2.jar",
+        "/libs/foo/wii/install/cfg1.properties",
+        "/libs/foo/wii/install/cfg2.properties",
+    };
+    
+    final String [] FAKE_CONFIGS = {
+        "/libs/foo/bar/install/cfgA",
+        "/libs/foo/wii/install/cfgB",
+        "/libs/foo/wii/install/cfgC"
+    };
+    
     private final Session session;
     
-    ContentHelper(Session s) {
+    ContentHelper(Session s) throws RepositoryException, IOException {
     	session = s;
+    	
+        final NamespaceRegistry r = session.getWorkspace().getNamespaceRegistry();
+        try {
+            r.registerNamespace("sling", "http://sling.apache.org/jcr/sling/1.0");
+        } catch(RepositoryException ignore) {
+            // don't fail if already registered
+        }
+        
+        RepositoryUtil.registerNodeType(session,
+                this.getClass().getResourceAsStream("/SLING-INF/nodetypes/osgiconfig.cnd"));
     }
 
     void cleanupContent() throws Exception {
@@ -70,6 +100,12 @@
         for(String folder : IGNORED_FOLDERS) {
             createFolder(folder);
         }
+        for(String path : FAKE_RESOURCES) {
+            createOrUpdateFile(path);
+        }
+        for(String path : FAKE_CONFIGS) {
+            createConfig(path, null);
+        }
     }
     
     void createFolder(String path) throws Exception {
@@ -90,6 +126,12 @@
         session.save();
     }
     
+    void createOrUpdateFile(String path) throws RepositoryException {
+        final String data = "Fake data for " + path;
+        final ByteArrayInputStream is = new ByteArrayInputStream(data.getBytes());
+        createOrUpdateFile(path, is, System.currentTimeMillis());
+    }
+    
     void createOrUpdateFile(String path, MockInstallableResource d) throws RepositoryException {
     	createOrUpdateFile(path, d.getInputStream(), System.currentTimeMillis());
     }
@@ -121,4 +163,15 @@
         }
         return path;
     }
+    
+    void createConfig(String path, Map<String, String> data) throws RepositoryException {
+        path = relPath(path);
+        Node cfg = null;
+        if(session.getRootNode().hasNode(path)) {
+            cfg = session.getRootNode().getNode(path);
+        } else {
+            cfg = session.getRootNode().addNode(path, "sling:OsgiConfig");
+        }
+        cfg.getParent().save();
+   }
 }
\ No newline at end of file

Modified: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java?rev=807717&r1=807716&r2=807717&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/MockOsgiInstaller.java Tue Aug 25 17:02:11 2009
@@ -20,23 +20,59 @@
 
 import java.io.IOException;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
 
 import org.apache.sling.osgi.installer.InstallableResource;
 import org.apache.sling.osgi.installer.OsgiInstaller;
 
 class MockOsgiInstaller implements OsgiInstaller {
 
+    private final long [] counters = new long[OsgiInstaller.COUNTERS_SIZE];
+    
+    static class InstallableResourceComparator implements Comparator<InstallableResource> {
+        public int compare(InstallableResource a, InstallableResource b) {
+            return a.getUrl().compareTo(b.getUrl());
+        }
+        
+    }
+    
+    /** Keep track of our method calls, for verification */
+    private final List<String> recordedCalls = new LinkedList<String>();
+    
     public void addResource(InstallableResource d) throws IOException {
+        recordCall("add", d);
     }
 
     public long[] getCounters() {
-        return null;
+        return counters;
     }
 
-    public void registerResources(Collection<InstallableResource> data,
-            String urlScheme) throws IOException {
+    public void registerResources(Collection<InstallableResource> data, String urlScheme) throws IOException {
+        // Sort the data to allow comparing the recorded calls reliably
+        final List<InstallableResource> sorted = new LinkedList<InstallableResource>();
+        sorted.addAll(data);
+        Collections.sort(sorted, new InstallableResourceComparator());
+        for(InstallableResource r : data) {
+            recordCall("register", r);
+        }
     }
 
     public void removeResource(InstallableResource d) throws IOException {
+        recordCall("remove", d);
+    }
+    
+    private synchronized void recordCall(String prefix, InstallableResource r) {
+        recordedCalls.add(prefix + ":" + r.getUrl() + ":" + r.getPriority());
+    }
+    
+    synchronized void clearRecordedCalls() {
+        recordedCalls.clear();
+    }
+    
+    List<String> getRecordedCalls() {
+        return recordedCalls;
     }
 }

Copied: sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ResourceDetectionTest.java (from r807661, sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.java)
URL: http://svn.apache.org/viewvc/sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ResourceDetectionTest.java?p2=sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ResourceDetectionTest.java&p1=sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.java&r1=807661&r2=807717&rev=807717&view=diff
==============================================================================
--- sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/jcr/impl/ResourceDetectionTest.java (original)
+++ sling/trunk/installer/jcr/jcrinstall/src/test/java/org/apache/sling/jcr/jcrinstall/impl/ResourceDetectionTest.java Tue Aug 25 17:02:11 2009
@@ -16,32 +16,28 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.jcrinstall.jcr.impl;
+package org.apache.sling.jcr.jcrinstall.impl;
+
+import java.util.List;
+
+import javax.jcr.Session;
 
 import org.apache.sling.commons.testing.jcr.RepositoryTestBase;
+import org.apache.sling.jcr.api.SlingRepository;
 
 /** Test that added/updated/removed resources are
- * 	correctly translated to OsgiController calls.
+ * 	correctly translated to OsgiInstaller registration
+ *  calls.
+ *  TODO: test deleting resources while JcrInstaller is stopped
  */
-/** TODO adapt or remove */
 public class ResourceDetectionTest extends RepositoryTestBase {
-	public void testNothing() {}
-	/*
+    public static final long TIMEOUT = 5000L;
     SlingRepository repo;
     Session session;
     private EventHelper eventHelper; 
     private ContentHelper contentHelper;
-    private Mockery mockery;
-    private Sequence sequence;
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        contentHelper.cleanupContent();
-        session.logout();
-        eventHelper = null;
-        contentHelper = null;
-    }
+    private JcrInstaller installer;
+    private MockOsgiInstaller osgiInstaller;
 
     @Override
     protected void setUp() throws Exception {
@@ -51,331 +47,79 @@
         eventHelper = new EventHelper(session);
         contentHelper = new ContentHelper(session);
         contentHelper.cleanupContent();
-        
-        // Need the sling namespace for testing
-        final NamespaceRegistry r = session.getWorkspace().getNamespaceRegistry();
-        try {
-        	r.registerNamespace("sling", "http://sling.apache.org/jcr/sling/1.0");
-        } catch(RepositoryException ignore) {
-        	// don't fail if already registered
-        }
-        
-        mockery = new Mockery();
-        sequence = mockery.sequence(getClass().getSimpleName());
+        contentHelper.setupContent();
+        osgiInstaller = new MockOsgiInstaller();
+        installer = MiscUtil.getJcrInstaller(repo, osgiInstaller);
     }
     
-    protected String getOsgiResourceLocation(String uri) {
-        return "jcrinstall://" + uri;
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        contentHelper.cleanupContent();
+        session.logout();
+        eventHelper = null;
+        contentHelper = null;
     }
-    
-    public void testSingleResourceDetection() throws Exception {
-        contentHelper.setupContent();
-        
-        final String dummyJar = "/libs/foo/bar/install/dummy.jar";
-        final MockInstallableData da = new MockInstallableData("a");
-        final MockInstallableData db = new MockInstallableData("b");
-        final Set<String> installedUri = new HashSet<String>();
-        final OsgiController c = mockery.mock(OsgiController.class);
-        
-        // Define the whole sequence of calls to OsgiController,
-        // Using getLastModified calls to mark the test phases
-        mockery.checking(new Expectations() {{
-        	allowing(c).executeScheduledOperations();
-            allowing(c).setResourceOverrideRules(with(any(ResourceOverrideRules.class)));
-            allowing(c).getInstalledUris(); will(returnValue(installedUri));
-            
-            one(c).getDigest("phase1"); 
-            inSequence(sequence);
-            one(c).getDigest(dummyJar); will(returnValue(null));
-            inSequence(sequence);
-            one(c).scheduleInstallOrUpdate(with(equal(dummyJar)), with(any(InstallableData.class)));
-            inSequence(sequence);
-            
-            one(c).getDigest("phase2"); 
-            inSequence(sequence);
-            one(c).getDigest(dummyJar); will(returnValue(da.getDigest()));
-            inSequence(sequence);
+
+    private void assertRegisteredPaths(String [] paths) {
+        final List<String> recorded = osgiInstaller.getRecordedCalls();
+        for(String path : paths) {
+            boolean found = false;
+            for(String rec : recorded) {
+                if(rec.contains(path)) {
+                    found = true;
+                    break;
+                }
+            }
             
-            one(c).getDigest("phase3"); 
-            inSequence(sequence);
-            one(c).getDigest(dummyJar); will(returnValue(da.getDigest()));
-            inSequence(sequence);
-            one(c).scheduleInstallOrUpdate(with(equal(dummyJar)), with(any(InstallableData.class)));
-            inSequence(sequence);
-        }});
-        
-        final RepositoryObserver ro = new MockRepositoryObserver(repo, c);
-        ro.activate(null);
-        
-        // Add two files, run one cycle must install the bundles
-        c.getDigest("phase1");
-        contentHelper.createOrUpdateFile(dummyJar, da);
-        eventHelper.waitForEvents(5000L);
-        ro.runOneCycle();
-        installedUri.add(dummyJar);
-        
-        // Updating with the same timestamp must not call install again
-        c.getDigest("phase2");
-        contentHelper.createOrUpdateFile(dummyJar, da);
-        eventHelper.waitForEvents(5000L);
-        ro.runOneCycle();
-        
-        // Updating with a new timestamp must call install again
-        c.getDigest("phase3");
-        contentHelper.createOrUpdateFile(dummyJar, db);
-        eventHelper.waitForEvents(5000L);
-        ro.runOneCycle();
-        
-        mockery.assertIsSatisfied();
-    }
-    
-    public void testMultipleResourceDetection() throws Exception {
-        contentHelper.setupContent();
-        
-        final String [] resources = {
-                "/libs/foo/bar/install/dummy.jar",
-                "/libs/foo/bar/install/dummy.cfg",
-                "/libs/foo/bar/install/dummy.dp"
-        };
-        final MockInstallableData da = new MockInstallableData("a");
-        final Set<String> installedUri = new HashSet<String>();
-        final OsgiController c = mockery.mock(OsgiController.class);
-        
-        // Define the whole sequence of calls to OsgiController,
-        mockery.checking(new Expectations() {{
-        	allowing(c).executeScheduledOperations();
-            allowing(c).setResourceOverrideRules(with(any(ResourceOverrideRules.class)));
-            allowing(c).getInstalledUris(); will(returnValue(installedUri));
-            allowing(c).getDigest(with(any(String.class))); will(returnValue(null)); 
-            one(c).scheduleInstallOrUpdate(with(equal(resources[0])), with(any(InstallableData.class)));
-            one(c).scheduleInstallOrUpdate(with(equal(resources[1])), with(any(InstallableData.class)));
-            one(c).scheduleInstallOrUpdate(with(equal(resources[2])), with(any(InstallableData.class)));
-        }});
-        
-        final RepositoryObserver ro = new MockRepositoryObserver(repo, c);
-        ro.activate(null);
-        
-        // Add files, run one cycle must install the bundles
-        for(String file : resources) {
-            contentHelper.createOrUpdateFile(file, da);
+            boolean expectFound = !path.contains("NOT");
+            assertEquals( 
+                    (expectFound ? "Expected " : "Did not expect ") 
+                    + path + " to be registered (" + recorded + ")",
+                    expectFound, found);
         }
-        eventHelper.waitForEvents(5000L);
-        ro.runOneCycle();
-        
-        mockery.assertIsSatisfied();
     }
     
-    public void testIgnoredFilenames() throws Exception {
-        contentHelper.setupContent();
-        
-        final String [] resources = {
-                "/libs/foo/bar/install/dummy.jar",
-                "/libs/foo/bar/install/dummy.cfg",
-                "/libs/foo/bar/install/dummy.dp"
-        };
-        
-        final String [] ignored  = {
-                "/libs/foo/bar/install/_dummy.jar",
-                "/libs/foo/bar/install/.dummy.cfg",
-                "/libs/foo/bar/install/dummy.longextension"
+    public void testInitialResourceDetection() throws Exception {
+        assertRegisteredPaths(contentHelper.FAKE_RESOURCES);
+        assertRegisteredPaths(contentHelper.FAKE_CONFIGS);
+    }
+    
+    public void testAddFiles() throws Exception {
+        final String [] paths = {
+            "/libs/foo/bar/install/" + System.currentTimeMillis() + ".jar",
+            "/libs/foo/wii/install/" + + System.currentTimeMillis() + ".jar",
+            "/libs/foo/wii/install/" + + System.currentTimeMillis() + ".properties",
+            "/libs/foo/wii/install/" + + System.currentTimeMillis() + ".cfg",
+            "/libs/foo/wii/install/NOT_" + + System.currentTimeMillis() + ".badExtension",
+            "/libs/foo/wii/install/.NOT_startsWithDot" + + System.currentTimeMillis() + ".jar",
         };
         
-        final MockInstallableData da = new MockInstallableData("a");
-        final Set<String> installedUri = new HashSet<String>();
-        final OsgiController c = mockery.mock(OsgiController.class);
-        
-        mockery.checking(new Expectations() {{
-        	allowing(c).executeScheduledOperations();
-            allowing(c).setResourceOverrideRules(with(any(ResourceOverrideRules.class)));
-            allowing(c).getInstalledUris(); will(returnValue(installedUri));
-            allowing(c).getDigest(with(any(String.class))); will(returnValue(null)); 
-            one(c).scheduleInstallOrUpdate(with(equal(resources[0])), with(any(InstallableData.class)));
-            one(c).scheduleInstallOrUpdate(with(equal(resources[1])), with(any(InstallableData.class)));
-            one(c).scheduleInstallOrUpdate(with(equal(resources[2])), with(any(InstallableData.class)));
-        }});
-        
-        final RepositoryObserver ro = new MockRepositoryObserver(repo, c);
-        ro.activate(null);
-        
-        for(String file : resources) {
-            contentHelper.createOrUpdateFile(file, da);
-        }
-        for(String file : ignored) {
-            contentHelper.createOrUpdateFile(file, da);
+        for(String path : paths) {
+            contentHelper.createOrUpdateFile(path);
         }
-        eventHelper.waitForEvents(5000L);
-        
-        ro.runOneCycle();
-        mockery.assertIsSatisfied();
-   }
-    
-    public void testInitialDeletions() throws Exception {
-        contentHelper.setupContent();
-        
-        final Set<String> installedUri = new HashSet<String>();
-        installedUri.add("/libs/foo/bar/install/dummy.jar");
-        installedUri.add("/libs/foo/bar/install/dummy.cfg");
-        installedUri.add("/libs/watchfolder-is-gone/install/gone.cfg");
-        
-        final OsgiController c = mockery.mock(OsgiController.class);
-        final RepositoryObserver ro = new MockRepositoryObserver(repo, c);
-        
-        mockery.checking(new Expectations() {{
-        	allowing(c).executeScheduledOperations();
-            allowing(c).setResourceOverrideRules(with(any(ResourceOverrideRules.class)));
-            allowing(c).getInstalledUris(); will(returnValue(installedUri));
-            allowing(c).getDigest(with(any(String.class))); will(returnValue(null));
-            
-            // scheduleUninstall might be called multiple times for the same resource
-            // during the initial deletion analysis - the OsgiController needs to accept
-            // such multiple calls
-            atLeast(1).of(c).scheduleUninstall("/libs/foo/bar/install/dummy.jar");
-            atLeast(1).of(c).scheduleUninstall("/libs/foo/bar/install/dummy.cfg");
-            atLeast(1).of(c).scheduleUninstall("/libs/watchfolder-is-gone/install/gone.cfg");
-        }});
-        
-        ro.activate(null);
-        ro.handleInitialUninstalls();
-        mockery.assertIsSatisfied();
-    }
-    
-    public void testInitialDeletionsWithException() throws Exception {
-        contentHelper.setupContent();
-        
-        final SortedSet<String> installedUri = new TreeSet<String>();
-        installedUri.add("/libs/foo/bar/install/dummy.cfg");
-        installedUri.add("/libs/foo/bar/install/dummy.dp");
-        installedUri.add("/libs/foo/bar/install/dummy.jar");
-        
-        final OsgiController c = mockery.mock(OsgiController.class);
-        final RepositoryObserver ro = new MockRepositoryObserver(repo, c);
-        
-        // See testInitialDeletions() about multiple scheduleUninstall calls
-        mockery.checking(new Expectations() {{
-        	allowing(c).executeScheduledOperations();
-            allowing(c).setResourceOverrideRules(with(any(ResourceOverrideRules.class)));
-            allowing(c).getInstalledUris(); will(returnValue(installedUri));
-            allowing(c).getDigest(with(any(String.class))); will(returnValue(null)); 
-            atLeast(1).of(c).scheduleUninstall("/libs/foo/bar/install/dummy.cfg");
-            inSequence(sequence);
-            atLeast(1).of(c).scheduleUninstall("/libs/foo/bar/install/dummy.dp");
-            inSequence(sequence);
-            will(throwException(new JcrInstallException("Fake BundleException for testing")));
-            atLeast(1).of(c).scheduleUninstall("/libs/foo/bar/install/dummy.jar");
-            inSequence(sequence);
-        }});
-        
-        // Activating with installed resources that are not in
-        // the repository must cause them to be uninstalled
-        ro.activate(null);
-        ro.handleInitialUninstalls();
-        mockery.assertIsSatisfied();
-    }
-    
-    public void testMultipleResourcesWithException() throws Exception {
-        contentHelper.setupContent();
-        
-        final String [] resources = {
-                "/libs/foo/bar/install/dummy.jar",
-                "/libs/foo/bar/install/dummy.cfg",
-                "/libs/foo/bar/install/dummy.dp"
+        eventHelper.waitForEvents(TIMEOUT);
+        MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+        assertRegisteredPaths(paths);
+    }
+    
+    public void testAddConfigs() throws Exception {
+        final String [] paths = {
+            "/libs/foo/bar/install/" + System.currentTimeMillis() + ".jar",
+            "/libs/foo/wii/install/" + + System.currentTimeMillis() + ".jar",
+            "/libs/foo/wii/install/" + + System.currentTimeMillis() + ".properties",
+            "/libs/foo/wii/install/" + + System.currentTimeMillis() + ".cfg",
+            "/libs/foo/wii/install/YES_" + + System.currentTimeMillis() + ".badExtension",
+            "/libs/foo/wii/install/.YES_startsWithDot" + + System.currentTimeMillis() + ".jar",
         };
-        final MockInstallableData da = new MockInstallableData("a");
-        final Set<String> installedUri = new HashSet<String>();
-        final OsgiController c = mockery.mock(OsgiController.class);
-        
-        // Define the whole sequence of calls to OsgiController,
-        mockery.checking(new Expectations() {{
-        	allowing(c).executeScheduledOperations();
-            allowing(c).setResourceOverrideRules(with(any(ResourceOverrideRules.class)));
-            allowing(c).getInstalledUris(); will(returnValue(installedUri));
-            allowing(c).getDigest(with(any(String.class))); will(returnValue(null)); 
-            one(c).scheduleInstallOrUpdate(with(equal(resources[0])), with(any(InstallableData.class)));
-            one(c).scheduleInstallOrUpdate(with(equal(resources[1])), with(any(InstallableData.class)));
-            will(throwException(new JcrInstallException("Fake BundleException for testing")));
-            one(c).scheduleInstallOrUpdate(with(equal(resources[2])), with(any(InstallableData.class)));
-        }});
         
-        final RepositoryObserver ro = new MockRepositoryObserver(repo, c);
-        ro.activate(null);
-        
-        // Add files, run one cycle must install the bundles
-        for(String file : resources) {
-            contentHelper.createOrUpdateFile(file, da);
+        for(String path : paths) {
+            contentHelper.createConfig(path, null);
         }
-        eventHelper.waitForEvents(5000L);
-        ro.runOneCycle();
         
-        mockery.assertIsSatisfied();
+        eventHelper.waitForEvents(TIMEOUT);
+        MiscUtil.waitForCycles(installer, 2, TIMEOUT);
+        assertRegisteredPaths(paths);
     }
     
-    public void testFolderRegexpChange() throws Exception {
-        final File serviceDataFile = File.createTempFile(getClass().getName(), ".properties");
-        serviceDataFile.deleteOnExit();
-        contentHelper.setupContent();
-        
-       final String [] resources = {
-                "/libs/foo/bar/install/dummy.jar",
-                "/libs/foo/wii/install/dummy.cfg",
-                "/libs/foo/bar/install/dummy.dp",
-                "/libs/foo/wii/install/more.cfg",
-        };
-        
-        final MockInstallableData da = new MockInstallableData("a");
-
-        for(String file : resources) {
-            contentHelper.createOrUpdateFile(file, da);
-        }
-        
-        final Set<String> installedUri = new HashSet<String>();
-        final OsgiController c = mockery.mock(OsgiController.class);
-        final Properties props = new Properties();
-        
-        // Test with first regexp
-        mockery.checking(new Expectations() {{
-        	allowing(c).executeScheduledOperations();
-            allowing(c).setResourceOverrideRules(with(any(ResourceOverrideRules.class)));
-            allowing(c).getInstalledUris(); will(returnValue(installedUri));
-            allowing(c).getDigest(with(any(String.class))); will(returnValue(null)); 
-            atLeast(1).of(c).scheduleInstallOrUpdate(with(equal(resources[0])), with(any(InstallableData.class)));
-            atLeast(1).of(c).scheduleInstallOrUpdate(with(equal(resources[2])), with(any(InstallableData.class)));
-        }});
-        
-        final MockRepositoryObserver ro = new MockRepositoryObserver(repo, c, serviceDataFile);
-        ro.setProperties(props);
-        props.setProperty(RepositoryObserver.FOLDER_NAME_REGEXP_PROPERTY, ".*foo/bar/install$");
-        ro.activate(null);
-        ro.handleInitialUninstalls();
-        for(String file : resources) {
-            contentHelper.createOrUpdateFile(file, da);
-        }
-        eventHelper.waitForEvents(5000L);
-        ro.runOneCycle();
-        mockery.assertIsSatisfied();
-        installedUri.add(resources[0]);
-        installedUri.add(resources[2]);
-        
-        // Test with a different regexp, install.A resources must be uninstalled
-        mockery.checking(new Expectations() {{
-        	allowing(c).executeScheduledOperations();
-            allowing(c).setResourceOverrideRules(with(any(ResourceOverrideRules.class)));
-            allowing(c).getInstalledUris(); will(returnValue(installedUri));
-            allowing(c).getDigest(with(any(String.class))); will(returnValue(null)); 
-            atLeast(1).of(c).scheduleUninstall(resources[0]);
-            atLeast(1).of(c).scheduleUninstall(resources[2]);
-            atLeast(1).of(c).scheduleInstallOrUpdate(with(equal(resources[1])), with(any(InstallableData.class)));
-            atLeast(1).of(c).scheduleInstallOrUpdate(with(equal(resources[3])), with(any(InstallableData.class)));
-        }});
-        
-        props.setProperty(RepositoryObserver.FOLDER_NAME_REGEXP_PROPERTY, ".*foo/wii/install$");
-        ro.activate(null);
-        ro.handleInitialUninstalls();
-        for(String file : resources) {
-            contentHelper.createOrUpdateFile(file, da);
-        }
-        eventHelper.waitForEvents(5000L);
-        ro.runOneCycle();
-        mockery.assertIsSatisfied();
-    }
-    */
 }
\ No newline at end of file