package com.github.triceo.splitlog; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.assertj.core.api.Assertions; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.github.triceo.splitlog.api.Follower; import com.github.triceo.splitlog.api.Message; import com.github.triceo.splitlog.conditions.AllLogWatchMessagesAcceptingCondition; public class ExpectationTest extends DefaultFollowerBaseTest { private static final int THREADS = 100; private static final int TOTAL_MESSAGES = 10; private ExecutorService es; @Before public void setUp() { this.es = Executors.newCachedThreadPool(); } @After public void tearDown() { this.es.shutdownNow(); try { this.es.awaitTermination(2, TimeUnit.SECONDS); } catch (final InterruptedException ex) { System.err.println("Executor service failed to terminate."); } } @Test public void testConcurrentExpectations() { final Map<Future<Message>, String> tasks = new HashMap<>(ExpectationTest.THREADS); final Random random = new Random(); for (int i = 0; i < ExpectationTest.THREADS; i++) { // First thread always waits for the last message, the rest is // random. final String expectedValue = "<" + ((i == 0) ? String.valueOf(ExpectationTest.TOTAL_MESSAGES - 1) : String.valueOf(random .nextInt(ExpectationTest.TOTAL_MESSAGES))) + ">"; final Follower f = this.getLogWatch().startFollowing(); final Future<Message> task = f.expect((evaluate, status, source) -> evaluate.getLines().get(0).endsWith(expectedValue)); tasks.put(task, expectedValue); } for (int i = 0; i < ExpectationTest.TOTAL_MESSAGES; i++) { LogWriter.write(this.getLogWatch().getWatchedFile(), "<" + String.valueOf(i) + ">"); } for (final Future<Message> task : tasks.keySet()) { try { final Message accepted = task.get(); Assertions.assertThat(accepted).as("Failed to accept message #" + tasks.get(task)).isNotNull(); } catch (final Exception e) { Assertions.fail("Failed to accept message #" + tasks.get(task), e); } } } @Test public void testExpectationWithAction() { final long timeout = 5000; // how long final Follower f = this.getLogWatch().startFollowing(); final long startTime = System.nanoTime(); final Future<Message> future = f.expect(AllLogWatchMessagesAcceptingCondition.INSTANCE, (message, source) -> { try { // emulates some long-running action Thread.sleep(timeout); } catch (final InterruptedException e) { throw new IllegalStateException("Failed waiting."); } }); LogWriter.write(f.getFollowed().getWatchedFile(), "test"); try { future.get(); // should not return before the long-running final long runTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime); Assertions.assertThat(runTime).isGreaterThanOrEqualTo(timeout); } catch (final Exception e) { Assertions.fail("Failed waiting for message.", e); } } }