package com.hubspot.blazar.queue;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jukito.JukitoRunner;
import org.jukito.UseModules;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.inject.Inject;
import com.hubspot.blazar.BlazarServiceTestBase;
import com.hubspot.blazar.BlazarServiceTestModule;
import com.hubspot.blazar.base.BuildTrigger;
import com.hubspot.blazar.base.BuildTrigger.Type;
@RunWith(JukitoRunner.class)
@UseModules({BlazarServiceTestModule.class})
public class QueueProcessorTest extends BlazarServiceTestBase {
private List<Object> received = new ArrayList<>();
@Inject
private EventBus eventBus;
@Inject
private QueueProcessor queueProcessor;
@Before
public void before() {
eventBus.register(new Object() {
@Subscribe
public void handleEvent(Object event) {
received.add(event);
}
});
}
@Test
public void itProcessesEvents() {
BuildTrigger event = new BuildTrigger(Type.PUSH, "abc");
eventBus.post(event);
waitForEvent();
assertThat(received).containsExactly(event);
}
@Test
public void itRetriesFailedEvents() {
eventBus.register(new Object() {
AtomicBoolean threw = new AtomicBoolean();
@Subscribe
public void handleEvent(Object event) {
if (threw.compareAndSet(false, true)) {
throw new RuntimeException();
}
}
});
BuildTrigger event = new BuildTrigger(Type.PUSH, "abc");
eventBus.post(event);
waitForEvent();
waitForEvent(11200, TimeUnit.MILLISECONDS);
assertThat(received).containsExactly(event, event);
}
@Test
public void itDoesntDoubleProcessItems() {
CountDownLatch latch = new CountDownLatch(1);
eventBus.register(new Object() {
AtomicBoolean slept = new AtomicBoolean();
@Subscribe
public void handleEvent(Object event) throws InterruptedException {
if (slept.compareAndSet(false, true)) {
Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
latch.countDown();
}
}
});
BuildTrigger event = new BuildTrigger(Type.PUSH, "abc");
eventBus.post(event);
Uninterruptibles.awaitUninterruptibly(latch);
Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
assertThat(received).containsExactly(event);
}
private void waitForEvent() {
waitForEvent(1200, TimeUnit.MILLISECONDS);
}
private void waitForEvent(long amount, TimeUnit unit) {
int events = received.size();
long start = System.nanoTime();
long stop = start + unit.toNanos(amount);
while (received.size() == events && System.nanoTime() < stop) {
Uninterruptibles.sleepUninterruptibly(25, TimeUnit.MILLISECONDS);
}
if (received.size() == events) {
throw new RuntimeException(new TimeoutException("No event received"));
}
}
}