/** * Prepare a new {@code StepVerifier} in an uncontrolled environment: * {@link Step#thenAwait} will block in real time. * Each {@link #verify()} will fully (re)play the scenario. * The verification will request a specified amount of values. * * @param publisher the publisher to subscribe to and verify * @param n the amount of items to request * * @return a builder for expectation declaration and ultimately verification. */ static <T> FirstStep<T> create(Publisher<? extends T> publisher, long n) { return create(publisher, StepVerifierOptions.create().initialRequest(n)); }
long n) { return withVirtualTime(scenarioSupplier, StepVerifierOptions.create() .initialRequest(n) .virtualTimeSchedulerSupplier(vtsLookup));
@Test public void windowWhileOneByOneStartingDelimiterReplenishes() { AtomicLong req = new AtomicLong(); Flux<String> source = Flux.just("#", "1A", "1B", "1C", "#", "2A", "2B", "2C", "2D", "#", "3A").hide(); StepVerifier.create( source .doOnRequest(r -> req.addAndGet(r)) .log("source", Level.FINE) .windowWhile(s -> !"#".equals(s), 2) .log("windowWhile", Level.FINE) .concatMap(w -> w.collectList() .log("window", Level.FINE) , 1) .log("downstream", Level.FINE) , StepVerifierOptions.create().checkUnderRequesting(false).initialRequest(1)) .expectNextMatches(List::isEmpty) .thenRequest(1) .assertNext(l -> assertThat(l).containsExactly("1A", "1B", "1C")) .thenRequest(1) .assertNext(l -> assertThat(l).containsExactly("2A", "2B", "2C", "2D")) .thenRequest(1) .assertNext(l -> assertThat(l).containsExactly("3A")) .expectComplete() .verify(Duration.ofSeconds(1)); //TODO is there something wrong here? concatMap now falls back to no fusion because of THREAD_BARRIER, and this results in 15 request total, not 13 assertThat(req.get()).isGreaterThanOrEqualTo(13); //11 elements + the prefetch }
@Test public void suppliedVirtualTimeButNoSourceDoesntEnableScheduler() { VirtualTimeScheduler vts = VirtualTimeScheduler.create(); new DefaultStepVerifierBuilder<String>(StepVerifierOptions.create() .initialRequest(Long.MAX_VALUE) .virtualTimeSchedulerSupplier(() -> vts), null) //important to avoid triggering of vts capture-and-enable .expectNoEvent(Duration.ofSeconds(4)) .expectComplete() .toSubscriber(); try { //also test the side effect case where VTS has been enabled and not reset VirtualTimeScheduler current = VirtualTimeScheduler.get(); assertThat(current).isNotSameAs(vts); } catch (IllegalStateException e) { assertThat(e).hasMessageContaining("VirtualTimeScheduler"); } }
@Test public void discardOnFlushWithoutRequest() { TestPublisher<Integer> testPublisher = TestPublisher.createNoncompliant(TestPublisher.Violation.REQUEST_OVERFLOW); StepVerifier.create(testPublisher .flux() .bufferTimeout(10, Duration.ofMillis(200)), StepVerifierOptions.create().initialRequest(0)) .then(() -> testPublisher.emit(1, 2, 3)) .thenAwait(Duration.ofMillis(250)) .expectErrorMatches(Exceptions::isOverflow) .verifyThenAssertThat() .hasDiscardedExactly(1, 2, 3); }
@Test(timeout = 1000L) public void lowRequestCheckCanBeDisabled() { StepVerifier.create(Flux.just(1, 2), StepVerifierOptions.create().initialRequest(1).checkUnderRequesting(false)) .expectNext(1) .thenConsumeWhile(s -> s == 1); //don't verify, this alone would throw an exception if check activated }
@Test(timeout = 4000) public void manuallyManagedVirtualTime() { VirtualTimeScheduler vts = VirtualTimeScheduler.create(); try { VirtualTimeScheduler.getOrSet(vts); assertThat(VirtualTimeScheduler.get()).isSameAs(vts); Flux<String> flux = Flux.just("foo").delayElements(Duration.ofSeconds(4)); DefaultVerifySubscriber<String> s = new DefaultStepVerifierBuilder<String>(StepVerifierOptions.create() .initialRequest(Long.MAX_VALUE) .virtualTimeSchedulerSupplier(() -> vts), null)//important to avoid triggering of vts capture-and-enable .thenAwait(Duration.ofSeconds(1)) .expectNext("foo") .expectComplete() .toSubscriber(); flux.subscribe(s); vts.advanceTimeBy(Duration.ofSeconds(3)); s.verify(); assertThat(s.virtualTimeScheduler()).isSameAs(vts); assertThat(VirtualTimeScheduler.get()).isSameAs(vts); } finally { VirtualTimeScheduler.reset(); } }
@Test public void recursiveCountdownBackpressure() { StepVerifier.create(Mono.just(10) .expand(countDown), StepVerifierOptions.create() .initialRequest(0) .checkUnderRequesting(false)) .thenRequest(1) .expectNext(10) .thenRequest(3) .expectNext(9, 8, 7) .thenRequest(4) .expectNext(6, 5, 4, 3) .thenRequest(3) .expectNext(2, 1, 0) .verifyComplete(); }
@Test public void discardOnEmitOverflow() { final TestPublisher<Integer> publisher = TestPublisher.createNoncompliant(TestPublisher.Violation.REQUEST_OVERFLOW); StepVerifier.create(publisher.flux() .buffer(Mono.never()), StepVerifierOptions.create().initialRequest(0)) .then(() -> publisher.emit(1, 2, 3)) .expectErrorMatches(Exceptions::isOverflow) .verifyThenAssertThat() .hasDiscardedExactly(1, 2, 3); } }
@Test public void recursiveCountdownBackpressureDepth() { StepVerifier.create(Mono.just(10) .expandDeep(countDown), StepVerifierOptions.create() .initialRequest(0) .checkUnderRequesting(false)) .thenRequest(1) .expectNext(10) .thenRequest(3) .expectNext(9, 8, 7) .thenRequest(4) .expectNext(6, 5, 4, 3) .thenRequest(3) .expectNext(2, 1, 0) .verifyComplete(); }
@Test public void subscribedTwice() { Flux<String> flux = Flux.just("foo", "bar"); DefaultVerifySubscriber<String> s = new DefaultStepVerifierBuilder<String>(StepVerifierOptions.create().initialRequest(Long.MAX_VALUE), null) .expectNext("foo", "bar") .expectComplete() .toSubscriber(); flux.subscribe(s); flux.subscribe(s); assertThatExceptionOfType(AssertionError.class) .isThrownBy(s::verify) .withMessageStartingWith("expectation failed (an unexpected Subscription has been received"); }
@Test public void recursiveCountdownBackpressure() { StepVerifier.create(Flux.just(10) .expand(countDown), StepVerifierOptions.create() .initialRequest(0) .checkUnderRequesting(false)) .thenRequest(1) .expectNext(10) .thenRequest(3) .expectNext(9, 8, 7) .thenRequest(4) .expectNext(6, 5, 4, 3) .thenRequest(3) .expectNext(2, 1, 0) .verifyComplete(); }
@Test public void recursiveCountdownBackpressureDepth() { StepVerifier.create(Flux.just(10) .expandDeep(countDown), StepVerifierOptions.create() .initialRequest(0) .checkUnderRequesting(false)) .thenRequest(1) .expectNext(10) .thenRequest(3) .expectNext(9, 8, 7) .thenRequest(4) .expectNext(6, 5, 4, 3) .thenRequest(3) .expectNext(2, 1, 0) .verifyComplete(); }
@Test public void testWithDescriptionAndScenarioName() { StepVerifierOptions options = StepVerifierOptions.create() .initialRequest(3) .scenarioName("some scenario name"); StepVerifier stepVerifier = StepVerifier .create(Flux.just("foo", "bar", "baz"), options) .expectNext("foo") .as("first") .expectNext("bar") .as("second") .expectNext("bar") .as("third") .as("this is ignored") .expectComplete() .log(); assertThatExceptionOfType(AssertionError.class) .isThrownBy(stepVerifier::verify) .withMessage("[some scenario name] expectation \"third\" failed (expected value: bar; actual value: baz)"); }
/** * Prepare a new {@code StepVerifier} in an uncontrolled environment: * {@link Step#thenAwait} will block in real time. * Each {@link #verify()} will fully (re)play the scenario. * The verification will request a specified amount of values. * * @param publisher the publisher to subscribe to and verify * @param n the amount of items to request * * @return a builder for expectation declaration and ultimately verification. */ static <T> FirstStep<T> create(Publisher<? extends T> publisher, long n) { return create(publisher, StepVerifierOptions.create().initialRequest(n)); }
long n) { return withVirtualTime(scenarioSupplier, StepVerifierOptions.create() .initialRequest(n) .virtualTimeSchedulerSupplier(vtsLookup));