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 2011/02/04 14:55:03 UTC

svn commit: r1067179 - in /sling/whiteboard/bdelacretaz/junit: core/src/main/java/org/apache/sling/junit/impl/JUnitServlet.java scriptable/src/main/java/org/apache/sling/junit/scriptable/ScriptableTestsProvider.java

Author: bdelacretaz
Date: Fri Feb  4 13:55:03 2011
New Revision: 1067179

URL: http://svn.apache.org/viewvc?rev=1067179&view=rev
Log:
SLING-1963 - ScriptableTestsProvider uses observation to watch test resources

Modified:
    sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitServlet.java
    sling/whiteboard/bdelacretaz/junit/scriptable/src/main/java/org/apache/sling/junit/scriptable/ScriptableTestsProvider.java

Modified: sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitServlet.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitServlet.java?rev=1067179&r1=1067178&r2=1067179&view=diff
==============================================================================
--- sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitServlet.java (original)
+++ sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitServlet.java Fri Feb  4 13:55:03 2011
@@ -19,6 +19,9 @@ package org.apache.sling.junit.impl;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -76,7 +79,10 @@ public class JUnitServlet extends HttpSe
         pw.println();
         
         // Any test classes?
-        final Collection<String> testClasses = testsManager.getTestNames();
+        final Collection<String> testClassesCollection = testsManager.getTestNames();
+        final List<String> testClasses = new LinkedList<String>();
+        testClasses.addAll(testClassesCollection);
+        Collections.sort(testClasses);
         if(testClasses.isEmpty()) {
             pw.println(
                     "No test classes found, check the requirements of the active " +

Modified: sling/whiteboard/bdelacretaz/junit/scriptable/src/main/java/org/apache/sling/junit/scriptable/ScriptableTestsProvider.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/scriptable/src/main/java/org/apache/sling/junit/scriptable/ScriptableTestsProvider.java?rev=1067179&r1=1067178&r2=1067179&view=diff
==============================================================================
--- sling/whiteboard/bdelacretaz/junit/scriptable/src/main/java/org/apache/sling/junit/scriptable/ScriptableTestsProvider.java (original)
+++ sling/whiteboard/bdelacretaz/junit/scriptable/src/main/java/org/apache/sling/junit/scriptable/ScriptableTestsProvider.java Fri Feb  4 13:55:03 2011
@@ -16,6 +16,7 @@
  */
 package org.apache.sling.junit.scriptable;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
@@ -23,6 +24,9 @@ import java.util.List;
 import javax.jcr.NodeIterator;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
 import javax.jcr.query.Query;
 
 import org.apache.felix.scr.annotations.Component;
@@ -48,10 +52,15 @@ public class ScriptableTestsProvider imp
     private String pid;
     private Session session;
     private ResourceResolver resolver;
+    private long lastModified = System.currentTimeMillis();
+    private long lastReloaded;
     
     /** List of resource paths that point to tests */
     private static List<String> testPaths = new LinkedList<String>();
     
+    public static final String SLING_TEST_NODETYPE = "sling:Test";
+    public static final String TEST_CLASS_NAME = ScriptableTestsProvider.class.getName();
+    
     /** We only consider test resources under the search path
      *  of the JCR resource resolver. These paths are supposed 
      *  to be secured, as they contain other admin stuff anyway, 
@@ -68,6 +77,22 @@ public class ScriptableTestsProvider imp
     @Reference
     private JcrResourceResolverFactory resolverFactory;
     
+    // Need one listener per root path
+    private List<EventListener> listeners = new ArrayList<EventListener>();
+    
+    class RootListener implements EventListener {
+        private final String path;
+        
+        RootListener(String path) {
+            this.path = path;
+        }
+        
+        public void onEvent(EventIterator it) {
+            log.debug("Change detected under {}, will reload list of test paths", path);
+            lastModified = System.currentTimeMillis();
+        }
+    };
+    
     protected void activate(ComponentContext ctx) throws Exception {
         pid = (String)ctx.getProperties().get(Constants.SERVICE_PID);
         session = repository.loginAdministrative(repository.getDefaultWorkspace());
@@ -81,19 +106,42 @@ public class ScriptableTestsProvider imp
                 allowedRoots[i] += "/";
             }
         }
+        
+        // Listen to changes to sling:Test nodes under allowed roots
+        final int eventTypes = 
+            Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
+        final boolean isDeep = true;
+        final boolean noLocal = true;
+        final String [] nodeTypes = { SLING_TEST_NODETYPE };
+        final String [] uuid = null;
+        for(String path : allowedRoots) {
+            final EventListener listener = new RootListener(path);
+            listeners.add(listener);
+            session.getWorkspace().getObservationManager().addEventListener(listener, eventTypes, path, isDeep, uuid, nodeTypes, noLocal);
+            log.debug("Listening for JCR events under {}", path);
+            
+        }
+        
         log.info("Activated, will look for test resources under {}", Arrays.asList(allowedRoots));
     }
     
     protected void deactivate(ComponentContext ctx) throws RepositoryException {
         resolver = null;
         if(session != null) {
+            for(EventListener listener : listeners) {
+                session.getWorkspace().getObservationManager().removeEventListener(listener);
+            }
+            listeners.clear();
             session.logout();
         }
         session = null;
     }
     
     public Class<?> createTestClass(String testName) throws ClassNotFoundException {
-        queryTestPaths();
+        if(!testName.equals(TEST_CLASS_NAME)) {
+            throw new ClassNotFoundException(testName + " - the only valid name is " + TEST_CLASS_NAME);
+        }
+        maybeQueryTestResources();
         
         if(testPaths.size() == 0) {
             return ExplainTests.class;
@@ -114,42 +162,47 @@ public class ScriptableTestsProvider imp
         // test class per test resource but that looks harder. Maybe
         // use the Sling compiler to generate test classes? 
         final List<String> result = new LinkedList<String>();
-        result.add(getClass().getSimpleName() + "Tests");
+        result.add(TEST_CLASS_NAME);
         return result;
     }
     
-    private List<String> queryTestPaths() {
-        final List<String> result = new LinkedList<String>();
+    private List<String> maybeQueryTestResources() {
+        if(lastModified <= lastReloaded) {
+            log.debug("No changes detected, keeping existing list of {} test resources", testPaths.size());
+            return testPaths;
+        }
+        
+        log.info("Changes detected, reloading list of test resources");
+        lastReloaded = System.currentTimeMillis();
+        final List<String> newList = new LinkedList<String>();
         
-        // TODO do we want to cache results, use observation, etc.
         try {
             for(String root : allowedRoots) {
-                final String statement = "/jcr:root" + root + "/element(*, sling:Test)";
+                final String statement = "/jcr:root" + root + "/element(*, " + SLING_TEST_NODETYPE + ")";
                 log.debug("Querying for test nodes: {}", statement);
                 final Query q = session.getWorkspace().getQueryManager().createQuery(statement, Query.XPATH);
                 final NodeIterator it = q.execute().getNodes();
                 while(it.hasNext()) {
                     final String path = it.nextNode().getPath();
-                    result.add(path);
+                    newList.add(path);
                     log.debug("Test resource found: {}", path);
                 }
             }
             log.info("List of test resources updated, {} resource(s) found under {}", 
-                    result.size(), Arrays.asList(allowedRoots));
+                    newList.size(), Arrays.asList(allowedRoots));
         } catch(RepositoryException re) {
             log.warn("RepositoryException in getTestNames()", re);
         }
 
         synchronized (testPaths) {
             testPaths.clear();
-            testPaths.addAll(result);
+            testPaths.addAll(newList);
         }
         
         return testPaths;
     }
-
+    
     public long lastModified() {
-        // TODO caching etc.
-        return System.currentTimeMillis();
+        return lastModified;
     }
 }