| /* |
| * 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.testing.teleporter.client; |
| |
| import static org.junit.Assert.fail; |
| |
| import java.io.File; |
| import java.io.IOException; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.sling.junit.rules.TeleporterRule; |
| import org.apache.sling.junit.rules.TeleporterRule.Customizer; |
| |
| /** |
| * This is the default {@link Customizer} which is used in case {@code TeleporterRule.forClass(Class)} was called. It relies on system |
| * properties to configure the important aspects of teleporting. <br> |
| * It assumes that there is already a running Sling server at the given baseUrl. To provision such a server the |
| * <a href="https://sling.apache.org/documentation/development/slingstart.html#slingstart-maven-plugin">slingstart-maven-plugin</a> could be |
| * used for example. <br> |
| * The following system properties must be set for this Customizer to work |
| * <ul> |
| * <li>{@code ClientSideTeleporter.baseUrl}, the server url on which Sling is already running</li> |
| * </ul> |
| * |
| * The following system properties may be set to further tweak the behavior: |
| * <ul> |
| * <li>{@code ClientSideTeleporter.includeDependencyPrefixes}, comma-separated list of package prefixes for classes referenced from the IT. |
| * Only the classes having one of the given package prefix are included in the bundle being deployed to the given Sling instance together |
| * with the IT class itself. They are only included though in case they are referenced! If this is not set, no referenced classes will be |
| * included.</li> |
| * <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.embedClassesDirectories}, comma-separated list directories containing class files 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.additionalBundleHeaders}, comma-separated list of entries in the format {@code <name>:<value>} which |
| * should be added to the test bundle as additional headers</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 { |
| static final String PROPERTY_BASE_URL = "ClientSideTeleporter.baseUrl"; |
| static final String PROPERTY_INCLUDE_DEPENDENCY_PREFIXES = "ClientSideTeleporter.includeDependencyPrefixes"; |
| static final String PROPERTY_EXCLUDE_DEPENDENCY_PREFIXES = "ClientSideTeleporter.excludeDependencyPrefixes"; |
| static final String PROPERTY_EMBED_CLASSES = "ClientSideTeleporter.embedClasses"; |
| static final String PROPERTY_EMBED_CLASSES_DIRECTORIES = "ClientSideTeleporter.embedClassesDirectories"; |
| 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 PROPERTY_ADDITIONAL_BUNDLE_HEADERS = "ClientSideTeleporter.additionalBundleHeaders"; |
| |
| static final String LIST_SEPARATOR = ","; |
| static final String NAME_VALUE_SEPARATOR = ":"; |
| |
| private final int testReadyTimeout; |
| private final String serverUsername; |
| private final String serverPassword; |
| private final String includeDependencyPrefixes; |
| private final String excludeDependencyPrefixes; |
| private final String embedClasses; |
| private final String embedClassesDirectories; |
| private final String baseUrl; |
| private final String testBundleDirectory; |
| private final boolean enableLogging; |
| private final boolean preventToUninstallBundle; |
| private final String additionalBundleHeaders; |
| |
| public DefaultPropertyBasedCustomizer() { |
| testReadyTimeout = Integer.getInteger(PROPERTY_TESTREADY_TIMEOUT_SECONDS, 12); |
| serverUsername = System.getProperty(PROPERTY_SERVER_USERNAME, "admin"); |
| serverPassword = System.getProperty(PROPERTY_SERVER_PASSWORD, "admin"); |
| includeDependencyPrefixes = System.getProperty(PROPERTY_INCLUDE_DEPENDENCY_PREFIXES); |
| excludeDependencyPrefixes = System.getProperty(PROPERTY_EXCLUDE_DEPENDENCY_PREFIXES); |
| embedClasses = System.getProperty(PROPERTY_EMBED_CLASSES); |
| embedClassesDirectories = System.getProperty(PROPERTY_EMBED_CLASSES_DIRECTORIES); |
| baseUrl = System.getProperty(PROPERTY_BASE_URL); |
| additionalBundleHeaders = System.getProperty(PROPERTY_ADDITIONAL_BUNDLE_HEADERS); |
| testBundleDirectory = System.getProperty(PROPERTY_TESTBUNDLE_DIRECTORY); |
| enableLogging = Boolean.getBoolean(PROPERTY_ENABLE_LOGGING); |
| preventToUninstallBundle = Boolean.getBoolean(PROPERTY_PREVENT_TO_UNINSTALL_BUNDLE); |
| } |
| |
| @Override |
| public void customize(TeleporterRule rule, String options) { |
| final ClientSideTeleporter cst = (ClientSideTeleporter)rule; |
| 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); |
| if (StringUtils.isNotBlank(includeDependencyPrefixes)) { |
| for (String includeDependencyPrefix : includeDependencyPrefixes.split(LIST_SEPARATOR)) { |
| if (StringUtils.isNotBlank(includeDependencyPrefix)) { |
| cst.includeDependencyPrefix(includeDependencyPrefix); |
| } |
| } |
| } |
| if (StringUtils.isNotBlank(excludeDependencyPrefixes)) { |
| for (String excludeDependencyPrefix : excludeDependencyPrefixes.split(LIST_SEPARATOR)) { |
| if (StringUtils.isNotBlank(excludeDependencyPrefix)) { |
| cst.excludeDependencyPrefix(excludeDependencyPrefix); |
| } |
| } |
| } |
| if (StringUtils.isNotBlank(embedClassesDirectories)) { |
| for (String embedClassesDirectory : embedClassesDirectories.split(LIST_SEPARATOR)) { |
| if (StringUtils.isNotBlank(embedClassesDirectory)) { |
| try { |
| cst.embedClassesDirectory(new File(embedClassesDirectory)); |
| } catch (ClassNotFoundException | IOException e) { |
| fail("Could not load class directory '" + embedClassesDirectory + "': " + e.getMessage()); |
| } |
| } |
| } |
| } |
| if (StringUtils.isNotBlank(embedClasses)) { |
| for (String embedClass : embedClasses.split(LIST_SEPARATOR)) { |
| if (StringUtils.isNotBlank(embedClass)) { |
| try { |
| Class<?> clazz = this.getClass().getClassLoader().loadClass(embedClass); |
| cst.embedClass(clazz); |
| } catch (ClassNotFoundException e) { |
| fail("Could not load class with name '" + embedClass + "': " + e.getMessage()); |
| } |
| } |
| } |
| } |
| if (StringUtils.isNotBlank(additionalBundleHeaders)) { |
| for (String additionalBundleHeader : additionalBundleHeaders.split(LIST_SEPARATOR)) { |
| if (StringUtils.isNotBlank(additionalBundleHeader)) { |
| // split up by name and value |
| int pos = additionalBundleHeader.indexOf(NAME_VALUE_SEPARATOR); |
| if (pos < 1 || pos >= additionalBundleHeader.length() -1) { |
| fail("Each entry given to property '" + PROPERTY_ADDITIONAL_BUNDLE_HEADERS + |
| "' must have exactly the format <name>:<value>, but one entry is '" + additionalBundleHeader + "'."); |
| } |
| cst.addAdditionalBundleHeader(additionalBundleHeader.substring(0, pos), additionalBundleHeader.substring(pos+1)); |
| } |
| } |
| } |
| } |
| } |