@Test
  public void testListenerErrorCanRestartReplication()
      throws URISyntaxException, InterruptedException {
    Listener listener = new Listener();

    URI uri = new URI("http://127.0.0.1:5984/db1");
    DatastoreExtended mockDatastore = mock(DatastoreExtended.class);
    ReplicationStrategy mockStrategy = mock(ReplicationStrategy.class);
    when(mockStrategy.isReplicationTerminated()).thenReturn(true);
    when(mockStrategy.getEventBus()).thenReturn(new EventBus());

    PullReplication pull = createPullReplication(uri, mockDatastore);
    TestReplicator replicator = new TestReplicator(pull, mockStrategy);
    replicator.getEventBus().register(listener);
    replicator.start();

    // Waits for callbacks to be run
    replicator.error(
        new ReplicationStrategyErrored(
            mockStrategy, new ErrorInfo(new RuntimeException("Mocked error"))));

    Assert.assertTrue(listener.run);
    Assert.assertFalse(listener.errorThrown);

    // Don't leave threads about the place
    replicator.complete(new ReplicationStrategyCompleted(mockStrategy));
  }
  @Test(expected = IllegalStateException.class)
  public void start_startWhenStopping_exception() throws Exception {
    startAndVerify();

    replicator.stop();
    Assert.assertEquals(Replicator.State.STOPPING, replicator.getState());
    replicator.start(); // can not restart until full stopped
  }
  @Test
  public void complete_woListener_nothing() {
    // don't subscribe to the eventbus
    replicator.start();
    replicator.complete(new ReplicationStrategyCompleted(mockStrategy));

    verify(mockListener, never()).complete(any(ReplicationCompleted.class));
    verify(mockListener, never()).error(any(ReplicationErrored.class));
  }
  @Test
  public void start_errorThenRestarted() throws Exception {
    startAndVerify();

    replicator.stop();
    Assert.assertEquals(Replicator.State.STOPPING, replicator.getState());

    ErrorInfo err = new ErrorInfo(new RuntimeException("Mocked error"));
    ReplicationStrategyErrored rse = new ReplicationStrategyErrored(mockStrategy, err);
    ReplicationErrored re = new ReplicationErrored(replicator, err);
    replicator.error(rse);
    Assert.assertEquals(Replicator.State.ERROR, replicator.getState());
    verify(mockListener).error(re);
    verify(mockListener, never()).complete(any(ReplicationCompleted.class));

    doAnswer(
            new Answer() {
              @Override
              public Object answer(InvocationOnMock invocation) throws Throwable {
                Thread.sleep(1000); // sleep for a second, will give enough time to check state
                return null;
              }
            })
        .when(mockStrategy)
        .run();
    replicator.start();
    Assert.assertEquals(Replicator.State.STARTED, replicator.getState());
    Assert.assertTrue(replicator.strategyThread().isAlive());
    replicator.await();
    Assert.assertFalse(replicator.strategyThread().isAlive());
    verify(mockStrategy, times(2)).run();
  }
  @Test
  public void error_woListener_nothing() {
    // don't subscribe to the eventbus
    replicator.start();
    replicator.error(
        new ReplicationStrategyErrored(
            mockStrategy, new ErrorInfo(new RuntimeException("Mocked error"))));

    verify(mockListener, never()).complete(any(ReplicationCompleted.class));
    verify(mockListener, never()).error(any(ReplicationErrored.class));
  }
  @Test
  public void startAndThenComplete_completeState() throws Exception {
    startAndVerify();

    ReplicationStrategyCompleted rsc = new ReplicationStrategyCompleted(mockStrategy);
    ReplicationCompleted rc = new ReplicationCompleted(replicator, 0, 0);

    replicator.complete(rsc);

    verify(mockListener).complete(rc);
    verify(mockListener, never()).error(any(ReplicationErrored.class));

    Assert.assertEquals(Replicator.State.COMPLETE, replicator.getState());
    Assert.assertFalse(replicator.strategyThread().isAlive());
  }
  @Test
  public void startAndThenError_errorState() throws Exception {
    startAndVerify();

    ErrorInfo err = new ErrorInfo(new RuntimeException("Mocked error"));
    ReplicationStrategyErrored rse = new ReplicationStrategyErrored(mockStrategy, err);
    ReplicationErrored re = new ReplicationErrored(replicator, err);

    replicator.error(rse);

    verify(mockListener).error(re);
    verify(mockListener, never()).complete(any(ReplicationCompleted.class));

    Assert.assertEquals(Replicator.State.ERROR, replicator.getState());
    Assert.assertFalse(replicator.strategyThread().isAlive());
  }
  @Test
  public void startAgainBeforeComplete_nothing() throws Exception {
    startAndVerify();
    replicator.start();

    verify(mockStrategy).run();
  }
  @Test
  public void complete_exceptionInCompleteCallback_exceptionShouldCorruptAnything()
      throws Exception {
    startAndVerify();

    ReplicationStrategyCompleted rsc = new ReplicationStrategyCompleted(mockStrategy);
    ReplicationCompleted rc = new ReplicationCompleted(replicator, 0, 0);

    doThrow(new RuntimeException("Mocked error")).when(mockListener).complete(rc);

    replicator.complete(rsc);

    verify(mockListener).complete(rc);
    verify(mockListener, never()).error(any(ReplicationErrored.class));

    Assert.assertEquals(Replicator.State.COMPLETE, replicator.getState());
    Assert.assertFalse(replicator.strategyThread().isAlive());
  }
  private void startAndVerify() throws Exception {
    Assert.assertEquals(Replicator.State.PENDING, replicator.getState());
    Assert.assertNull(replicator.strategyThread());

    replicator.getEventBus().register(mockListener);
    replicator.start();

    Assert.assertNotNull(replicator.strategyThread());
    Assert.assertEquals(Replicator.State.STARTED, replicator.getState());

    // Make sure the strategy returned before move on, other wise
    // the mock strategy might not be called when you try to verify
    replicator.await();
    Assert.assertFalse(replicator.strategyThread().isAlive());

    verify(mockStrategy).run();

    // No interaction to listener yet
    verifyZeroInteractions(mockListener);
  }
 @Test
 public void start_woListener_nothing() {
   // don't subscribe to the eventbus
   replicator.start();
 }
 @Test
 public void constructor() throws Exception {
   Assert.assertEquals(Replicator.State.PENDING, replicator.getState());
   Assert.assertNull(replicator.strategyThread());
 }
 @Test
 public void stopBeforeStart_stopped() throws Exception {
   replicator.stop();
   Assert.assertEquals(Replicator.State.STOPPED, replicator.getState());
   verify(mockStrategy, never()).run();
 }