Return-Path: Delivered-To: apmail-sling-commits-archive@www.apache.org Received: (qmail 22804 invoked from network); 4 Feb 2011 13:55:28 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 4 Feb 2011 13:55:28 -0000 Received: (qmail 3694 invoked by uid 500); 4 Feb 2011 13:55:28 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 3631 invoked by uid 500); 4 Feb 2011 13:55:26 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 3624 invoked by uid 99); 4 Feb 2011 13:55:25 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 04 Feb 2011 13:55:25 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 04 Feb 2011 13:55:24 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id EC55823889E5; Fri, 4 Feb 2011 13:55:03 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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 Date: Fri, 04 Feb 2011 13:55:03 -0000 To: commits@sling.apache.org From: bdelacretaz@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110204135503.EC55823889E5@eris.apache.org> 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 testClasses = testsManager.getTestNames(); + final Collection testClassesCollection = testsManager.getTestNames(); + final List testClasses = new LinkedList(); + 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 testPaths = new LinkedList(); + 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 listeners = new ArrayList(); + + 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 result = new LinkedList(); - result.add(getClass().getSimpleName() + "Tests"); + result.add(TEST_CLASS_NAME); return result; } - private List queryTestPaths() { - final List result = new LinkedList(); + private List 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 newList = new LinkedList(); - // 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; } }