@Test
  public void testListenerCompleteCanRestartReplication()
      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
    ReplicationStrategyCompleted rsc = new ReplicationStrategyCompleted(mockStrategy);
    replicator.complete(rsc);

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

    // Don't leave threads about the place
    replicator.complete(rsc);
  }
  @Test
  public void start_stoppedThenRestarted() throws Exception {
    startAndVerify();

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

    ReplicationStrategyCompleted rsc = new ReplicationStrategyCompleted(mockStrategy);
    ReplicationCompleted rc = new ReplicationCompleted(replicator, 0, 0);
    replicator.complete(rsc);
    Assert.assertEquals(Replicator.State.STOPPED, replicator.getState());
    verify(mockListener).complete(rc);
    verify(mockListener, never()).error(any(ReplicationErrored.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 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 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 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());
  }