/**
   * Test to make sure that after rejected notification in-flight notifications are re-transmitted
   * with a queued connection
   *
   * @throws InterruptedException
   */
  @Test(timeout = 10000)
  public void handleTransmissionErrorInQueuedConnection() throws InterruptedException {
    server = new ApnsServerStub(FixedCertificates.serverContext().getServerSocketFactory());
    final AtomicInteger sync = new AtomicInteger(138);
    final AtomicInteger numResent = new AtomicInteger();
    final AtomicInteger numSent = new AtomicInteger();
    server.waitForError.acquire();
    server.start();
    ApnsService service =
        APNS.newService()
            .withSSLContext(clientContext())
            .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
            .asQueued()
            .withDelegate(
                new ApnsDelegate() {
                  public void messageSent(ApnsNotification message, boolean resent) {
                    if (!resent) {
                      numSent.incrementAndGet();
                    }
                    sync.getAndDecrement();
                  }

                  public void messageSendFailed(ApnsNotification message, Throwable e) {
                    numSent.decrementAndGet();
                    sync.incrementAndGet();
                  }

                  public void connectionClosed(DeliveryError e, int messageIdentifier) {}

                  public void cacheLengthExceeded(int newCacheLength) {}

                  public void notificationsResent(int resendCount) {
                    numResent.set(resendCount);
                    sync.getAndAdd(resendCount);
                  }
                })
            .build();
    server.stopAt(
        eMsg3.length() * 50 + msg1.length() * 3 + eMsg2.length() * 2 + eMsg1.length() * 85);
    for (int i = 0; i < 50; ++i) {
      service.push(eMsg3);
    }
    service.push(msg1);
    service.push(eMsg2);
    service.push(eMsg1);
    service.push(msg2);
    for (int i = 0; i < 85; ++i) {
      service.push(eMsg1);
    }

    server.sendError(8, eMsg2.getIdentifier());
    server.waitForError.release();
    server.messages.acquire();

    while (sync.get() != 0) {
      Thread.yield();
    }
  }
  /**
   * Test2 to make sure that after rejected notification in-flight notifications are re-transmitted
   *
   * @throws InterruptedException
   */
  @Test(timeout = 5000)
  public void handleReTransmissionError1Good1Bad2Good() throws InterruptedException {
    server = new ApnsServerStub(FixedCertificates.serverContext().getServerSocketFactory());
    final CountDownLatch sync = new CountDownLatch(6);
    final AtomicInteger numResent = new AtomicInteger();
    final AtomicInteger numSent = new AtomicInteger();
    int EXPECTED_RESEND_COUNT = 2;
    int EXPECTED_SEND_COUNT = 3;
    server.waitForError.acquire();
    server.start();
    ApnsService service =
        APNS.newService()
            .withSSLContext(clientContext())
            .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
            .withDelegate(
                new ApnsDelegate() {
                  public void messageSent(ApnsNotification message, boolean resent) {
                    if (!resent) {
                      numSent.incrementAndGet();
                    }
                    sync.countDown();
                  }

                  public void messageSendFailed(ApnsNotification message, Throwable e) {
                    numSent.decrementAndGet();
                  }

                  public void connectionClosed(DeliveryError e, int messageIdentifier) {}

                  public void cacheLengthExceeded(int newCacheLength) {}

                  public void notificationsResent(int resendCount) {
                    numResent.set(resendCount);
                  }
                })
            .build();
    server.stopAt(msg1.length() * 3 + eMsg2.length() * 2);
    service.push(msg1);
    service.push(eMsg2);
    service.push(eMsg1);
    service.push(msg2);

    server.sendError(8, eMsg2.getIdentifier());
    server.waitForError.release();
    server.messages.acquire();

    sync.await();

    Assert.assertEquals(EXPECTED_RESEND_COUNT, numResent.get());
    Assert.assertEquals(EXPECTED_SEND_COUNT, numSent.get());
  }