@Test
  public void shouldWaitForWorkCompleteWhereCompleteWorkThresholdIsBehind() throws Exception {
    long expectedNumberMessages = 10;
    fillRingBuffer(expectedNumberMessages);

    final StubEventProcessor[] eventProcessors = new StubEventProcessor[3];
    for (int i = 0, size = eventProcessors.length; i < size; i++) {
      eventProcessors[i] = new StubEventProcessor();
      eventProcessors[i].setSequence(expectedNumberMessages - 2);
    }

    final SequenceBarrier sequenceBarrier =
        ringBuffer.newBarrier(Util.getSequencesFor(eventProcessors));

    Runnable runnable =
        new Runnable() {
          public void run() {
            for (StubEventProcessor stubWorker : eventProcessors) {
              stubWorker.setSequence(stubWorker.getSequence().get() + 1L);
            }
          }
        };

    Thread thread = new Thread(runnable);
    thread.start();
    thread.join();

    long expectedWorkSequence = expectedNumberMessages - 1;
    long completedWorkSequence = sequenceBarrier.waitFor(expectedWorkSequence);
    assertTrue(completedWorkSequence >= expectedWorkSequence);
  }
  @Test
  public void shouldWaitForWorkCompleteWhereAllWorkersAreBlockedOnRingBuffer() throws Exception {
    long expectedNumberMessages = 10;
    fillRingBuffer(expectedNumberMessages);

    final StubEventProcessor[] workers = new StubEventProcessor[3];
    for (int i = 0, size = workers.length; i < size; i++) {
      workers[i] = new StubEventProcessor();
      workers[i].setSequence(expectedNumberMessages - 1);
    }

    final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(Util.getSequencesFor(workers));

    Runnable runnable =
        new Runnable() {
          public void run() {
            long sequence = ringBuffer.next();
            StubEvent event = ringBuffer.getPreallocated(sequence);
            event.setValue((int) sequence);
            ringBuffer.publish(sequence);

            for (StubEventProcessor stubWorker : workers) {
              stubWorker.setSequence(sequence);
            }
          }
        };

    new Thread(runnable).start();

    long expectedWorkSequence = expectedNumberMessages;
    long completedWorkSequence = sequenceBarrier.waitFor(expectedNumberMessages);
    assertTrue(completedWorkSequence >= expectedWorkSequence);
  }
  @Test
  public void shouldInterruptDuringBusySpin() throws Exception {
    final long expectedNumberMessages = 10;
    fillRingBuffer(expectedNumberMessages);

    final CountDownLatch latch = new CountDownLatch(3);
    final Sequence sequence1 = new CountDownLatchSequence(8L, latch);
    final Sequence sequence2 = new CountDownLatchSequence(8L, latch);
    final Sequence sequence3 = new CountDownLatchSequence(8L, latch);

    context.checking(
        new Expectations() {
          {
            one(eventProcessor1).getSequence();
            will(returnValue(sequence1));

            one(eventProcessor2).getSequence();
            will(returnValue(sequence2));

            one(eventProcessor3).getSequence();
            will(returnValue(sequence3));
          }
        });

    final SequenceBarrier sequenceBarrier =
        ringBuffer.newBarrier(
            Util.getSequencesFor(eventProcessor1, eventProcessor2, eventProcessor3));

    final boolean[] alerted = {false};
    Thread t =
        new Thread(
            new Runnable() {
              public void run() {
                try {
                  sequenceBarrier.waitFor(expectedNumberMessages - 1);
                } catch (AlertException e) {
                  alerted[0] = true;
                } catch (InterruptedException e) {
                  // don't care
                }
              }
            });

    t.start();
    latch.await(3, TimeUnit.SECONDS);
    sequenceBarrier.alert();
    t.join();

    assertTrue("Thread was not interrupted", alerted[0]);
  }