// Copyright © 2011-2013, 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.core.runs; import fi.jumi.actors.ActorRef; import fi.jumi.api.drivers.*; import fi.jumi.core.api.RunId; import fi.jumi.core.stdout.OutputCapturer; import org.junit.Test; import java.util.*; import java.util.concurrent.*; import static org.mockito.Mockito.*; public class AssigningRunIdsTest { private static final RunId FIRST_RUN_ID = new RunId(RunId.FIRST_ID); private static final RunId ANOTHER_RUN_ID = new RunId(RunId.FIRST_ID + 1); private final RunListener listener = mock(RunListener.class); private final RunIdSequence runIdSequence = new RunIdSequence(); private final OutputCapturer outputCapturer = new OutputCapturer(); private final SuiteNotifier notifier = new ThreadBoundSuiteNotifier(ActorRef.wrap(listener), runIdSequence, outputCapturer); @Test public void RunId_is_assigned_when_a_test_is_started() { notifier.fireTestStarted(TestId.ROOT); verify(listener).onTestStarted(FIRST_RUN_ID, TestId.ROOT); } @Test public void nested_tests_get_the_same_RunId() { notifier.fireTestStarted(TestId.ROOT); notifier.fireTestStarted(TestId.of(0)); verify(listener).onTestStarted(FIRST_RUN_ID, TestId.of(0)); } @Test public void siblings_of_nested_tests_get_the_same_RunId() { notifier.fireTestStarted(TestId.ROOT); notifier.fireTestStarted(TestId.of(0)) .fireTestFinished(); notifier.fireTestStarted(TestId.of(1)); verify(listener).onTestStarted(FIRST_RUN_ID, TestId.of(1)); } @Test public void nested_tests_in_child_threads_get_the_same_RunId() throws Exception { notifier.fireTestStarted(TestId.ROOT); execute(() -> { notifier.fireTestStarted(TestId.of(0)); }); verify(listener).onTestStarted(FIRST_RUN_ID, TestId.of(0)); } @Test public void new_runs_get_a_different_RunId() { notifier.fireTestStarted(TestId.ROOT) .fireTestFinished(); notifier.fireTestStarted(TestId.of(0)); verify(listener).onTestStarted(ANOTHER_RUN_ID, TestId.of(0)); } @Test public void concurrent_runs_in_other_threads_get_a_different_RunId() throws Exception { CyclicBarrier barrier = new CyclicBarrier(2); Runnable test1 = () -> { TestNotifier tn1 = notifier.fireTestStarted(TestId.of(1)); syncOn(barrier); // test 1 is be started first syncOn(barrier); // test 1 will be running when test 2 starts tn1.fireTestFinished(); }; Runnable test2 = () -> { syncOn(barrier); TestNotifier tn2 = notifier.fireTestStarted(TestId.of(2)); syncOn(barrier); tn2.fireTestFinished(); }; execute(test1, test2); verify(listener).onTestStarted(FIRST_RUN_ID, TestId.of(1)); verify(listener).onTestStarted(ANOTHER_RUN_ID, TestId.of(2)); } private void syncOn(CyclicBarrier sync) { try { sync.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (BrokenBarrierException e) { throw new RuntimeException(e); } } private static void execute(Runnable... tasks) throws Exception { List<Future<?>> futures = new ArrayList<>(); ExecutorService executor = Executors.newCachedThreadPool(); try { for (Runnable task : tasks) { futures.add(executor.submit(task)); } for (Future<?> future : futures) { future.get(1000, TimeUnit.MILLISECONDS); } } finally { executor.shutdownNow(); } } }