// makes sure that when a listener is register, we don't see any messages being published before
  // it got registered. We'll only see the messages after it got registered.
  @Test
  public void testAlwaysStartAfterTail() {
    topic.publish("1");
    topic.publish("2");
    topic.publish("3");

    spawn(
        new Runnable() {
          @Override
          public void run() {
            sleepSeconds(5);
            topic.publish("4");
            topic.publish("5");
            topic.publish("6");
          }
        });

    final ReliableMessageListenerMock listener = new ReliableMessageListenerMock();
    topic.addMessageListener(listener);

    assertTrueEventually(
        new AssertTask() {
          @Override
          public void run() throws Exception {
            assertEquals(asList("4", "5", "6"), Arrays.asList(listener.objects.toArray()));
          }
        });
  }
  @Test
  public void testMessageFieldSetCorrectly() {
    final ReliableMessageListenerMock listener = new ReliableMessageListenerMock();
    topic.addMessageListener(listener);

    final long beforePublishTime = Clock.currentTimeMillis();
    topic.publish("foo");
    final long afterPublishTime = Clock.currentTimeMillis();

    assertTrueEventually(
        new AssertTask() {
          @Override
          public void run() throws Exception {
            assertEquals(1, listener.messages.size());
            Message<String> message = listener.messages.get(0);

            assertEquals("foo", message.getMessageObject());
            Member localMember = local.getCluster().getLocalMember();
            assertEquals(localMember, message.getPublishingMember());

            long actualPublishTime = message.getPublishTime();
            assertTrue(actualPublishTime >= beforePublishTime);
            assertTrue(actualPublishTime <= afterPublishTime);
          }
        });
  }
  @Test
  public void publishNull() throws InterruptedException {
    final ReliableMessageListenerMock listener = new ReliableMessageListenerMock();
    topic.addMessageListener(listener);
    topic.publish(null);

    assertTrueEventually(
        new AssertTask() {
          @Override
          public void run() throws Exception {
            assertContains(listener.objects, null);
          }
        });
  }
  @Test
  public void publishSingle() throws InterruptedException {
    final ReliableMessageListenerMock listener = new ReliableMessageListenerMock();
    topic.addMessageListener(listener);
    final String msg = "foobar";
    topic.publish(msg);

    assertTrueEventually(
        new AssertTask() {
          @Override
          public void run() throws Exception {
            assertContains(listener.objects, msg);
          }
        });
  }
  @Test
  public void removeMessageListener_whenExisting() {
    final ReliableMessageListenerMock listener = new ReliableMessageListenerMock();
    String id = topic.addMessageListener(listener);

    boolean removed = topic.removeMessageListener(id);
    assertTrue(removed);
    topic.publish("1");

    // it should not receive any events
    assertTrueDelayed5sec(
        new AssertTask() {
          @Override
          public void run() throws Exception {
            assertEquals(0, listener.objects.size());
          }
        });
  }
  @Test
  public void statistics() {
    final ReliableMessageListenerMock listener = new ReliableMessageListenerMock();

    topic.addMessageListener(listener);

    final int messageCount = 10;
    final LocalTopicStats localTopicStats = topic.getLocalTopicStats();
    for (int k = 0; k < messageCount; k++) {
      topic.publish("foo");
    }

    assertEquals(messageCount, localTopicStats.getPublishOperationCount());
    assertTrueEventually(
        new AssertTask() {
          @Override
          public void run() throws Exception {
            assertEquals(messageCount, localTopicStats.getReceiveOperationCount());
          }
        });
  }
  @Test
  public void publishMultiple() throws InterruptedException {
    final ReliableMessageListenerMock listener = new ReliableMessageListenerMock();
    topic.addMessageListener(listener);

    final List<String> items = new ArrayList<String>();
    for (int k = 0; k < 5; k++) {
      items.add("" + k);
    }

    for (String item : items) {
      topic.publish(item);
    }

    assertTrueEventually(
        new AssertTask() {
          @Override
          public void run() throws Exception {
            assertEquals(items, Arrays.asList(listener.objects.toArray()));
          }
        });
  }
  @Test
  public void removeMessageListener_whenNonExisting() {
    boolean result = topic.removeMessageListener(UUID.randomUUID().toString());

    assertFalse(result);
  }
 @Test(expected = NullPointerException.class)
 public void removeMessageListener_whenNull() {
   topic.removeMessageListener(null);
 }
  @Test
  public void addMessageListener() {
    String id = topic.addMessageListener(new ReliableMessageListenerMock());

    assertNotNull(id);
  }