All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sling.junit.rules.TeleporterRule Maven / Gradle / Ivy

/*
 * 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.rules;

import java.util.ArrayList;
import java.util.List;

import org.apache.sling.junit.Activator;
import org.junit.rules.ExternalResource;

/** JUnit Rule used to teleport a server-side test to a Sling instance
 *  to execute it there. See the launchpad/integration-tests module for
 *  usage examples (coming soon). 
 *  A concrete TeleporterRule class is selected to match the different required 
 *  behaviors of the server-side and client-side variants of this rule.
 *  The junit.core module only contains the server-side code, to minimize
 *  its dependencies, and the client-side part is in the sling testing.teleporter
 *  module.  
 */
public abstract class TeleporterRule extends ExternalResource {
    protected Class classUnderTest;

    /** Name of the implementation class to use when running on the client side */ 
    public static final String CLIENT_CLASS = "org.apache.sling.testing.teleporter.client.ClientSideTeleporter";
    
    /** Class name pattern for Customizers */ 
    public static final String CUSTOMIZER_PATTERN = "org.apache.sling.junit.teleporter.customizers.Customizer";
    
    private static final String DEFAULT_CUSTOMIZER_CLASS = "org.apache.sling.testing.teleporter.client.DefaultPropertyBasedCustomizer";
    
    /** Customizer is used client-side to setup the server URL and other parameters */
    public static interface Customizer {
        void customize(TeleporterRule t, String options);
    }
    private String clientSetupOptions;
    protected List embeddedResourcePaths = new ArrayList();

    /** Meant to be instantiated via {@link #forClass} */
    protected TeleporterRule() {
    }
    
    protected void setClassUnderTest(Class c) {
        this.classUnderTest = c;
    }

    /** True if running on the server-side. */
    public static boolean isServerSide() {
        return Activator.getBundleContext() != null;
    }
    
    /** Build a TeleporterRule for the given class, with no client setup options */
    public static TeleporterRule forClass(Class  classUnderTest) {
        return forClass(classUnderTest, null);
    }
    
    /** Build a TeleporterRule for the given class, with optional clientSetupOptions.
     * 
     *  @param clientSetupOptions If supplied, the part of that string before the first colon
     *  is used as the class name of a Customizer (or shorthand for that if it contains no dots). 
     *  The rest of the string is then passed to the Customizer so that it can be used to define 
     *  options (which server to run the test on, etc) 
     */
    public static TeleporterRule forClass(Class  classUnderTest, String clientSetupOptions) {
        TeleporterRule result = null;
        
        if(isServerSide()) {
            result = new ServerSideTeleporter(classUnderTest);
        } else {
            // Client-side. Instantiate the class dynamically to 
            // avoid bringing its dependencies into this module when
            // it's running on the server side
            try {
                result = createInstance(TeleporterRule.class, CLIENT_CLASS);
            } catch(Exception e) {
                throw new RuntimeException("Unable to instantiate Teleporter client " + CLIENT_CLASS, e);
            }
        }
        
        result.clientSetupOptions = clientSetupOptions;
        result.setClassUnderTest(classUnderTest);
        return result;
    }

    /** Use a Customizer, if one was defined, to customize this Rule */
    protected void customize() {
        // As with the client-side rule implementation, instantiate our Customizer
        // dynamically to avoid requiring its class on the server side.
        if(!isServerSide()) {
            if((clientSetupOptions != null) && !clientSetupOptions.isEmpty()) {
                String customizerClassName = clientSetupOptions;
                String customizerOptions = "";
                final int firstColon = clientSetupOptions.indexOf(":");
                if(firstColon > 0) {
                    customizerClassName = clientSetupOptions.substring(0, firstColon);
                    customizerOptions = clientSetupOptions.substring(firstColon + 1);
                }
                // If a short name is used, transform it using our pattern.
                // Simplifies referring to these customizers in test code,
                // without having to make the customizer classes accessible to this bundle
                if(!customizerClassName.contains(".")) {
                    customizerClassName = CUSTOMIZER_PATTERN.replace("", customizerClassName);
                }
                createInstance(Customizer.class, customizerClassName).customize(this, customizerOptions);
            } else {
                // use default customizer which is based on system properties
                createInstance(Customizer.class, DEFAULT_CUSTOMIZER_CLASS).customize(this, null);
            }
        }
    }
    
    @SuppressWarnings("unchecked")
    protected static  T createInstance(Class objectClass, String className) {
        try {
            return (T)(TeleporterRule.class.getClassLoader().loadClass(className).newInstance());
        } catch(Exception e) {
            throw new RuntimeException("Unable to instantiate " + className, e);
        }
    }
    
    /** If running on the server side, get an OSGi service */
    public final  T getService (Class serviceClass) {
        return getService(serviceClass, null);
    }
    
    /** If running on the server side, get an OSGi service specified by an LDAP service filter */
    public  T getService (Class serviceClass, String ldapFilter) {
        throw new UnsupportedOperationException("This TeleporterRule does not implement getService()");
    }
    
    /** Tell the concrete teleporter to embed resources, based on their path, in
     *  the test bundle. 
     *  @param paths 0..N resource paths to add to the current rule. A path that 
     *      ends with a / causes all resources found under it
     *      to be recursively embedded as well.
     */
    public TeleporterRule withResources(String ...paths) {
        for(String path : paths) {
            embeddedResourcePaths.add(path);
        }
        return this;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy