Java Code Examples for reactor.test.publisher.TestPublisher#next()

The following examples show how to use reactor.test.publisher.TestPublisher#next() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: NotificationTriggerTest.java    From Moss with Apache License 2.0 6 votes vote down vote up
@Test
public void should_notify_on_event() throws InterruptedException {
    //given
    Notifier notifier = mock(Notifier.class);
    TestPublisher<InstanceEvent> events = TestPublisher.create();
    NotificationTrigger trigger = new NotificationTrigger(notifier, events);
    trigger.start();
    Thread.sleep(500L); //wait for subscription

    //when registered event is emitted
    InstanceStatusChangedEvent event = new InstanceStatusChangedEvent(instance.getId(), instance.getVersion(),
        StatusInfo.ofDown());
    events.next(event);
    //then should notify
    verify(notifier, times(1)).notify(event);

    //when registered event is emitted but the trigger has been stopped
    trigger.stop();
    clearInvocations(notifier);
    events.next(new InstanceRegisteredEvent(instance.getId(), instance.getVersion(), instance.getRegistration()));
    //then should not notify
    verify(notifier, never()).notify(event);
}
 
Example 2
Source File: FluxSwitchOnFirstTest.java    From reactor-core with Apache License 2.0 6 votes vote down vote up
@Test
public void shouldNeverSendIncorrectRequestSizeToUpstreamConditional() throws InterruptedException {
    TestPublisher<Long> publisher = TestPublisher.createCold();
    AtomicLong capture = new AtomicLong();
    ArrayList<Long> requested = new ArrayList<>();
    CountDownLatch latch = new CountDownLatch(1);
    Flux<Long> switchTransformed = publisher.flux()
                                            .doOnRequest(requested::add)
                                            .switchOnFirst((first, innerFlux) -> innerFlux)
                                            .filter(e -> true);

    publisher.next(1L);
    publisher.complete();

    switchTransformed.subscribeWith(new LambdaSubscriber<>(capture::set, __ -> {}, latch::countDown, s -> s.request(1)));

    latch.await(5, TimeUnit.SECONDS);

    Assertions.assertThat(capture.get()).isEqualTo(1L);
    Assertions.assertThat(requested).containsExactly(1L);
}
 
Example 3
Source File: FluxSwitchOnFirstTest.java    From reactor-core with Apache License 2.0 6 votes vote down vote up
@Test
public void shouldNeverSendIncorrectRequestSizeToUpstream() throws InterruptedException {
    TestPublisher<Long> publisher = TestPublisher.createCold();
    AtomicLong capture = new AtomicLong();
    ArrayList<Long> requested = new ArrayList<>();
    CountDownLatch latch = new CountDownLatch(1);
    Flux<Long> switchTransformed = publisher.flux()
                                            .doOnRequest(requested::add)
                                            .switchOnFirst((first, innerFlux) -> innerFlux);

    publisher.next(1L);
    publisher.complete();

    switchTransformed.subscribeWith(new LambdaSubscriber<>(capture::set, __ -> {}, latch::countDown, s -> s.request(1)));

    latch.await(5, TimeUnit.SECONDS);

    Assertions.assertThat(capture.get()).isEqualTo(1L);
    Assertions.assertThat(requested).containsExactly(1L);
}
 
Example 4
Source File: FluxWindowPredicateTest.java    From reactor-core with Apache License 2.0 6 votes vote down vote up
@Test
public void windowWhilePropagatingCancelToSource_disposeOuterFirst() {
	final AtomicBoolean beforeWindowWhileStageCancelled = new AtomicBoolean();
	final AtomicBoolean afterWindowWhileStageCancelled = new AtomicBoolean();

	TestPublisher<String> testPublisher = TestPublisher.create();

	final Flux<String> sourceFlux = testPublisher
			.flux()
			.doOnCancel(() -> beforeWindowWhileStageCancelled.set(true));

	final AtomicInteger windowCounter = new AtomicInteger();

	final Disposable.Swap innerDisposable = Disposables.swap();

	final Disposable outerDisposable = sourceFlux
			.windowWhile(s -> !"#".equals(s))
			.doOnCancel(() -> afterWindowWhileStageCancelled.set(true))
			.subscribe(next -> {
				final int windowId = windowCounter.getAndIncrement();

				innerDisposable.update(next.subscribe());
			});

	testPublisher.next("1");

	// Dispose outer subscription; we should see cancellation at stage after windowWhile, but not before
	outerDisposable.dispose();
	assertThat(afterWindowWhileStageCancelled).as("afterWindowWhileStageCancelled cancelled when outer is disposed").isTrue();
	assertThat(beforeWindowWhileStageCancelled).as("beforeWindowWhileStageCancelled cancelled when outer is disposed").isFalse();

	// Dispose inner subscription; we should see cancellation propagates all the way up
	innerDisposable.dispose();
	assertThat(afterWindowWhileStageCancelled).as("afterWindowWhileStageCancelled cancelled when inner is disposed").isTrue();
	assertThat(beforeWindowWhileStageCancelled).as("beforeWindowWhileStageCancelled cancelled when inner is disposed").isTrue();
}
 
Example 5
Source File: MonoExpandTest.java    From reactor-core with Apache License 2.0 6 votes vote down vote up
@Test
public void depthEmitCancelRace() {
	for (int i = 0; i < 1000; i++) {

		final TestPublisher<Integer> pp = TestPublisher.create();

		final AssertSubscriber<Integer> ts = AssertSubscriber.create(1);

		Mono.just(0)
		    .expandDeep(it -> pp)
		    .subscribe(ts);

		Runnable r1 = () -> pp.next(1);
		Runnable r2 = ts::cancel;

		RaceTestUtils.race(r1, r2, Schedulers.single());
	}
}
 
Example 6
Source File: FluxSwitchOnFirstTest.java    From reactor-core with Apache License 2.0 6 votes vote down vote up
@Test
public void shouldErrorOnOverflowTest() {
    TestPublisher<Long> publisher = TestPublisher.createCold();

    Flux<String> switchTransformed = publisher.flux()
                                              .switchOnFirst((first, innerFlux) -> innerFlux.map(String::valueOf));

    publisher.next(1L);

    StepVerifier.create(switchTransformed, 0)
                .thenRequest(1)
                .expectNext("1")
                .then(() -> publisher.next(2L))
                .expectErrorSatisfies(t -> Assertions
                    .assertThat(t)
                    .isInstanceOf(IllegalStateException.class)
                    .hasMessage("Can't deliver value due to lack of requests")
                )
                .verify(Duration.ofSeconds(10));

    publisher.assertWasRequested();
    publisher.assertNoRequestOverflow();
}
 
Example 7
Source File: FluxSwitchOnFirstTest.java    From reactor-core with Apache License 2.0 6 votes vote down vote up
@Test
public void shouldBeRequestedExactlyOneAndThenLongMaxValue() throws InterruptedException {
    TestPublisher<Long> publisher = TestPublisher.createCold();
    ArrayList<Long> capture = new ArrayList<>();
    ArrayList<Long> requested = new ArrayList<>();
    CountDownLatch latch = new CountDownLatch(1);
    Flux<Long> switchTransformed = publisher.flux()
                                            .doOnRequest(requested::add)
                                            .switchOnFirst((first, innerFlux) -> innerFlux);

    publisher.next(1L);
    publisher.complete();

    switchTransformed.subscribe(capture::add, __ -> {}, latch::countDown);

    latch.await(5, TimeUnit.SECONDS);

    Assertions.assertThat(capture).containsExactly(1L);
    Assertions.assertThat(requested).containsExactly(1L, Long.MAX_VALUE);
}
 
Example 8
Source File: FluxSwitchOnFirstTest.java    From reactor-core with Apache License 2.0 6 votes vote down vote up
@Test
public void shouldBeAbleToBeCancelledProperly3() {
    TestPublisher<Integer> publisher = TestPublisher.createCold();
    Flux<String> switchTransformed = publisher.flux()
                                              .switchOnFirst((first, innerFlux) ->
                                                      innerFlux
                                                              .map(String::valueOf)
                                              )
                                              .take(1);

    publisher.next(1);
    publisher.next(2);
    publisher.next(3);
    publisher.next(4);

    StepVerifier.create(switchTransformed, 1)
                .expectNext("1")
                .expectComplete()
                .verify(Duration.ofSeconds(10));

    publisher.assertCancelled();
    publisher.assertWasRequested();
}
 
Example 9
Source File: ByteStreamAggregatorTest.java    From styx with Apache License 2.0 5 votes vote down vote up
@Test
public void aggregatesUpToNBytes() {
    AtomicReference<Throwable> causeCapture = new AtomicReference<>(null);

    Buffer a = new Buffer("aaabbb", UTF_8);
    Buffer b = new Buffer("ccc", UTF_8);

    TestPublisher<Buffer> upstream = TestPublisher.create();

    ByteStreamAggregator aggregator = new ByteStreamAggregator(upstream, 8);

    CompletableFuture<Buffer> future = aggregator.apply()
            .exceptionally(cause -> {
                causeCapture.set(cause);
                throw new RuntimeException();
            });

    upstream.next(a);
    upstream.next(b);

    upstream.assertCancelled();

    assertTrue(future.isCompletedExceptionally());
    assertThat(causeCapture.get(), instanceOf(ContentOverflowException.class));

    assertThat(a.delegate().refCnt(), is(0));
    assertThat(b.delegate().refCnt(), is(0));
}
 
Example 10
Source File: ByteStreamAggregatorTest.java    From styx with Apache License 2.0 5 votes vote down vote up
@Test
public void emitsErrors() {
    AtomicReference<Throwable> causeCapture = new AtomicReference<>(null);

    Buffer a = new Buffer("aaabbb", UTF_8);

    TestPublisher<Buffer> upstream = TestPublisher.create();

    ByteStreamAggregator aggregator = new ByteStreamAggregator(upstream, 8);

    CompletableFuture<Buffer> future = aggregator.apply()
            .exceptionally(cause -> {
                causeCapture.set(cause);
                throw new RuntimeException();
            });

    upstream.next(a);
    upstream.error(new RuntimeException("something broke"));

    upstream.assertCancelled();

    assertTrue(future.isCompletedExceptionally());
    assertThat(causeCapture.get(), instanceOf(RuntimeException.class));
    assertThat(causeCapture.get().getMessage(), is("something broke"));

    assertThat(a.delegate().refCnt(), is(0));
}
 
Example 11
Source File: StepVerifierTests.java    From reactor-core with Apache License 2.0 5 votes vote down vote up
@Test
public void testExpectRecordedMatchesWithoutComplete() {
	List<Integer> expected = Arrays.asList(1,2);

	TestPublisher<Integer> publisher = TestPublisher.createCold();
	publisher.next(1);
	publisher.next(2);

	StepVerifier.create(publisher)
	            .recordWith(ArrayList::new)
	            .thenConsumeWhile(i -> i < 2)
	            .expectRecordedMatches(expected::equals)
	            .thenCancel()
	            .verify();
}
 
Example 12
Source File: FluxBufferPredicateTest.java    From reactor-core with Apache License 2.0 5 votes vote down vote up
@Test
public void onNextRaceWithRequest() {
	AtomicLong requested = new AtomicLong();
	TestPublisher<Integer> testPublisher = TestPublisher.create();
	FluxBufferPredicate<Integer, List<Integer>> bufferPredicate = new FluxBufferPredicate<>(
			testPublisher.flux().doOnRequest(requested::addAndGet),
			i -> true, ArrayList::new, FluxBufferPredicate.Mode.UNTIL);

	BaseSubscriber<List<Integer>> subscriber = new BaseSubscriber<List<Integer>>() {
		@Override
		protected void hookOnSubscribe(Subscription subscription) {
			request(1);
		}
	};
	bufferPredicate.subscribe(subscriber);
	@SuppressWarnings("unchecked")
	final FluxBufferPredicate.BufferPredicateSubscriber<Integer, List<Integer>> bufferPredicateSubscriber =
			(FluxBufferPredicate.BufferPredicateSubscriber<Integer, List<Integer>>) subscriber.subscription;

	for (int i = 0; i < 10; i++) {
		final int value = i;
		RaceTestUtils.race(() -> testPublisher.next(value), () -> subscriber.request(1));
	}
	for (int i = 0; i < bufferPredicateSubscriber.requestedFromSource; i++) {
		testPublisher.next(100 + i);
	}
	testPublisher.complete();

	assertThat(requested).as("total upstream request").hasValue(10 + 1);
}
 
Example 13
Source File: ReconnectMonoTests.java    From rsocket-java with Apache License 2.0 5 votes vote down vote up
@Test
public void shouldBePossibleToRemoveThemSelvesFromTheList_CancellationTest() {
  final TestPublisher<String> publisher =
      TestPublisher.createNoncompliant(TestPublisher.Violation.REQUEST_OVERFLOW);

  final ReconnectMono<String> reconnectMono =
      publisher.mono().as(source -> new ReconnectMono<>(source, onExpire(), onValue()));

  MonoProcessor<String> processor = MonoProcessor.create();

  reconnectMono.subscribe(processor);

  Assertions.assertThat(expired).isEmpty();
  Assertions.assertThat(received).isEmpty();
  Assertions.assertThat(processor.isTerminated()).isFalse();

  publisher.next("test");

  Assertions.assertThat(expired).isEmpty();
  Assertions.assertThat(received).isEmpty();
  Assertions.assertThat(processor.isTerminated()).isFalse();

  processor.cancel();

  Assertions.assertThat(reconnectMono.resolvingInner.subscribers)
      .isEqualTo(ResolvingOperator.EMPTY_SUBSCRIBED);

  publisher.complete();

  Assertions.assertThat(expired).isEmpty();
  Assertions.assertThat(received).hasSize(1);
  Assertions.assertThat(processor.isTerminated()).isFalse();
  Assertions.assertThat(processor.peek()).isNull();
}
 
Example 14
Source File: FluxBufferPredicateTest.java    From reactor-core with Apache License 2.0 5 votes vote down vote up
@Test
public void requestRaceWithOnNext() {
	AtomicLong requested = new AtomicLong();
	TestPublisher<Integer> testPublisher = TestPublisher.create();
	FluxBufferPredicate<Integer, List<Integer>> bufferPredicate = new FluxBufferPredicate<>(
			testPublisher.flux().doOnRequest(requested::addAndGet),
			i -> true, ArrayList::new, FluxBufferPredicate.Mode.UNTIL);

	BaseSubscriber<List<Integer>> subscriber = new BaseSubscriber<List<Integer>>() {
		@Override
		protected void hookOnSubscribe(Subscription subscription) {
			request(1);
		}
	};
	bufferPredicate.subscribe(subscriber);
	@SuppressWarnings("unchecked")
	final FluxBufferPredicate.BufferPredicateSubscriber<Integer, List<Integer>> bufferPredicateSubscriber =
			(FluxBufferPredicate.BufferPredicateSubscriber<Integer, List<Integer>>) subscriber.subscription;

	for (int i = 0; i < 10; i++) {
		final int value = i;
		RaceTestUtils.race(() -> subscriber.request(1), () -> testPublisher.next(value));
	}
	for (int i = 0; i < bufferPredicateSubscriber.requestedFromSource; i++) {
		testPublisher.next(100 + i);
	}
	testPublisher.complete();

	assertThat(requested).as("total upstream request").hasValue(10 + 1);
}
 
Example 15
Source File: ReconnectMonoTests.java    From rsocket-java with Apache License 2.0 5 votes vote down vote up
@Test
public void shouldNotExpiredIfNotCompleted() {
  final TestPublisher<String> publisher =
      TestPublisher.createNoncompliant(TestPublisher.Violation.REQUEST_OVERFLOW);

  final ReconnectMono<String> reconnectMono =
      publisher.mono().as(source -> new ReconnectMono<>(source, onExpire(), onValue()));

  MonoProcessor<String> processor = MonoProcessor.create();

  reconnectMono.subscribe(processor);

  Assertions.assertThat(expired).isEmpty();
  Assertions.assertThat(received).isEmpty();
  Assertions.assertThat(processor.isTerminated()).isFalse();

  publisher.next("test");

  Assertions.assertThat(expired).isEmpty();
  Assertions.assertThat(received).isEmpty();
  Assertions.assertThat(processor.isTerminated()).isFalse();

  reconnectMono.invalidate();

  Assertions.assertThat(expired).isEmpty();
  Assertions.assertThat(received).isEmpty();
  Assertions.assertThat(processor.isTerminated()).isFalse();
  publisher.assertSubscribers(1);
  Assertions.assertThat(publisher.subscribeCount()).isEqualTo(1);

  publisher.complete();

  Assertions.assertThat(expired).isEmpty();
  Assertions.assertThat(received).hasSize(1);
  Assertions.assertThat(processor.isTerminated()).isTrue();

  publisher.assertSubscribers(0);
  Assertions.assertThat(publisher.subscribeCount()).isEqualTo(1);
}
 
Example 16
Source File: ReconnectMonoTests.java    From rsocket-java with Apache License 2.0 4 votes vote down vote up
@Test
public void shouldExpireValueOnRacingDisposeAndErrorWithNoBackoff() {
  Hooks.onErrorDropped(t -> {});
  RuntimeException runtimeException = new RuntimeException("test");
  for (int i = 0; i < 10000; i++) {
    final TestPublisher<String> cold =
        TestPublisher.createNoncompliant(TestPublisher.Violation.REQUEST_OVERFLOW);

    final ReconnectMono<String> reconnectMono =
        cold.mono()
            .retryWhen(Retry.max(1).filter(t -> t instanceof Exception))
            .as(source -> new ReconnectMono<>(source, onExpire(), onValue()));

    final MonoProcessor<String> processor = reconnectMono.subscribeWith(MonoProcessor.create());

    Assertions.assertThat(expired).isEmpty();
    Assertions.assertThat(received).isEmpty();

    cold.next("value" + i);

    RaceTestUtils.race(() -> cold.error(runtimeException), reconnectMono::dispose);

    Assertions.assertThat(processor.isTerminated()).isTrue();

    if (processor.isError()) {

      if (processor.getError() instanceof CancellationException) {
        Assertions.assertThat(processor.getError())
            .isInstanceOf(CancellationException.class)
            .hasMessage("ReconnectMono has already been disposed");
      } else {
        Assertions.assertThat(processor.getError())
            .matches(t -> Exceptions.isRetryExhausted(t))
            .hasCause(runtimeException);
      }

      Assertions.assertThat(expired).hasSize(1).containsOnly("value" + i);
    } else {
      Assertions.assertThat(received)
          .hasSize(1)
          .containsOnly(Tuples.of("value" + i, reconnectMono));
      Assertions.assertThat(processor.peek()).isEqualTo("value" + i);
    }

    expired.clear();
    received.clear();
  }
}
 
Example 17
Source File: OnDiscardShouldNotLeakTest.java    From reactor-core with Apache License 2.0 4 votes vote down vote up
@Test
public void ensureNoLeaksPopulatedQueueAndRacingCancelAndOnComplete() {
	Assumptions.assumeThat(discardScenario.subscriptionsNumber).isOne();
	for (int i = 0; i < 10000; i++) {
		tracker.reset();
		TestPublisher<Tracked> testPublisher = TestPublisher.createNoncompliant(
				TestPublisher.Violation.DEFER_CANCELLATION,
				TestPublisher.Violation.REQUEST_OVERFLOW);
		Publisher<Tracked> source = discardScenario.producePublisherFromSources(testPublisher);

		if (conditional) {
			if (source instanceof Flux) {
				source = ((Flux<Tracked>) source).filter(t -> true);
			}
			else {
				source = ((Mono<Tracked>) source).filter(t -> true);
			}
		}

		Scannable scannable = Scannable.from(source);
		Integer prefetch = scannable.scan(Scannable.Attr.PREFETCH);

		Assumptions.assumeThat(prefetch).isNotZero();

		AssertSubscriber<Tracked> assertSubscriber = new AssertSubscriber<>(Operators.enableOnDiscard(null, Tracked::safeRelease), 0);
		if (fused) {
			assertSubscriber.requestedFusionMode(Fuseable.ANY);
		}
		source.subscribe(assertSubscriber);

		testPublisher.next(tracker.track(1));
		testPublisher.next(tracker.track(2));
		testPublisher.next(tracker.track(3));
		testPublisher.next(tracker.track(4));

		RaceTestUtils.race(
				assertSubscriber::cancel,
				() -> testPublisher.complete(),
				scheduler);

		List<Tracked> values = assertSubscriber.values();
		values.forEach(Tracked::release);

		tracker.assertNoLeaks();
	}
}
 
Example 18
Source File: OnDiscardShouldNotLeakTest.java    From reactor-core with Apache License 2.0 4 votes vote down vote up
@Test
public void ensureNoLeaksPopulatedQueueAndRacingCancelAndOnError() {
	Assumptions.assumeThat(discardScenario.subscriptionsNumber).isOne();
	for (int i = 0; i < 10000; i++) {
		tracker.reset();
		TestPublisher<Tracked> testPublisher = TestPublisher.createNoncompliant(
				TestPublisher.Violation.DEFER_CANCELLATION,
				TestPublisher.Violation.REQUEST_OVERFLOW);
		@SuppressWarnings("unchecked")
		Publisher<Tracked> source = discardScenario.producePublisherFromSources(testPublisher);

		if (conditional) {
			if (source instanceof Flux) {
				source = ((Flux<Tracked>) source).filter(t -> true);
			}
			else {
				source = ((Mono<Tracked>) source).filter(t -> true);
			}
		}

		Scannable scannable = Scannable.from(source);
		Integer prefetch = scannable.scan(Scannable.Attr.PREFETCH);

		Assumptions.assumeThat(prefetch).isNotZero();

		AssertSubscriber<Tracked> assertSubscriber = new AssertSubscriber<>(Operators.enableOnDiscard(null, Tracked::safeRelease), 0);
		if (fused) {
			assertSubscriber.requestedFusionMode(Fuseable.ANY);
		}
		source.subscribe(assertSubscriber);

		testPublisher.next(tracker.track(1));
		testPublisher.next(tracker.track(2));
		testPublisher.next(tracker.track(3));
		testPublisher.next(tracker.track(4));

		RaceTestUtils.race(
				assertSubscriber::cancel,
				() -> testPublisher.error(new RuntimeException("test")),
				scheduler);

		List<Tracked> values = assertSubscriber.values();
		values.forEach(Tracked::release);
		if (assertSubscriber.isTerminated()) {
			// has a chance to error with rejected exception
			assertSubscriber.assertError();
		}

		tracker.assertNoLeaks();
	}
}
 
Example 19
Source File: ReconnectMonoTests.java    From rsocket-java with Apache License 2.0 4 votes vote down vote up
@Test
public void shouldExpireValueExactlyOnceOnRacingBetweenInvalidates() {
  for (int i = 0; i < 10000; i++) {
    final TestPublisher<String> cold = TestPublisher.createCold();
    cold.next("value");
    final int timeout = 10;

    final ReconnectMono<String> reconnectMono =
        cold.mono().as(source -> new ReconnectMono<>(source, onExpire(), onValue()));

    StepVerifier.create(reconnectMono.subscribeOn(Schedulers.elastic()))
        .expectSubscription()
        .expectNext("value")
        .expectComplete()
        .verify(Duration.ofSeconds(timeout));

    Assertions.assertThat(expired).isEmpty();
    Assertions.assertThat(received).hasSize(1).containsOnly(Tuples.of("value", reconnectMono));

    RaceTestUtils.race(reconnectMono::invalidate, reconnectMono::invalidate);

    Assertions.assertThat(expired).hasSize(1).containsOnly("value");
    Assertions.assertThat(received).hasSize(1).containsOnly(Tuples.of("value", reconnectMono));

    StepVerifier.create(reconnectMono.subscribeOn(Schedulers.elastic()))
        .expectSubscription()
        .expectNext("value")
        .expectComplete()
        .verify(Duration.ofSeconds(timeout));

    Assertions.assertThat(expired).hasSize(1).containsOnly("value");
    Assertions.assertThat(received)
        .hasSize(2)
        .containsOnly(Tuples.of("value", reconnectMono), Tuples.of("value", reconnectMono));

    Assertions.assertThat(cold.subscribeCount()).isEqualTo(2);

    expired.clear();
    received.clear();
  }
}
 
Example 20
Source File: InfoUpdateTriggerTest.java    From Moss with Apache License 2.0 4 votes vote down vote up
@Test
public void should_update_on_event() throws InterruptedException {
    //given
    InfoUpdater updater = mock(InfoUpdater.class);
    when(updater.updateInfo(any(InstanceId.class))).thenReturn(Mono.empty());

    TestPublisher<InstanceEvent> events = TestPublisher.create();
    InfoUpdateTrigger trigger = new InfoUpdateTrigger(updater, events.flux());
    trigger.start();
    Thread.sleep(50L); //wait for subscription

    //when some non-status-change event is emitted
    events.next(new InstanceRegisteredEvent(instance.getId(), instance.getVersion(), instance.getRegistration()));
    //then should not update
    verify(updater, never()).updateInfo(instance.getId());

    //when status-change event is emitted
    events.next(new InstanceStatusChangedEvent(instance.getId(), instance.getVersion(), StatusInfo.ofDown()));
    //then should update
    verify(updater, times(1)).updateInfo(instance.getId());

    //when endpoints-detected event is emitted
    clearInvocations(updater);
    events.next(new InstanceEndpointsDetectedEvent(instance.getId(), instance.getVersion(), Endpoints.empty()));
    //then should update
    verify(updater, times(1)).updateInfo(instance.getId());

    //when registration updated event is emitted
    clearInvocations(updater);
    events.next(
        new InstanceRegistrationUpdatedEvent(instance.getId(), instance.getVersion(), instance.getRegistration()));
    //then should update
    verify(updater, times(1)).updateInfo(instance.getId());

    //when registered event is emitted but the trigger has been stopped
    trigger.stop();
    clearInvocations(updater);
    events.next(new InstanceRegisteredEvent(instance.getId(), instance.getVersion(), instance.getRegistration()));
    //then should not update
    verify(updater, never()).updateInfo(instance.getId());
}