@Test
  public void keepAliveSubscriberWhoHasSubscriptions() {

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .subscribe(with(subscriber), with(event.TYPE), with(any(AsyncCallback.class)));
            will(asyncAction);
          }
        });

    pushChannel.subscribe(event.TYPE, subscribeCallback);
    asyncAction.onSuccess(null);

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .keepAlive(with(subscriber), with(any(AsyncCallback.class)));
          }
        });

    pushChannel.onTime();
  }
  @Test
  public void reopenChannelWhenTokenExpires() {

    final AsyncAction<String> asyncAction = new AsyncAction<String>();

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .connect(with(subscriber), with(any(AsyncCallback.class)));
            will(asyncAction);

            oneOf(channel).open(with("channelToken"), with(channelListener));
          }
        });

    pushChannel.connect();
    asyncAction.onSuccess("channelToken");

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .connect(with(subscriber), with(any(AsyncCallback.class)));
            will(asyncAction);

            oneOf(channel).open(with("newChannelToken"), with(channelListener));
          }
        });

    channelListener.getValue().onTokenExpire();
    asyncAction.onSuccess("newChannelToken");

    assertTrue(pushChannel.hasInitialConnection());
  }
  @Test
  public void openConnection() throws Exception {

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .connect(with(subscriber), with(any(AsyncCallback.class)));
            will(asyncAction);
          }
        });

    pushChannel.connect();
    assertTrue(pushChannel.hasInitialConnection());
  }
  @Test
  public void retrySubscribingForEventOnce() {

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .subscribe(with(subscriber), with(event.TYPE), with(any(AsyncCallback.class)));
            will(asyncAction);

            oneOf(timer).scheduleAction(with(any(Integer.class)), with(timerAction));
          }
        });

    pushChannel.subscribe(event.TYPE, subscribeCallback);
    asyncAction.onFailure(new RuntimeException());

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .subscribe(with(subscriber), with(event.TYPE), with(any(AsyncCallback.class)));
            will(asyncAction);

            never(timer);
          }
        });

    timerAction.getValue().execute();
    asyncAction.onSuccess(null);

    assertThat(subscribeCallback.timesCalled, is(1));
  }
  @Test(expected = UnableToUnsubscribeFromEventException.class)
  public void unableToUnsubscribeFromEvent() {

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .unsubscribe(with(subscriber), with(event.TYPE), with(any(AsyncCallback.class)));
            will(asyncAction);

            oneOf(timer).scheduleAction(with(any(Integer.class)), with(timerAction));
          }
        });

    pushChannel.unsubscribe(event.TYPE, unsubscribeCallback);
    asyncAction.onFailure(new RuntimeException());

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .unsubscribe(with(subscriber), with(event.TYPE), with(any(AsyncCallback.class)));
            will(asyncAction);

            never(timer);
          }
        });

    timerAction.getValue().execute();
    asyncAction.onFailure(null);

    assertThat(unsubscribeCallback.timesCalled, is(0));
  }
  @Test(expected = SubscriberNotAliveException.class)
  public void unableToKeepSubscriberAlive() {

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .subscribe(with(subscriber), with(event.TYPE), with(any(AsyncCallback.class)));
            will(asyncAction);
          }
        });

    pushChannel.subscribe(event.TYPE, subscribeCallback);
    asyncAction.onSuccess(null);

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .keepAlive(with(subscriber), with(any(AsyncCallback.class)));
            will(asyncAction);
          }
        });

    pushChannel.onTime();

    context.checking(
        new Expectations() {
          {
            oneOf(timer).scheduleAction(with(any(Integer.class)), with(timerAction));
          }
        });

    asyncAction.onFailure(new RuntimeException());

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .keepAlive(with(subscriber), with(any(AsyncCallback.class)));
            will(asyncAction);
          }
        });

    timerAction.getValue().execute();
    asyncAction.onFailure(new RuntimeException());
  }
  @Test
  public void subscriberWithoutSubscriptionsIsNotKeptAlive() {

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .subscribe(with(subscriber), with(event.TYPE), with(any(AsyncCallback.class)));
            will(asyncAction);
          }
        });

    pushChannel.subscribe(event.TYPE, subscribeCallback);
    asyncAction.onSuccess(null);

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .unsubscribe(with(subscriber), with(event.TYPE), with(any(AsyncCallback.class)));
            will(asyncAction);
          }
        });

    pushChannel.unsubscribe(event.TYPE, unsubscribeCallback);
    asyncAction.onSuccess(null);

    context.checking(
        new Expectations() {
          {
            never(timer);
            never(pushChannelServiceAsync);
          }
        });

    pushChannel.onTime();
  }
  @Test
  public void subscribeForEvent() {

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .subscribe(with(subscriber), with(event.TYPE), with(any(AsyncCallback.class)));
            will(asyncAction);
          }
        });

    pushChannel.subscribe(event.TYPE, subscribeCallback);
    asyncAction.onSuccess(null);

    assertThat(subscribeCallback.timesCalled, is(1));
  }
  @Test
  public void retryToOpenConnection() throws Exception {
    final AsyncAction<String> asyncAction = new AsyncAction<String>();

    context.checking(
        new Expectations() {
          {
            oneOf(pushChannelServiceAsync)
                .connect(with(subscriber), with(any(AsyncCallback.class)));
            will(asyncAction);

            oneOf(timer).reconnect(pushChannel);
          }
        });

    pushChannel.connect();
    asyncAction.onFailure(new RuntimeException());
  }