Author: kwin
Date: Thu Feb 23 08:46:15 2017
New Revision: 1784090

URL: http://svn.apache.org/viewvc?rev=1784090&view=rev
Log:
SLING-6546, optionally enable logging, persist test-bundles and prevent test 
bundle from being uninstalled

Modified:
    
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/ClientSideTeleporter.java
    
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/DefaultPropertyBasedCustomizer.java
    
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/DependencyAnalyzer.java

Modified: 
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/ClientSideTeleporter.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/ClientSideTeleporter.java?rev=1784090&r1=1784089&r2=1784090&view=diff
==============================================================================
--- 
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/ClientSideTeleporter.java
 (original)
+++ 
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/ClientSideTeleporter.java
 Thu Feb 23 08:46:15 2017
@@ -18,8 +18,13 @@ package org.apache.sling.testing.telepor
 
 import static org.junit.Assert.fail;
 
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.MalformedURLException;
 import java.text.SimpleDateFormat;
 import java.util.Collection;
@@ -30,12 +35,16 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.sling.junit.rules.TeleporterRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 import org.ops4j.pax.tinybundles.core.TinyBundle;
 import org.ops4j.pax.tinybundles.core.TinyBundles;
 import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.helpers.NOPLogger;
 
 /** Client-side TeleporterRule. Packages the
  *  test to run in a test bundle, installs the bundle,
@@ -49,12 +58,17 @@ public class ClientSideTeleporter extend
     private int testReadyTimeoutSeconds = 20;
     private int webConsoleReadyTimeoutSeconds = 30;
     private int waitForServiceTimout = 10;
+    private boolean enableLogging = false;
+    private boolean preventToUninstallBundle = false;
+    private File directoryForPersistingTestBundles = null;
     private String baseUrl;
     private String serverCredentials;
     private String testServletPath = DEFAULT_TEST_SERVLET_PATH;
     private final Set<Class<?>> embeddedClasses = new HashSet<Class<?>>();
     private final Map<String, String> additionalBundleHeaders = new 
HashMap<String, String>();
     
+    private Logger log;
+    
     private InputStream buildTestBundle(Class<?> c, Collection<Class<?>> 
embeddedClasses, String bundleSymbolicName) throws IOException {
         final TinyBundle b = TinyBundles.bundle()
             .set(Constants.BUNDLE_SYMBOLICNAME, bundleSymbolicName)
@@ -66,6 +80,12 @@ public class ClientSideTeleporter extend
             b.set(header.getKey(), header.getValue());
         }
         
+        // enrich embedded classes by automatically detected dependencies
+        for(Class<?> embeddedClazz : dependencyAnalyzer.getDependencies(log)) {
+            log.info("Embed class '{}' because it is referenced and in the 
allowed package prefixes", embeddedClazz);
+            embeddedClasses.add(embeddedClazz);
+        }
+        
         // Embed specified classes
         for(Class<?> clz : embeddedClasses) {
             b.add(clz);
@@ -78,6 +98,7 @@ public class ClientSideTeleporter extend
                     @Override
                     public void process(String resourcePath, InputStream 
resourceStream) throws IOException {
                         b.add(resourcePath, resourceStream);
+                        log.info("Embedded resource '{}' in test bundle", 
resourcePath);
                     }
                     
                 };
@@ -165,19 +186,56 @@ public class ClientSideTeleporter extend
     public Map<String, String> getAdditionalBundleHeaders() {
         return additionalBundleHeaders;
     }
-    
+
+    public void setEnableLogging(boolean enableLogging) {
+        this.enableLogging = enableLogging;
+    }
+
+    public void setPreventToUninstallBundle(boolean 
preventToUninstallTestBundle) {
+        this.preventToUninstallBundle = preventToUninstallTestBundle;
+    }
+
+    public void setDirectoryForPersistingTestBundles(File 
directoryForPersistingTestBundles) {
+        this.directoryForPersistingTestBundles = 
directoryForPersistingTestBundles;
+    }
+
     private String installTestBundle(TeleporterHttpClient httpClient) throws 
MalformedURLException, IOException {
-        final SimpleDateFormat fmt = new SimpleDateFormat("HH-mm-ss-");
-        final String bundleSymbolicName = getClass().getSimpleName() + "." + 
fmt.format(new Date()) + "." + UUID.randomUUID();
-        final InputStream bundle = buildTestBundle(classUnderTest, 
embeddedClasses, bundleSymbolicName);
-        httpClient.installBundle(bundle, bundleSymbolicName, 
webConsoleReadyTimeoutSeconds);
+        final SimpleDateFormat fmt = new SimpleDateFormat("HH-mm-ss");
+        final String bundleSymbolicName = getClass().getSimpleName() + "." + 
classUnderTest.getSimpleName() + "." + fmt.format(new Date()) + "." + 
UUID.randomUUID();
+        log.info("Installing bundle '{}' to {}", bundleSymbolicName, baseUrl);
+        
+        try (final InputStream bundle = buildTestBundle(classUnderTest, 
embeddedClasses, bundleSymbolicName)) {
+            // optionally persist the test bundle
+            if (directoryForPersistingTestBundles != null) {
+                directoryForPersistingTestBundles.mkdirs();
+                File bundleFile = new File(directoryForPersistingTestBundles, 
bundleSymbolicName + ".jar");
+                log.info("Persisting test bundle in '{}'", bundleFile);
+                try (OutputStream output = new FileOutputStream(bundleFile)) {
+                    IOUtils.copy(bundle, output);
+                }
+                try (InputStream bundleInput = new BufferedInputStream(new 
FileInputStream(bundleFile))) {
+                    httpClient.installBundle(bundleInput, bundleSymbolicName, 
webConsoleReadyTimeoutSeconds);
+                }
+            } else {
+                httpClient.installBundle(bundle, bundleSymbolicName, 
webConsoleReadyTimeoutSeconds);
+            }
+            httpClient.verifyCorrectBundleState(bundleSymbolicName, 
webConsoleReadyTimeoutSeconds);
+        };
         return bundleSymbolicName;
     }
-    
+
+    private void initLogger() {
+        if (enableLogging) {
+            log = LoggerFactory.getLogger(ClientSideTeleporter.class);
+        } else {
+            log = NOPLogger.NOP_LOGGER;
+        }
+    }
+
     @Override
     public Statement apply(final Statement base, final Description 
description) {
         customize();
-        
+        initLogger();
         if(baseUrl == null) {
             fail("base URL is not set");
         }
@@ -189,10 +247,6 @@ public class ClientSideTeleporter extend
         if(baseUrl.endsWith("/")) {
             baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
         }
-        
-        for(Class<?> c : dependencyAnalyzer.getDependencies()) {
-            embeddedClasses.add(c);
-        }
 
         final TeleporterHttpClient httpClient = new 
TeleporterHttpClient(baseUrl, testServletPath);
         httpClient.setCredentials(serverCredentials);
@@ -204,12 +258,18 @@ public class ClientSideTeleporter extend
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
+                
                 final String bundleSymbolicName = 
installTestBundle(httpClient);
                 final String testPath = description.getClassName() + "/" + 
description.getMethodName();
                 try {
                     httpClient.runTests(testPath, testReadyTimeoutSeconds);
                 } finally {
-                    httpClient.uninstallBundle(bundleSymbolicName, 
webConsoleReadyTimeoutSeconds);
+                    if (!preventToUninstallBundle) {
+                        log.info("Uninstalling bundle '{}' from {}", 
bundleSymbolicName, baseUrl);
+                        httpClient.uninstallBundle(bundleSymbolicName, 
webConsoleReadyTimeoutSeconds);
+                    } else {
+                        log.info("Not uninstalling bundle '{}' from {} due to 
according configuration", bundleSymbolicName, baseUrl);
+                    }
                 }
             }
         };

Modified: 
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/DefaultPropertyBasedCustomizer.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/DefaultPropertyBasedCustomizer.java?rev=1784090&r1=1784089&r2=1784090&view=diff
==============================================================================
--- 
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/DefaultPropertyBasedCustomizer.java
 (original)
+++ 
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/DefaultPropertyBasedCustomizer.java
 Thu Feb 23 08:46:15 2017
@@ -18,6 +18,8 @@ package org.apache.sling.testing.telepor
 
 import static org.junit.Assert.fail;
 
+import java.io.File;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.junit.rules.TeleporterRule;
 import org.apache.sling.junit.rules.TeleporterRule.Customizer;
@@ -43,9 +45,15 @@ import org.apache.sling.junit.rules.Tele
  *      <li>{@code ClientSideTeleporter.excludeDependencyPrefixes}, 
comma-separated list of package prefixes for classes referenced from the IT. 
  *      Classes having one of the given package prefix will not be included in 
the bundle being deployed to the given Sling instance together with the IT 
class itself. 
  *      This takes precedence over the {@code 
ClientSideTeleporter.includeDependencyPrefixes}.</li>
+ *      <li>{@code ClientSideTeleporter.embedClasses}, comma-separated list of 
fully qualified class names which should be embedded in the test bundle.
+ *      Use this only for classes which are not detected automatically by the 
Maven Dependency Analyzer but still should be embedded in the test bundle</li>
  *      <li>{@code ClientSideTeleporter.testReadyTimeoutSeconds}, how long to 
wait for our test to be ready on the server-side in seconds, after installing 
the test bundle. By default {@code 12}.</li>
  *      <li>{@code ClientSideTeleporter.serverUsername}, the username with 
which to send requests to the Sling server. By default {@code admin}.</li>
  *      <li>{@code ClientSideTeleporter.serverPassword}, the password with 
which to send requests to the Sling server. By default {@code admin}.</li>
+ *      <li>{@code ClientSideTeleporter.enableLogging}, set to true to log the 
tasks being performed by the teleporter. Useful for debugging.</li>
+ *      <li>{@code ClientSideTeleporter.preventToUninstallBundle}, set to true 
to not automatically uninstall the test bundle after test execution. Useful for 
debugging.</li>
+ *      <li>{@code ClientSideTeleporter.testBundleDirectory}, if set the test 
bundles are being persisted (before being installed) within the given directory 
name. 
+ *      If the directory does not exist, it will be automatically created. 
Useful for debugging.</li>
  * </ul>
  */
 public class DefaultPropertyBasedCustomizer implements Customizer {
@@ -56,6 +64,9 @@ public class DefaultPropertyBasedCustomi
     static final String PROPERTY_SERVER_PASSWORD = 
"ClientSideTeleporter.serverPassword";
     static final String PROPERTY_SERVER_USERNAME = 
"ClientSideTeleporter.serverUsername";
     static final String PROPERTY_TESTREADY_TIMEOUT_SECONDS = 
"ClientSideTeleporter.testReadyTimeoutSeconds";
+    static final String PROPERTY_TESTBUNDLE_DIRECTORY = 
"ClientSideTeleporter.testBundleDirectory";
+    static final String PROPERTY_ENABLE_LOGGING = 
"ClientSideTeleporter.enableLogging";
+    static final String PROPERTY_PREVENT_TO_UNINSTALL_BUNDLE = 
"ClientSideTeleporter.preventToUninstallBundle";
     
     static final String LIST_SEPARATOR = ",";
     
@@ -66,6 +77,9 @@ public class DefaultPropertyBasedCustomi
     private final String excludeDependencyPrefixes;
     private final String embedClasses;
     private final String baseUrl;
+    private final String testBundleDirectory;
+    private final boolean enableLogging;
+    private final boolean preventToUninstallBundle;
 
     public DefaultPropertyBasedCustomizer() {
         testReadyTimeout = 
Integer.getInteger(PROPERTY_TESTREADY_TIMEOUT_SECONDS, 12);
@@ -75,6 +89,9 @@ public class DefaultPropertyBasedCustomi
         excludeDependencyPrefixes = 
System.getProperty(PROPERTY_EXCLUDE_DEPENDENCY_PREFIXES);
         embedClasses = System.getProperty(PROPERTY_EMBED_CLASSES);
         baseUrl = System.getProperty(PROPERTY_BASE_URL);
+        testBundleDirectory = 
System.getProperty(PROPERTY_TESTBUNDLE_DIRECTORY);
+        enableLogging = Boolean.getBoolean(PROPERTY_ENABLE_LOGGING);
+        preventToUninstallBundle = 
Boolean.getBoolean(PROPERTY_PREVENT_TO_UNINSTALL_BUNDLE);
     }
 
     @Override
@@ -83,6 +100,11 @@ public class DefaultPropertyBasedCustomi
         if (StringUtils.isBlank(baseUrl)) {
             fail("The mandatory system property " + PROPERTY_BASE_URL + " is 
not set!");
         }
+        cst.setEnableLogging(enableLogging);
+        cst.setPreventToUninstallBundle(preventToUninstallBundle);
+        if (StringUtils.isNotBlank(testBundleDirectory)) {
+            cst.setDirectoryForPersistingTestBundles(new 
File(testBundleDirectory));
+        }
         cst.setBaseUrl(baseUrl);
         cst.setServerCredentials(serverUsername, serverPassword);
         cst.setTestReadyTimeoutSeconds(testReadyTimeout);

Modified: 
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/DependencyAnalyzer.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/DependencyAnalyzer.java?rev=1784090&r1=1784089&r2=1784090&view=diff
==============================================================================
--- 
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/DependencyAnalyzer.java
 (original)
+++ 
sling/trunk/testing/junit/teleporter/src/main/java/org/apache/sling/testing/teleporter/client/DependencyAnalyzer.java
 Thu Feb 23 08:46:15 2017
@@ -23,6 +23,7 @@ import java.util.HashSet;
 import java.util.Set;
 
 import 
org.apache.maven.shared.dependency.analyzer.asm.DependencyClassFileVisitor;
+import org.slf4j.Logger;
 
 /** Find the class dependencies of a class, recursively, 
  *  using the maven-dependency-analyzer and optionally considering only
@@ -62,13 +63,13 @@ class DependencyAnalyzer {
     /** Get the aggregate dependencies of our classes, based on a recursive
      *  analysis that takes our include/exclude prefixes into account
      */
-    synchronized Collection<Class<?>> getDependencies() {
+    synchronized Collection<Class<?>> getDependencies(Logger log) {
         if(dependencies != null) {
             return dependencies;
         }
         dependencies = new HashSet<Class<?>>();
         for(Class<?> c : classes) {
-            analyze(c);
+            analyze(c, log);
         }
         for(String dep : dependencyNames) {
             dependencies.add(toClass(dep));
@@ -77,7 +78,7 @@ class DependencyAnalyzer {
     }
     
     /** Analyze a single class, recursively */
-    private void analyze(Class<?> c) {
+    private void analyze(Class<?> c, Logger log) {
         if(alreadySeen.contains(c)) {
             return;
         }
@@ -105,15 +106,15 @@ class DependencyAnalyzer {
             if(dep.equals(c.getName())) {
                 continue;
             }
-            if(accept(dep)) {
+            if(accept(dep, log)) {
                 dependencyNames.add(dep);
-                analyze(toClass(dep));
+                analyze(toClass(dep), log);
             }
         }
     }
     
     /** True if given class name matches our include/exclude prefixes */
-    private boolean accept(String className) {
+    private boolean accept(String className, Logger log) {
         boolean result = false;
         
         for(String s : includes) {
@@ -128,10 +129,16 @@ class DependencyAnalyzer {
             for(String s : excludes) {
                 if(className.startsWith(s)) {
                     result = false;
+                    log.trace("Dependent class '{}' not included because 
package blacklisted via exclude '{}'.", className, s);
                     break;
                 }
             }
         }
+        if (result) {
+            log.trace("Dependent class '{}' included because package not 
whitelisted via include.", className);
+        } else {
+            log.trace("Dependent class '{}' not included because package not 
whitelisted via include.", className);
+        }
         return result;
     }
     


Reply via email to