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

org.kaazing.robot.junit.rules.RoboticStatement Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2014 "Kaazing Corporation," (www.kaazing.com)
 *
 * This file is part of Robot.
 *
 * Robot is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see .
 */

package org.kaazing.robot.junit.rules;

import static java.lang.String.format;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.net.URL;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

import org.junit.ComparisonFailure;
import org.junit.runners.model.Statement;

final class RoboticStatement extends Statement {

    private final Statement statement;
    private final URL controlURL;
    private final List scriptNames;
    private final RoboticLatch latch;

    RoboticStatement(Statement statement, URL controlURL, List scriptNames, RoboticLatch latch) {
        this.statement = statement;
        this.controlURL = controlURL;
        this.scriptNames = scriptNames;
        this.latch = latch;
    }

    @Override
    public void evaluate() throws Throwable {

        ScriptRunner scriptRunner = new ScriptRunner(controlURL, scriptNames, latch);
        FutureTask scriptFuture = new FutureTask(scriptRunner);

        try {
            // start the script execution
            new Thread(scriptFuture).start();

            // wait for script to be prepared (all binds ready for incoming connections from statement)
            latch.awaitPrepared();

            try {
                // note: JUnit timeout will trigger an exception
                statement.evaluate();
            } catch (Throwable cause) {
                // any exception aborts the script (including timeout)
                if (latch.hasException()) {
                    // propagate exception if the latch has an exception
                    throw cause;
                } else {
                    // It is possible that the script is finished even if we get an exception
                    // in particular a timeout may occur but the script may finish before we actually
                    // process it the timeout, send the abort and get the result back.

                    // No reason to send the abort if we are already finished.
                    // Note that there is a race in that the script may be finished before
                    // we actually send the abort. But that is ok.
                    if (!latch.isFinished()) {
                        scriptRunner.abort();
                    }

                    try {
                        // wait at most 5sec for the observed script (due to the abort case)
                        // should take less than a second for the Robot to complete
                        ScriptPair scripts = scriptFuture.get(5, SECONDS);

                        try {
                            assertEquals("Robotic behavior did not match", scripts.getExpectedScript(), scripts.getObservedScript());
                            // Throw the original exception if we are equal
                            throw cause;
                        } catch (ComparisonFailure f) {
                            // throw an exception that highlights the difference in behavior, but caused by the timeout
                            // (or
                            // original exception)
                            f.initCause(cause);
                            throw f;
                        }

                    } catch (ExecutionException ee) {
                        throw ee.getCause().initCause(cause);
                    } catch (Exception e) {
                        // Note that ComparisonFailure are not an Exception we do want those to bubble up.
                        throw cause;
                    }
                }
            }

            // note: statement MUST call join() to ensure wrapped Rule(s) do not complete early
            // and to allow Robot script to make progress
            assertTrue(format("Did you call %s.join()?", RobotRule.class.getSimpleName()), latch.isStartable());

            ScriptPair scripts = scriptFuture.get();

            assertEquals("Robotic behavior did not match expected", scripts.getExpectedScript(), scripts.getObservedScript());
        } finally {
            // clean up the task if it is still running
            scriptFuture.cancel(true);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy