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

org.kaazing.k3po.junit.rules.K3poRule Maven / Gradle / Ivy

There is a newer version: 5.0.6
Show newest version
/**
 * Copyright 2007-2015, Kaazing Corporation. All rights reserved.
 *
 * Licensed 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.kaazing.k3po.junit.rules;

import static java.lang.String.format;
import static org.junit.Assert.assertTrue;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;

import org.junit.rules.Verifier;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runners.model.Statement;
import org.kaazing.k3po.junit.annotation.Specification;
import org.kaazing.net.URLFactory;

/**
 * A K3poRule specifies how a Test using k3po is executed.
 *
 */
public class K3poRule extends Verifier {

    /*
     * For some reason earlier versions of JUnit will cause tests to either hang or succeed incorrectly without ever
     * talking to the K3PO. I'm not sure why but the apply method does not seem to be called. So we need to require
     * version 4.10 (I know 4.7 has the problem ... not sure about 4.8 and 4.9 but 4.10 works).
     */
    static {
        JUnitCore core = new JUnitCore();
        String version = core.getVersion();
        String[] versionTokens = version.split("\\.");
        Integer[] versionsInt = new Integer[versionTokens.length];
        for (int i = 0; i < versionTokens.length; i++) {
            String versionToken = versionTokens[i];
            if (versionToken.contains("-")) {
                versionToken = versionToken.substring(0, versionToken.indexOf("-"));
            }
            versionsInt[i] = Integer.parseInt(versionToken);
        }
        if (versionsInt[0] < 5) {
            if (versionsInt.length == 1 || versionsInt[0] < 4 || versionsInt[1] < 10) {
                throw new AssertionError("JUnit library 4.10+ required. Found version " + version);
            }
        }
    }

    private final Latch latch;
    private String scriptRoot;
    private URL controlURL;
    private SpecificationStatement statement;

    /**
     * Allocates a new K3poRule.
     */
    public K3poRule() {
        latch = new Latch();
    }

    /**
     * Sets the ClassPath root of where to look for scripts when resolving them.
     * @param scriptRoot is a directory/package name of where to resolve scripts from.
     * @return an instance of K3poRule for convenience
     */
    public K3poRule setScriptRoot(String scriptRoot) {
        this.scriptRoot = scriptRoot;
        return this;
    }

    /**
     * Sets the URI on which to communicate to the k3po driver.
     * @param controlURI the URI on which to connect
     * @return an instance of K3poRule for convenience
     */
    public K3poRule setControlURI(URI controlURI) {
        this.controlURL = createURL(controlURI.toString());
        return this;
    }

    @Override
    public Statement apply(Statement statement, final Description description) {

        Specification specification = description.getAnnotation(Specification.class);
        String[] scripts = (specification != null) ? specification.value() : null;

        if (scripts != null) {
            // decorate with K3PO behavior only if @Specification annotation is present
            String packagePath = this.scriptRoot;
            if (packagePath == null) {
                Class testClass = description.getTestClass();
                String packageName = testClass.getPackage().getName();
                packagePath = packageName.replaceAll("\\.", "/");
            }

            List scriptNames = new LinkedList<>();
            for (String script : scripts) {
                // strict compatibility (relax to support fully qualified paths later)
                if (script.startsWith("/")) {
                    throw new IllegalArgumentException("Script path must be relative");
                }

                String scriptName = format("%s/%s", packagePath, script);
                scriptNames.add(scriptName);
            }

            URL controlURL = this.controlURL;
            if (controlURL == null) {
                // lazy dependency on TCP scheme
                controlURL = createURL("tcp://localhost:11642");
            }

            this.statement = new SpecificationStatement(statement, controlURL, scriptNames, latch);
            statement = this.statement;
        }

        return super.apply(statement, description);
    }

    /**
     * Starts the connects in the robot scripts.  The accepts are implicitly started just prior to the test logic in the
     * Specification.
     */
    public void start() {
        // script should already be prepared before annotated test can execute
        assertTrue(format("Did you call start() from outside @%s test?", Specification.class.getSimpleName()),
                latch.isPrepared());

        // notify script to start
        latch.notifyStartable();
    }

    /**
     * Blocking call to await for the K3po threads to stop executing.  If the connects have not already been initiated via the
     * start() method, they will be implicitly called.
     * @throws Exception if an error has occurred in the execution of the tests.
     */
    public void finish() throws Exception {
        assertTrue(format("Did you call finish() from outside @%s test?", Specification.class.getSimpleName()),
                !latch.isInInitState());

        // wait for script to finish
        latch.notifyStartable();

        latch.awaitFinished();
    }

    private static URL createURL(String location) {
        try {
            return URLFactory.createURL("tcp://localhost:11642");
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Wait for barrier to fire.
     * @param barrierName is the name of the barrier to await
     * @throws InterruptedException if await is interrupted
     */
    public void awaitBarrier(String barrierName) throws InterruptedException {
        statement.awaitBarrier(barrierName);
    }

    /**
     * Notify barrier to fire.
     * @param barrierName is the name for the barrier to notify
     * @throws InterruptedException if notify is interrupted (note: waits for confirm that is notified)
     */
    public void notifyBarrier(String barrierName) throws InterruptedException {
        statement.notifyBarrier(barrierName);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy