// 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.util.timeout; import fi.jumi.actors.eventizers.Event; import fi.jumi.actors.eventizers.dynamic.*; import fi.jumi.actors.queue.*; import fi.jumi.core.util.SpyListener; import org.junit.*; import java.util.concurrent.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertNotNull; public class InitialMessageTimeoutTest { private static final long NEVER = 10 * 1000; private static final DynamicEventizer<DummyListener> EVENTIZER = new DynamicEventizer<>(DummyListener.class); @Rule public final org.junit.rules.Timeout testTimeout = new org.junit.rules.Timeout(1000); private final SpyListener<DummyListener> spy = new SpyListener<>(DummyListener.class); private final DummyListener expect = spy.getListener(); private final MessageQueue<Event<DummyListener>> target = new MessageQueue<>(); @Test public void if_the_first_event_happens_before_timeout_then_forwards_all_messages_to_the_target_listener() { MessageReceiver<Event<DummyListener>> timeoutMessages = onBar123(); InitialMessageTimeout<Event<DummyListener>> timeout = new InitialMessageTimeout<>(target, timeoutMessages, NEVER, TimeUnit.MILLISECONDS); sendTo(timeout).onFoo(1); timeout.timedOut(); sendTo(timeout).onFoo(2); sendTo(timeout).onFoo(3); expect.onFoo(1); expect.onFoo(2); expect.onFoo(3); verifyExpected(target); } @Test public void if_times_out_before_initial_message_then_sends_timeout_messages_and_drops_all_future_messages() { MessageReceiver<Event<DummyListener>> timeoutMessages = onBar123(); InitialMessageTimeout<Event<DummyListener>> timeout = new InitialMessageTimeout<>(target, timeoutMessages, NEVER, TimeUnit.MILLISECONDS); timeout.timedOut(); sendTo(timeout).onFoo(1); sendTo(timeout).onFoo(2); sendTo(timeout).onFoo(3); expect.onBar(1); expect.onBar(2); expect.onBar(3); verifyExpected(target); } @Test public void the_timeout_happens_after_the_specified_time() throws InterruptedException { MessageQueue<Event<DummyListener>> target = new MessageQueue<>(); MessageReceiver<Event<DummyListener>> timeoutMessages = onBar123(); new InitialMessageTimeout<>(target, timeoutMessages, 0, TimeUnit.MILLISECONDS); assertNotNull(target.take()); } @Test public void is_thread_safe() throws InterruptedException { final int ITERATIONS = 10; for (int i = 0; i < ITERATIONS; i++) { SpyDummyListener target = new SpyDummyListener(); MessageReceiver<Event<DummyListener>> timeoutMessages = onBar123(); InitialMessageTimeout<Event<DummyListener>> timeout = new InitialMessageTimeout<>(new EventToDynamicListener<DummyListener>(target), timeoutMessages, 0, TimeUnit.MILLISECONDS); sendTo(timeout).onFoo(1); sendTo(timeout).onFoo(2); sendTo(timeout).onFoo(3); String[] notTimedOutEvents = {"foo1", "foo2", "foo3"}; String[] timedOutEvents = {"bar1", "bar2", "bar3"}; String[] actual = {target.received.take(), target.received.take(), target.received.take()}; assertThat(actual, either(arrayContaining(notTimedOutEvents)).or(arrayContaining(timedOutEvents))); assertThat(target.received, is(empty())); } } // helpers private static MessageReceiver<Event<DummyListener>> onBar123() { MessageQueue<Event<DummyListener>> messages = new MessageQueue<>(); sendTo(messages).onBar(1); sendTo(messages).onBar(2); sendTo(messages).onBar(3); return messages; } private static DummyListener sendTo(MessageSender<Event<DummyListener>> timeout) { return EVENTIZER.newFrontend(timeout); } private void verifyExpected(MessageReceiver<Event<DummyListener>> messages) { spy.replay(); Event<DummyListener> message; while ((message = messages.poll()) != null) { message.fireOn(expect); } spy.verify(); } public interface DummyListener { void onFoo(int i); void onBar(int i); } private static class SpyDummyListener implements DummyListener { public final BlockingQueue<String> received = new ArrayBlockingQueue<>(10); @Override public void onFoo(int i) { received.add("foo" + i); } @Override public void onBar(int i) { received.add("bar" + i); } } }