// Copyright © 2011-2014, Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0
package fi.jumi.launcher.remote;
import fi.jumi.actors.ActorRef;
import fi.jumi.actors.eventizers.Event;
import fi.jumi.actors.queue.*;
import fi.jumi.core.api.*;
import fi.jumi.core.config.*;
import fi.jumi.core.events.RequestListenerEventizer;
import fi.jumi.core.events.suiteListener.*;
import fi.jumi.core.ipc.api.RequestListener;
import fi.jumi.core.util.SpyListener;
import fi.jumi.launcher.FakeActorThread;
import org.junit.*;
import org.junit.rules.ExpectedException;
import java.nio.file.Paths;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.*;
public class RemoteSuiteLauncherTest {
@Rule
public final ExpectedException thrown = ExpectedException.none();
private final RequestListener daemon = mock(RequestListener.class);
private final MessageSender<Event<RequestListener>> senderToDaemon = new RequestListenerEventizer().newBackend(daemon);
private final SpyDaemonSummoner daemonSummoner = new SpyDaemonSummoner();
private final SuiteConfiguration dummySuiteConfig = new SuiteConfiguration();
private final DaemonConfiguration dummyDaemonConfig = new DaemonConfiguration();
private final RemoteSuiteLauncher suiteLauncher =
new RemoteSuiteLauncher(new FakeActorThread(), ActorRef.<DaemonSummoner>wrap(daemonSummoner));
private final MessageQueue<Event<SuiteListener>> suiteListener = new MessageQueue<>();
@Test
public void sends_RunTests_command_to_the_daemon_when_it_connects() {
SuiteConfiguration config = new SuiteConfigurationBuilder()
.addToClasspath(Paths.get("dependency.jar"))
.setTestClasses("FooTest")
.freeze();
suiteLauncher.runTests(config, dummyDaemonConfig, suiteListener);
callback().tell().onConnected(null, senderToDaemon);
verify(daemon).runTests(config);
}
@Test
@SuppressWarnings("unchecked")
public void forwards_messages_from_daemon_to_the_SuiteListener() {
Event<SuiteListener> expectedEvent = mock(Event.class);
suiteLauncher.runTests(dummySuiteConfig, dummyDaemonConfig, suiteListener);
callback().tell().onConnected(null, senderToDaemon);
callback().tell().onMessage(expectedEvent);
assertThat(suiteListener.poll(), is(expectedEvent));
}
@Test
public void can_send_shutdown_command_to_the_daemon() {
suiteLauncher.runTests(dummySuiteConfig, dummyDaemonConfig, suiteListener);
callback().tell().onConnected(null, senderToDaemon);
suiteLauncher.shutdownDaemon();
verify(daemon).shutdown();
}
@Test
public void shutdown_command_fails_if_the_daemon_is_not_connected() {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("daemon not connected");
suiteLauncher.shutdownDaemon();
}
// reporting a daemon which dies unexpectedly
@Test
public void reports_an_internal_error_if_the_daemon_disconnects_between_onSuiteStarted_and_onSuiteFinished() {
SpyListener<SuiteListener> spy = new SpyListener<>(SuiteListener.class);
SuiteListener expect = spy.getListener();
expect.onSuiteStarted();
expect.onInternalError("The test runner daemon process disconnected or died unexpectedly", StackTrace.from(new Exception("disconnected")));
expect.onSuiteFinished();
spy.replay();
suiteLauncher.runTests(dummySuiteConfig, dummyDaemonConfig, new EventToSuiteListener(expect));
callback().tell().onConnected(null, senderToDaemon);
callback().tell().onMessage(new OnSuiteStartedEvent()); // suite is in progress
callback().tell().onDisconnected(); // daemon dies, network connection is disconnection
spy.verify();
}
@Test
public void does_not_report_any_errors_if_daemon_disconnects_before_onSuiteStarted() {
SpyListener<SuiteListener> spy = new SpyListener<>(SuiteListener.class);
SuiteListener expect = spy.getListener();
// expect no events; another component will report whether starting the daemon failed
spy.replay();
suiteLauncher.runTests(dummySuiteConfig, dummyDaemonConfig, new EventToSuiteListener(expect));
callback().tell().onConnected(null, senderToDaemon);
callback().tell().onDisconnected();
spy.verify();
}
@Test
public void does_not_report_any_errors_if_daemon_disconnects_after_onSuiteFinished() {
SpyListener<SuiteListener> spy = new SpyListener<>(SuiteListener.class);
SuiteListener expect = spy.getListener();
expect.onSuiteStarted();
expect.onSuiteFinished();
spy.replay();
suiteLauncher.runTests(dummySuiteConfig, dummyDaemonConfig, new EventToSuiteListener(expect));
callback().tell().onConnected(null, senderToDaemon);
callback().tell().onMessage(new OnSuiteStartedEvent());
callback().tell().onMessage(new OnSuiteFinishedEvent());
callback().tell().onDisconnected();
spy.verify();
}
// helpers
private ActorRef<DaemonListener> callback() {
return daemonSummoner.lastListener;
}
private static class SpyDaemonSummoner implements DaemonSummoner {
public ActorRef<DaemonListener> lastListener;
@Override
public void connectToDaemon(SuiteConfiguration suiteConfiguration,
DaemonConfiguration daemonConfiguration,
ActorRef<DaemonListener> listener) {
lastListener = listener;
}
}
}