package uk.co.acuminous.julez.runner;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static uk.co.acuminous.julez.util.JulezSugar.SCENARIOS;
import static uk.co.acuminous.julez.util.JulezSugar.THREADS;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
import uk.co.acuminous.julez.event.Event;
import uk.co.acuminous.julez.scenario.BaseScenario;
import uk.co.acuminous.julez.scenario.Scenario;
import uk.co.acuminous.julez.scenario.ScenarioEvent;
import uk.co.acuminous.julez.scenario.ScenarioSource;
import uk.co.acuminous.julez.scenario.limiter.SizeLimiter;
import uk.co.acuminous.julez.scenario.source.ScenarioHopper;
import uk.co.acuminous.julez.scenario.source.ScenarioRepeater;
import uk.co.acuminous.julez.test.NoOpScenario;
import uk.co.acuminous.julez.test.SleepingScenario;
import uk.co.acuminous.julez.test.TestEventRepository;
public class ConcurrentScenarioRunnerTest {
private TestEventRepository repository;
@Before
public void init() {
repository = new TestEventRepository();
}
@Test
public void runsScenarios() {
Scenario scenario = new NoOpScenario().register(repository);
ScenarioSource scenarios = new SizeLimiter().limit(new ScenarioRepeater(scenario)).to(10, SCENARIOS);
new ConcurrentScenarioRunner().queue(scenarios).go();
assertEquals(10, repository.count(Event.TYPE, ScenarioEvent.BEGIN));
assertEquals(10, repository.count(Event.TYPE, ScenarioEvent.END));
}
@Test
public void doesntBeginNewScenariosAfterRunTimeIsExceeded() {
Scenario scenario = new SleepingScenario(700, MILLISECONDS).register(repository);
ScenarioSource scenarios = new SizeLimiter().limit(new ScenarioRepeater(scenario)).to(10, SCENARIOS);
new ConcurrentScenarioRunner().queue(scenarios).runFor(2, SECONDS).go();
assertEquals(3, repository.count(Event.TYPE, ScenarioEvent.BEGIN));
}
@Test
public void interuptsInFlightScenariosWhenRunTimeIsExceeded() {
Scenario scenario = new SleepingScenario(700, MILLISECONDS).register(repository);
ScenarioSource scenarios = new ScenarioRepeater(scenario);
new ConcurrentScenarioRunner().queue(scenarios).runFor(1, SECONDS).go();
assertEquals(1, repository.count(Event.TYPE, ScenarioEvent.ERROR));
}
@Test
public void defersStartUntilAGivenTime() {
long desiredStartTime = new DateTime().plusMillis(500).getMillis();
Scenario scenario = new NoOpScenario().register(repository);
ScenarioSource scenarios = new ScenarioHopper(scenario);
new ConcurrentScenarioRunner().queue(scenarios).waitUntil(desiredStartTime).go();
assertTrue("Runner did not defer start", repository.first().getTimestamp() >= desiredStartTime);
assertTrue("Runner deferred start by too long", repository.first().getTimestamp() < desiredStartTime + 200);
}
@Test
public void considersDeferredStartWhenDeterminingWhetherTheGivenRunTimeExceeded() {
long desiredStartTime = new DateTime().plusMillis(500).getMillis();
Scenario scenario = new SleepingScenario(700, MILLISECONDS).register(repository);
ScenarioSource scenarios = new SizeLimiter().limit(new ScenarioRepeater(scenario)).to(10, SCENARIOS);
new ConcurrentScenarioRunner().queue(scenarios).waitUntil(desiredStartTime).runFor(2, SECONDS).go();
assertEquals(3, repository.count(Event.TYPE, ScenarioEvent.BEGIN));
}
@Test
public void raisesBeginEvent() {
ScenarioSource scenarios = new SizeLimiter().limit(new ScenarioRepeater(new NoOpScenario())).to(10, SCENARIOS);
new ConcurrentScenarioRunner().register(repository).queue(scenarios).go();
assertEquals(ScenarioRunnerEvent.BEGIN, repository.first().getType());
}
@Test
public void raisesBeginEventOnOrAfterDeferedStart() {
long desiredStartTime = new DateTime().plusSeconds(1).getMillis();
Scenario scenario = new NoOpScenario().register(repository);
ScenarioSource scenarios = new ScenarioHopper(scenario);
new ConcurrentScenarioRunner().register(repository).queue(scenarios).waitUntil(desiredStartTime).go();
assertTrue(repository.first().getTimestamp() >= desiredStartTime);
}
@Test
public void raisesEndEvent() {
ScenarioSource scenarios = new SizeLimiter().limit(new ScenarioRepeater(new NoOpScenario())).to(10, SCENARIOS);
new ConcurrentScenarioRunner().register(repository).queue(scenarios).go();
assertEquals(ScenarioRunnerEvent.END, repository.last().getType());
}
@Test
public void canBeConfiguredForMultipleThreads() {
ThreadCountingScenario scenario = new ThreadCountingScenario();
ScenarioSource scenarios = new SizeLimiter().limit(new ScenarioRepeater(scenario)).to(1000, SCENARIOS);
new ConcurrentScenarioRunner().queue(scenarios).allocate(10, THREADS).go();
assertEquals(10, scenario.count());
}
class ThreadCountingScenario extends BaseScenario {
private Set<Thread> threads = Collections.synchronizedSet(new HashSet<Thread>());
@Override
public void run() {
handler.onEvent(eventFactory.begin());
threads.add(Thread.currentThread());
handler.onEvent(eventFactory.end());
}
public int count() {
return threads.size();
}
}
}