Author: bdelacretaz
Date: Wed Feb 2 14:06:15 2011
New Revision: 1066470
URL: http://svn.apache.org/viewvc?rev=1066470&view=rev
Log:
SLING-1963 - modularize TestsProvider, in preparation for scriptable tests
Added:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestsProvider.java
(with props)
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/AutoDetect.java
- copied, changed from r1066422,
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/AutoDetect.java
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/SlingAnnotationsTestRunner.java
- copied, changed from r1066422,
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/SlingAnnotationsTestRunner.java
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/TestReference.java
- copied, changed from r1066422,
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestReference.java
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/BundleTestsProvider.java
(with props)
Removed:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/AutoDetect.java
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/JUnitConstants.java
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/SlingAnnotationsTestRunner.java
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestReference.java
Modified:
sling/whiteboard/bdelacretaz/junit/core/pom.xml
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/Activator.java
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/JUnitTestsManager.java
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/AnnotationsProcessor.java
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitServlet.java
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitTestsManagerImpl.java
sling/whiteboard/bdelacretaz/junit/testbundle/src/main/java/org/apache/sling/junit/testbundle/tests/OsgiAwareTest.java
Modified: sling/whiteboard/bdelacretaz/junit/core/pom.xml
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/pom.xml?rev=1066470&r1=1066469&r2=1066470&view=diff
==============================================================================
--- sling/whiteboard/bdelacretaz/junit/core/pom.xml (original)
+++ sling/whiteboard/bdelacretaz/junit/core/pom.xml Wed Feb 2 14:06:15 2011
@@ -60,6 +60,7 @@
<Bundle-Activator>org.apache.sling.junit.Activator</Bundle-Activator>
<Export-Package>
org.apache.sling.junit;version=${project.version},
+
org.apache.sling.junit.annotations;version=${project.version},
junit.framework;version=${junit.version},
org.junit;version=${junit.version},
org.junit.matchers.*;version=${junit.version},
Modified:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/Activator.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/Activator.java?rev=1066470&r1=1066469&r2=1066470&view=diff
==============================================================================
---
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/Activator.java
(original)
+++
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/Activator.java
Wed Feb 2 14:06:15 2011
@@ -19,13 +19,23 @@ package org.apache.sling.junit;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
+/** Used to make our BundleContext available to
+ * JUnit classes that need it but have no
+ * OSGi context.
+ */
public class Activator implements BundleActivator {
+ private static BundleContext bundleContext;
+
+ public static BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
public void start(BundleContext context) throws Exception {
- SlingAnnotationsTestRunner.setBundleContext(context);
+ bundleContext = context;
}
public void stop(BundleContext context) throws Exception {
- SlingAnnotationsTestRunner.setBundleContext(null);
+ bundleContext = null;
}
}
Modified:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/JUnitTestsManager.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/JUnitTestsManager.java?rev=1066470&r1=1066469&r2=1066470&view=diff
==============================================================================
---
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/JUnitTestsManager.java
(original)
+++
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/JUnitTestsManager.java
Wed Feb 2 14:06:15 2011
@@ -16,13 +16,13 @@
*/
package org.apache.sling.junit;
-import java.util.List;
+import java.util.Collection;
/** Service that gives access to JUnit test classes */
public interface JUnitTestsManager {
- /** Return the names of all currently registered test classes */
- public List<String> getTestClasses();
+ /** Return the names of all currently available tests */
+ public Collection<String> getTestNames();
- /** Instantiate specified test class from the appropriate bundle */
- public Class<?> getTestClass(String className) throws
ClassNotFoundException;
+ /** Instantiate test class for specified test */
+ public Class<?> getTestClass(String testName) throws
ClassNotFoundException;
}
Added:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestsProvider.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestsProvider.java?rev=1066470&view=auto
==============================================================================
---
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestsProvider.java
(added)
+++
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestsProvider.java
Wed Feb 2 14:06:15 2011
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.junit;
+
+import java.util.List;
+
+/** Provides tests, for example by scanning bundles,
+ * finding test resources in a content repository, etc.
+ */
+public interface TestsProvider {
+ /** Return this service's PID, client might use it later
+ * to instantiate a specific test.
+ */
+ String getServicePid();
+
+ /** Return the list of available tests */
+ List<String> getTestNames();
+
+ /** Create a test class to execute the specified test */
+ Class<?> createTestClass(String testName) throws ClassNotFoundException;
+
+ /** Return the timestamp at which our list of tests was last modified */
+ long lastModified();
+}
Propchange:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestsProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestsProvider.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL
Copied:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/AutoDetect.java
(from r1066422,
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/AutoDetect.java)
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/AutoDetect.java?p2=sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/AutoDetect.java&p1=sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/AutoDetect.java&r1=1066422&r2=1066470&rev=1066470&view=diff
==============================================================================
---
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/AutoDetect.java
(original)
+++
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/AutoDetect.java
Wed Feb 2 14:06:15 2011
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sling.junit;
+package org.apache.sling.junit.annotations;
/**
* Placeholder class for default value of annotation
Copied:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/SlingAnnotationsTestRunner.java
(from r1066422,
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/SlingAnnotationsTestRunner.java)
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/SlingAnnotationsTestRunner.java?p2=sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/SlingAnnotationsTestRunner.java&p1=sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/SlingAnnotationsTestRunner.java&r1=1066422&r2=1066470&rev=1066470&view=diff
==============================================================================
---
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/SlingAnnotationsTestRunner.java
(original)
+++
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/SlingAnnotationsTestRunner.java
Wed Feb 2 14:06:15 2011
@@ -14,8 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sling.junit;
+package org.apache.sling.junit.annotations;
+import org.apache.sling.junit.Activator;
+import org.apache.sling.junit.TestObjectProcessor;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
import org.osgi.framework.BundleContext;
@@ -31,24 +33,19 @@ import org.slf4j.LoggerFactory;
public class SlingAnnotationsTestRunner extends BlockJUnit4ClassRunner {
private static final Logger log =
LoggerFactory.getLogger(SlingAnnotationsTestRunner.class);
- private static BundleContext bundleContext;
private static TestObjectProcessor testObjectProcessor;
public SlingAnnotationsTestRunner(Class<?> clazz) throws
InitializationError {
super(clazz);
}
- static void setBundleContext(BundleContext ctx) {
- bundleContext = ctx;
- testObjectProcessor = null;
- }
-
@Override
protected Object createTest() throws Exception {
- if(testObjectProcessor == null && bundleContext != null) {
- final ServiceReference ref =
bundleContext.getServiceReference(TestObjectProcessor.class.getName());
+ final BundleContext ctx = Activator.getBundleContext();
+ if(testObjectProcessor == null && ctx != null) {
+ final ServiceReference ref =
ctx.getServiceReference(TestObjectProcessor.class.getName());
if(ref != null) {
- testObjectProcessor =
(TestObjectProcessor)bundleContext.getService(ref);
+ testObjectProcessor = (TestObjectProcessor)ctx.getService(ref);
}
log.info("Got TestObjectProcessor {}", testObjectProcessor);
}
Copied:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/TestReference.java
(from r1066422,
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestReference.java)
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/TestReference.java?p2=sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/TestReference.java&p1=sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestReference.java&r1=1066422&r2=1066470&rev=1066470&view=diff
==============================================================================
---
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/TestReference.java
(original)
+++
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/annotations/TestReference.java
Wed Feb 2 14:06:15 2011
@@ -14,13 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sling.junit;
+package org.apache.sling.junit.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+
/** Annotation used to inject services in test classes. Similar
* to the Felix @Reference annotation, but we need RetentionPolicy.RUNTIME
* so we cannot use that one.
Modified:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/AnnotationsProcessor.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/AnnotationsProcessor.java?rev=1066470&r1=1066469&r2=1066470&view=diff
==============================================================================
---
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/AnnotationsProcessor.java
(original)
+++
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/AnnotationsProcessor.java
Wed Feb 2 14:06:15 2011
@@ -21,7 +21,7 @@ import java.lang.reflect.Field;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.junit.TestObjectProcessor;
-import org.apache.sling.junit.TestReference;
+import org.apache.sling.junit.annotations.TestReference;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
Added:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/BundleTestsProvider.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/BundleTestsProvider.java?rev=1066470&view=auto
==============================================================================
---
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/BundleTestsProvider.java
(added)
+++
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/BundleTestsProvider.java
Wed Feb 2 14:06:15 2011
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.junit.impl;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.junit.TestsProvider;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** A TestProvider that gets test classes from bundles
+ * that have a Sling-Test-Regexp header and corresponding
+ * exported classes.
+ */
+@Component
+@Service
+public class BundleTestsProvider implements TestsProvider, BundleListener {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private long lastModified;
+ private BundleContext bundleContext;
+ private String pid;
+
+ public static final String SLING_TEST_REGEXP = "Sling-Test-Regexp";
+
+ /** Symbolic names of bundles that changed state - if not empty, need
+ * to adjust the list of tests
+ */
+ private final List<String> changedBundles = new ArrayList<String>();
+
+ /** List of (candidate) test classes, keyed by bundle so that we can
+ * update them easily when bundles come and go
+ */
+ private final Map<String, List<String>> testClassesMap = new
HashMap<String, List<String>>();
+
+ protected void activate(ComponentContext ctx) {
+ bundleContext = ctx.getBundleContext();
+ bundleContext.addBundleListener(this);
+
+ // Initially consider all bundles as "changed"
+ for(Bundle b : bundleContext.getBundles()) {
+ if(getSlingTestRegexp(b) != null) {
+ changedBundles.add(b.getSymbolicName());
+ log.debug("Will look for test classes inside bundle {}",
b.getSymbolicName());
+ }
+ }
+
+ lastModified = System.currentTimeMillis();
+ pid = (String)ctx.getProperties().get(Constants.SERVICE_PID);
+ }
+
+ protected void deactivate(ComponentContext ctx) {
+ bundleContext.removeBundleListener(this);
+ bundleContext = null;
+ changedBundles.clear();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ", pid=" + pid;
+ }
+
+ /** Update testClasses if bundle changes require it */
+ private void maybeUpdateTestClasses() {
+ if(changedBundles.isEmpty()) {
+ return;
+ }
+
+ // Get the list of bundles that have changed
+ final List<String> bundlesToUpdate = new ArrayList<String>();
+ synchronized (changedBundles) {
+ bundlesToUpdate.addAll(changedBundles);
+ changedBundles.clear();
+ }
+
+ // Remove test classes that belong to changed bundles
+ for(String symbolicName : bundlesToUpdate) {
+ testClassesMap.remove(symbolicName);
+ }
+
+ // Get test classes from bundles that are in our list
+ for(Bundle b : bundleContext.getBundles()) {
+ if(bundlesToUpdate.contains(b.getSymbolicName())) {
+ final List<String> testClasses = getTestClasses(b);
+ if(testClasses != null) {
+ testClassesMap.put(b.getSymbolicName(), testClasses);
+ log.debug("{} test classes found in bundle {}, added to
our list",
+ testClasses.size(), b.getSymbolicName());
+ } else {
+ log.debug("No test classes found in bundle {}",
b.getSymbolicName());
+ }
+ }
+ }
+ }
+
+ /** Called when a bundle changes state */
+ public void bundleChanged(BundleEvent event) {
+ // Only consider bundles which contain tests
+ final Bundle b = event.getBundle();
+ if(getSlingTestRegexp(b) == null) {
+ log.debug("Bundle {} does not have {} header, ignored",
+ b.getSymbolicName(), SLING_TEST_REGEXP);
+ return;
+ }
+ synchronized (changedBundles) {
+ log.debug("Got BundleEvent for Bundle {}, will rebuild its lists
of tests");
+ changedBundles.add(b.getSymbolicName());
+ }
+ lastModified = System.currentTimeMillis();
+ }
+
+ private String getSlingTestRegexp(Bundle b) {
+ return (String)b.getHeaders().get(SLING_TEST_REGEXP);
+ }
+
+ /** Get test classes that bundle b provides (as done in Felix/Sigil) */
+ private List<String> getTestClasses(Bundle b) {
+ final List<String> result = new ArrayList<String>();
+ Pattern testClassRegexp = null;
+ final String headerValue = getSlingTestRegexp(b);
+ try {
+ testClassRegexp = Pattern.compile(headerValue);
+ } catch(PatternSyntaxException pse) {
+ log.warn(
+ "Invalid pattern '" + headerValue
+ + "' for bundle " + b.getSymbolicName() + ", ignored",
+ pse);
+ }
+
+ if(testClassRegexp == null) {
+ log.info("Bundle {} does not have {} header, not looking for test
classes", SLING_TEST_REGEXP);
+ } else if(Bundle.ACTIVE != b.getState()) {
+ log.info("Bundle {} is not active, no test classes considered",
b.getSymbolicName());
+ } else {
+ @SuppressWarnings("unchecked")
+ Enumeration<URL> classUrls = b.findEntries("", "*.class", true);
+ while (classUrls.hasMoreElements()) {
+ URL url = classUrls.nextElement();
+ final String name = toClassName(url);
+ if(testClassRegexp.matcher(name).matches()) {
+ result.add(name);
+ } else {
+ log.debug("Class {} does not match {} pattern {} of bundle
{}, ignored",
+ new Object[] { name, SLING_TEST_REGEXP,
testClassRegexp, b.getSymbolicName() });
+ }
+ }
+ log.info("{} test classes found in bundle {}", result.size(),
b.getSymbolicName());
+ }
+
+ return result;
+ }
+
+ /** Convert class URL to class name */
+ private String toClassName(URL url) {
+ final String f = url.getFile();
+ final String cn = f.substring(1, f.length() - ".class".length());
+ return cn.replace('/', '.');
+ }
+
+ /** Find bundle by symbolic name */
+ private Bundle findBundle(String symbolicName) {
+ for(Bundle b : bundleContext.getBundles()) {
+ if(b.getSymbolicName().equals(symbolicName)) {
+ return b;
+ }
+ }
+ return null;
+ }
+
+ /** @inheritDoc */
+ public Class<?> createTestClass(String testName) throws
ClassNotFoundException {
+ // Find the bundle to which the class belongs
+ Bundle b = null;
+ for(Map.Entry<String, List<String>> e : testClassesMap.entrySet()) {
+ if(e.getValue().contains(testName)) {
+ b = findBundle(e.getKey());
+ break;
+ }
+ }
+
+ if(b == null) {
+ throw new IllegalArgumentException("No Bundle found that supplies
test class " + testName);
+ }
+ return b.loadClass(testName);
+ }
+
+ /** @inheritDoc */
+ public long lastModified() {
+ return lastModified;
+ }
+
+ /** @inheritDoc */
+ public String getServicePid() {
+ return pid;
+ }
+
+ /** @inheritDoc */
+ public List<String> getTestNames() {
+ maybeUpdateTestClasses();
+ final List<String> result = new ArrayList<String>();
+ for(List<String> list : testClassesMap.values()) {
+ result.addAll(list);
+ }
+ return result;
+ }
+}
\ No newline at end of file
Propchange:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/BundleTestsProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/BundleTestsProvider.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL
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=1066470&r1=1066469&r2=1066470&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
Wed Feb 2 14:06:15 2011
@@ -18,7 +18,7 @@ package org.apache.sling.junit.impl;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.List;
+import java.util.Collection;
import javax.servlet.ServletException;
@@ -29,7 +29,6 @@ import org.apache.felix.scr.annotations.
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
-import org.apache.sling.junit.JUnitConstants;
import org.apache.sling.junit.JUnitTestsManager;
import org.junit.runner.JUnitCore;
@@ -54,18 +53,17 @@ public class JUnitServlet extends SlingA
pw.println();
// Any test classes?
- final List<String> testClasses = testsManager.getTestClasses();
+ final Collection<String> testClasses = testsManager.getTestNames();
if(testClasses.isEmpty()) {
pw.println(
- "No test classes found, please activate at least one
bundle "
- + "which exports JUnit test classes and points to them
using a "
- + JUnitConstants.SLING_TEST_REGEXP + " header."
+ "No test classes found, check the requirements of the
active " +
+ "TestsProvider services for how to supply tests."
);
return;
}
// List test classes
- pw.println("TEST CLASSES (found in bundles that have a " +
JUnitConstants.SLING_TEST_REGEXP + " header):");
+ pw.println("TEST CLASSES");
for(String className : testClasses) {
pw.println(className);
}
Modified:
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitTestsManagerImpl.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitTestsManagerImpl.java?rev=1066470&r1=1066469&r2=1066470&view=diff
==============================================================================
---
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitTestsManagerImpl.java
(original)
+++
sling/whiteboard/bdelacretaz/junit/core/src/main/java/org/apache/sling/junit/impl/JUnitTestsManagerImpl.java
Wed Feb 2 14:06:15 2011
@@ -16,193 +16,131 @@
*/
package org.apache.sling.junit.impl;
-import static org.apache.sling.junit.JUnitConstants.SLING_TEST_REGEXP;
-
-import java.net.URL;
import java.util.ArrayList;
-import java.util.Enumeration;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.junit.JUnitTestsManager;
-import org.osgi.framework.Bundle;
+import org.apache.sling.junit.TestsProvider;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.BundleListener;
+import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
+import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component
@Service
-public class JUnitTestsManagerImpl implements BundleListener,JUnitTestsManager
{
+public class JUnitTestsManagerImpl implements JUnitTestsManager {
private final Logger log = LoggerFactory.getLogger(getClass());
+ private ServiceTracker tracker;
+ private int lastTrackingCount = -1;
private BundleContext bundleContext;
- /** Symbolic names of bundles that changed state - if not empty, need
- * to adjust the list of tests
- */
- private final List<String> changedBundles = new ArrayList<String>();
-
- /** List of (candidate) test classes, keyed by bundle so that we can
- * update them easily when bundles come and go
- */
- private final Map<String, List<String>> testClassesMap = new
HashMap<String, List<String>>();
-
- private String getSlingTestRegexp(Bundle b) {
- return (String)b.getHeaders().get(SLING_TEST_REGEXP);
- }
+ // List of providers
+ private List<TestsProvider> providers = new ArrayList<TestsProvider>();
+
+ // Map of test names to their provider's PID
+ private Map<String, String> tests = new HashMap<String, String>();
+
+ // Last-modified values for each provider
+ private Map<String, Long> lastModified = new HashMap<String, Long>();
protected void activate(ComponentContext ctx) {
bundleContext = ctx.getBundleContext();
- bundleContext.addBundleListener(this);
-
- // Initially consider all bundles as "changed"
- for(Bundle b : bundleContext.getBundles()) {
- if(getSlingTestRegexp(b) != null) {
- changedBundles.add(b.getSymbolicName());
- log.debug("Will look for test classes inside bundle {}",
b.getSymbolicName());
- }
- }
+ tracker = new ServiceTracker(bundleContext,
TestsProvider.class.getName(), null);
+ tracker.open();
}
-
+
protected void deactivate(ComponentContext ctx) {
- bundleContext.removeBundleListener(this);
- bundleContext = null;
- changedBundles.clear();
- }
-
- /** Called when a bundle changes state */
- public void bundleChanged(BundleEvent event) {
- // Only consider bundles which contain tests
- final Bundle b = event.getBundle();
- if(getSlingTestRegexp(b) == null) {
- log.debug("Bundle {} does not have {} header, ignored",
- b.getSymbolicName(), SLING_TEST_REGEXP);
- return;
- }
- synchronized (changedBundles) {
- log.debug("Got BundleEvent for Bundle {}, will rebuild its lists
of tests");
- changedBundles.add(b.getSymbolicName());
+ if(tracker != null) {
+ tracker.close();
}
+ tracker = null;
+ bundleContext = null;
}
- /** Update testClasses if bundle changes require it */
- private void maybeUpdateTestClasses() {
- if(changedBundles.isEmpty()) {
- return;
- }
-
- // Get the list of bundles that have changed
- final List<String> bundlesToUpdate = new ArrayList<String>();
- synchronized (changedBundles) {
- bundlesToUpdate.addAll(changedBundles);
- changedBundles.clear();
- }
-
- // Remove test classes that belong to changed bundles
- for(String symbolicName : bundlesToUpdate) {
- testClassesMap.remove(symbolicName);
+ /** inheritDoc */
+ public Class<?> getTestClass(String testName) throws
ClassNotFoundException {
+ maybeUpdateProviders();
+
+ // find TestsProvider that can instantiate testName
+ final String providerPid = tests.get(testName);
+ if(providerPid == null) {
+ throw new IllegalStateException("Provider PID not found for test "
+ testName);
+ }
+ TestsProvider provider = null;
+ for(TestsProvider p : providers) {
+ if(p.getServicePid().equals(providerPid)) {
+ provider = p;
+ break;
+ }
}
- // Get test classes from bundles that are in our list
- for(Bundle b : bundleContext.getBundles()) {
- if(bundlesToUpdate.contains(b.getSymbolicName())) {
- final List<String> testClasses = getTestClasses(b);
- if(testClasses != null) {
- testClassesMap.put(b.getSymbolicName(), testClasses);
- log.debug("{} test classes found in bundle {}, added to
our list",
- testClasses.size(), b.getSymbolicName());
- } else {
- log.debug("No test classes found in bundle {}",
b.getSymbolicName());
- }
- }
+ if(provider == null) {
+ throw new IllegalStateException("No TestsProvider found for PID "
+ providerPid);
}
- }
- /** @inheritDoc */
- public List<String> getTestClasses() {
- maybeUpdateTestClasses();
- final List<String> result = new ArrayList<String>();
- for(List<String> list : testClassesMap.values()) {
- result.addAll(list);
- }
- return result;
+ log.debug("Using provider {} to create test class {}", testName);
+ return provider.createTestClass(testName);
}
- /** Get test classes that bundle b provides (as done in Felix/Sigil) */
- private List<String> getTestClasses(Bundle b) {
- final List<String> result = new ArrayList<String>();
- Pattern testClassRegexp = null;
- final String headerValue = getSlingTestRegexp(b);
- try {
- testClassRegexp = Pattern.compile(headerValue);
- } catch(PatternSyntaxException pse) {
- log.warn(
- "Invalid pattern '" + headerValue
- + "' for bundle " + b.getSymbolicName() + ", ignored",
- pse);
+ /** inheritDoc */
+ public Collection<String> getTestNames() {
+ maybeUpdateProviders();
+
+ // If any provider has changes, reload the whole list
+ // of test names (to keep things simple)
+ boolean reload = false;
+ for(TestsProvider p : providers) {
+ final Long lastMod = lastModified.get(p.getServicePid());
+ if(lastMod == null || lastMod.longValue() != p.lastModified()) {
+ reload = true;
+ log.debug("{} updated, will reload test names from all
providers", p);
+ break;
+ }
}
- if(testClassRegexp == null) {
- log.info("Bundle {} does not have {} header, not looking for test
classes", SLING_TEST_REGEXP);
- } else if(Bundle.ACTIVE != b.getState()) {
- log.info("Bundle {} is not active, no test classes considered",
b.getSymbolicName());
- } else {
- @SuppressWarnings("unchecked")
- Enumeration<URL> classUrls = b.findEntries("", "*.class", true);
- while (classUrls.hasMoreElements()) {
- URL url = classUrls.nextElement();
- final String name = toClassName(url);
- if(testClassRegexp.matcher(name).matches()) {
- result.add(name);
- } else {
- log.debug("Class {} does not match {} pattern {} of bundle
{}, ignored",
- new Object[] { name, SLING_TEST_REGEXP,
testClassRegexp, b.getSymbolicName() });
+ if(reload) {
+ tests.clear();
+ for(TestsProvider p : providers) {
+ final String pid = p.getServicePid();
+ if(pid == null) {
+ log.warn("{} has null PID, ignored", p);
+ continue;
+ }
+ lastModified.put(pid, new Long(p.lastModified()));
+ final List<String> names = p.getTestNames();
+ for(String name : names) {
+ tests.put(name, pid);
}
+ log.debug("Added {} test names from provider {}",
names.size(), p);
}
- log.info("{} test classes found in bundle {}", result.size(),
b.getSymbolicName());
+ log.info("Test names reloaded, total {} names from {} providers",
tests.size(), providers.size());
}
- return result;
+ return tests.keySet();
}
- /** Convert class URL to class name */
- private String toClassName(URL url) {
- final String f = url.getFile();
- final String cn = f.substring(1, f.length() - ".class".length());
- return cn.replace('/', '.');
- }
-
- /** Find bundle by symbolic name */
- private Bundle findBundle(String symbolicName) {
- for(Bundle b : bundleContext.getBundles()) {
- if(b.getSymbolicName().equals(symbolicName)) {
- return b;
+ /** Update our list of providers if tracker changed */
+ private void maybeUpdateProviders() {
+ if(tracker.getTrackingCount() != lastTrackingCount) {
+ // List of providers changed, need to reload everything
+ lastModified.clear();
+ List<TestsProvider> newList = new ArrayList<TestsProvider>();
+ for(ServiceReference ref : tracker.getServiceReferences()) {
+ newList.add((TestsProvider)bundleContext.getService(ref));
}
- }
- return null;
- }
-
- /** @inheritDoc */
- public Class<?> getTestClass(String className) throws
ClassNotFoundException {
- // Find the bundle to which the class belongs
- Bundle b = null;
- for(Map.Entry<String, List<String>> e : testClassesMap.entrySet()) {
- if(e.getValue().contains(className)) {
- b = findBundle(e.getKey());
- break;
+ synchronized (providers) {
+ providers.clear();
+ providers.addAll(newList);
}
+ log.info("Updated list of TestsProvider: {}", providers);
}
-
- if(b == null) {
- throw new IllegalArgumentException("No Bundle found that supplies
test class " + className);
- }
- return b.loadClass(className);
+ lastTrackingCount = tracker.getTrackingCount();
}
}
\ No newline at end of file
Modified:
sling/whiteboard/bdelacretaz/junit/testbundle/src/main/java/org/apache/sling/junit/testbundle/tests/OsgiAwareTest.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/junit/testbundle/src/main/java/org/apache/sling/junit/testbundle/tests/OsgiAwareTest.java?rev=1066470&r1=1066469&r2=1066470&view=diff
==============================================================================
---
sling/whiteboard/bdelacretaz/junit/testbundle/src/main/java/org/apache/sling/junit/testbundle/tests/OsgiAwareTest.java
(original)
+++
sling/whiteboard/bdelacretaz/junit/testbundle/src/main/java/org/apache/sling/junit/testbundle/tests/OsgiAwareTest.java
Wed Feb 2 14:06:15 2011
@@ -18,8 +18,8 @@ package org.apache.sling.junit.testbundl
import static org.junit.Assert.assertNotNull;
-import org.apache.sling.junit.SlingAnnotationsTestRunner;
-import org.apache.sling.junit.TestReference;
+import org.apache.sling.junit.annotations.SlingAnnotationsTestRunner;
+import org.apache.sling.junit.annotations.TestReference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.osgi.framework.BundleContext;