/**
   * tests a series of messages being sent when append of the primary will fail succeed or fail
   * based on its twiddle state.
   *
   * @throws InterruptedException
   */
  @Test
  public void testFailOverSink() throws IOException, InterruptedException {
    MockClock mock = new MockClock(0);
    Clock.setClock(mock);

    CounterSink primary = new CounterSink("primary");
    CounterSink secondary = new CounterSink("backup");
    ExceptionTwiddleDecorator<CounterSink> twiddle =
        new ExceptionTwiddleDecorator<CounterSink>(primary);
    BackOffFailOverSink failsink =
        new BackOffFailOverSink(twiddle, secondary, 100, 10000); // 100 ms
    // initial
    // backoff,
    // 10000ms max
    // backoff
    failsink.open();

    Event e = new EventImpl("event".getBytes());
    // two successful appends to primary.
    failsink.append(e);
    failsink.append(e);
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());
    Assert.assertEquals(2, primary.getCount());
    Assert.assertEquals(0, secondary.getCount());

    mock.forward(100);
    twiddle.setAppendOk(false); // go to fail over.
    failsink.append(e); // primary fails and automatically go to 2ndary
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());
    Assert.assertEquals(1, failsink.getFails()); // one attempt on primary
    // failed.
    Assert.assertEquals(2, primary.getCount()); // same as before,
    Assert.assertEquals(1, secondary.getCount()); // message went to the
    // secondary

    mock.forward(50);
    failsink.append(e); // skip primary and just go to 2ndary
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());
    Assert.assertEquals(1, failsink.getFails()); // still only one attempt on
    // primary
    Assert.assertEquals(2, primary.getCount()); // same as before,
    Assert.assertEquals(2, secondary.getCount()); // message went to the
    // secondary

    mock.forward(50);
    failsink.append(e); // after this fails backoff is now 200
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());
    Assert.assertEquals(2, failsink.getFails()); // try primary
    Assert.assertEquals(0, primary.getCount()); // resets because primary
    // restarted
    // (and still fails)
    Assert.assertEquals(3, secondary.getCount()); // but failover to secondary

    mock.forward(200);
    failsink.append(e); // should go to 2ndary, after this fails backoff is now
    // 400
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());
    Assert.assertEquals(3, failsink.getFails());
    Assert.assertEquals(0, primary.getCount());
    Assert.assertEquals(4, secondary.getCount());

    twiddle.setAppendOk(true);
    failsink.append(e); // even through primary is ok, we are backing off
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());
    Assert.assertEquals(3, failsink.getFails());
    Assert.assertEquals(0, primary.getCount());
    Assert.assertEquals(5, secondary.getCount());

    mock.forward(400);
    failsink.append(e); // now that the backoff has expired, we retry the
    // primary and succeed
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());
    Assert.assertEquals(3, failsink.getFails());
    Assert.assertEquals(1, primary.getCount());
    Assert.assertEquals(5, secondary.getCount());

    // this should succeed, with the counts being equal in primary and
    // secondary.
    failsink.close();
  }
  /**
   * Purposely tests backoff timeout.
   *
   * @throws InterruptedException
   */
  @Test
  public void testFailTimeout() throws IOException, InterruptedException {
    System.out.println("===========================");
    MockClock mock = new MockClock(0);
    Clock.setClock(mock);

    CounterSink primary = new CounterSink("primary");
    CounterSink secondary = new CounterSink("backup");
    ExceptionTwiddleDecorator<CounterSink> twiddle =
        new ExceptionTwiddleDecorator<CounterSink>(primary);
    BackOffFailOverSink failsink = new BackOffFailOverSink(twiddle, secondary, 100, 1000); // 100 ms
    // initial
    // backoff,
    // 10000ms max
    // backoff
    failsink.open();

    Event e = new EventImpl("event".getBytes());

    mock.forward(100);
    twiddle.setAppendOk(false); // go to fail over.
    failsink.append(e);
    failsink.append(e);
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());

    mock.forward(100);
    failsink.append(e);
    failsink.append(e);
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());

    mock.forward(200);
    failsink.append(e);
    failsink.append(e);
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());

    mock.forward(400);
    failsink.append(e);
    failsink.append(e);
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());
    Assert.assertEquals(4, failsink.getFails());
    Assert.assertEquals(0, primary.getCount());
    Assert.assertEquals(8, secondary.getCount());

    mock.forward(800);
    failsink.append(e);
    failsink.append(e);
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());
    Assert.assertEquals(5, failsink.getFails());
    Assert.assertEquals(0, primary.getCount());
    Assert.assertEquals(10, secondary.getCount());

    // without capping there would be no new fail here bug still the
    // twelve on the secondary count.
    mock.forward(1000);
    failsink.append(e);
    failsink.append(e);
    System.out.println(mock);
    System.out.printf(
        "pri: %4d sec: %4d fail: %4d\n",
        primary.getCount(), secondary.getCount(), failsink.getFails());
    Assert.assertEquals(6, failsink.getFails());
    Assert.assertEquals(0, primary.getCount());
    Assert.assertEquals(12, secondary.getCount());
  }