@Test public void recursiveCountdownLoop() { for (int i = 0; i < 1000; i = (i < 100 ? i + 1 : i + 50)) { String tag = "i = " + i + ", strategy = breadth"; List<Integer> list = new ArrayList<>(); StepVerifier.create(Mono.just(i) .expand(countDown)) .expectSubscription() .recordWith(() -> list) .expectNextCount(i + 1) .as(tag) .verifyComplete(); for (int j = 0; j <= i; j++) { assertThat(list.get(j).intValue()) .as(tag + ", " + list) .isEqualTo(i - j); } } }
@Test public void recursiveCountdownLoopDepth() { for (int i = 0; i < 1000; i = (i < 100 ? i + 1 : i + 50)) { String tag = "i = " + i + ", strategy = depth"; List<Integer> list = new ArrayList<>(); StepVerifier.create(Mono.just(i) .expandDeep(countDown)) .expectSubscription() .recordWith(() -> list) .expectNextCount(i + 1) .as(tag) .verifyComplete(); for (int j = 0; j <= i; j++) { assertThat(list.get(j).intValue()) .as(tag + ", " + list) .isEqualTo(i - j); } } }
@Test public void doesntResubscribeNormal() { AtomicInteger subCount = new AtomicInteger(); Mono<Integer> source = Mono.defer(() -> Mono.just(subCount.incrementAndGet())); Mono<Integer> cached = source.cache(Duration.ofMillis(100)) .hide(); StepVerifier.create(cached) .expectNoFusionSupport() .expectNext(1) .as("first subscription caches 1") .verifyComplete(); StepVerifier.create(cached) .expectNext(1) .as("second subscription uses cache") .verifyComplete(); assertThat(subCount.get()).isEqualTo(1); }
@Test default void transactionRollback() { getJdbcOperations().execute("INSERT INTO test VALUES (100)"); Mono.from(getConnectionFactory().create()) .flatMapMany(connection -> Mono.from(connection .beginTransaction()) .<Object>thenMany(Flux.from(connection.createStatement("SELECT value FROM test") .execute()) .flatMap(Example::extractColumns)) .concatWith(Flux.from(connection.createStatement(String.format("INSERT INTO test VALUES (%s)", getPlaceholder(0))) .bind(getIdentifier(0), 200) .execute()) .flatMap(Example::extractRowsUpdated)) .concatWith(Flux.from(connection.createStatement("SELECT value FROM test") .execute()) .flatMap(Example::extractColumns)) .concatWith(connection.rollbackTransaction()) .concatWith(Flux.from(connection.createStatement("SELECT value FROM test") .execute()) .flatMap(Example::extractColumns)) .concatWith(close(connection))) .as(StepVerifier::create) .expectNext(Collections.singletonList(100)).as("value from select") .expectNext(1).as("rows inserted") .expectNext(Arrays.asList(100, 200)).as("values from select") .expectNext(Collections.singletonList(100)).as("value from select") .verifyComplete(); }
@Test default void transactionCommit() { getJdbcOperations().execute("INSERT INTO test VALUES (100)"); Mono.from(getConnectionFactory().create()) .flatMapMany(connection -> Mono.from(connection .beginTransaction()) .<Object>thenMany(Flux.from(connection.createStatement("SELECT value FROM test") .execute()) .flatMap(Example::extractColumns)) .concatWith(Flux.from(connection.createStatement(String.format("INSERT INTO test VALUES (%s)", getPlaceholder(0))) .bind(getIdentifier(0), 200) .execute()) .flatMap(Example::extractRowsUpdated)) .concatWith(Flux.from(connection.createStatement("SELECT value FROM test") .execute()) .flatMap(Example::extractColumns)) .concatWith(connection.commitTransaction()) .concatWith(Flux.from(connection.createStatement("SELECT value FROM test") .execute()) .flatMap(Example::extractColumns)) .concatWith(close(connection))) .as(StepVerifier::create) .expectNext(Collections.singletonList(100)).as("value from select") .expectNext(1).as("rows inserted") .expectNext(Arrays.asList(100, 200)).as("values from select") .expectNext(Arrays.asList(100, 200)).as("values from select") .verifyComplete(); }
@Test default void prepareStatement() { Mono.from(getConnectionFactory().create()) .flatMapMany(connection -> { Statement statement = connection.createStatement(String.format("INSERT INTO test VALUES(%s)", getPlaceholder(0))); IntStream.range(0, 10) .forEach(i -> statement.bind(getIdentifier(0), i).add()); return Flux.from(statement .execute()) .concatWith(close(connection)); }) .as(StepVerifier::create) .expectNextCount(10).as("values from insertions") .verifyComplete(); }
@Test default void compoundStatement() { getJdbcOperations().execute("INSERT INTO test VALUES (100)"); Mono.from(getConnectionFactory().create()) .flatMapMany(connection -> Flux.from(connection .createStatement("SELECT value FROM test; SELECT value FROM test") .execute()) .flatMap(Example::extractColumns) .concatWith(close(connection))) .as(StepVerifier::create) .expectNext(Collections.singletonList(100)).as("value from first select") .expectNext(Collections.singletonList(100)).as("value from second select") .verifyComplete(); }
@Test default void batch() { getJdbcOperations().execute("INSERT INTO test VALUES (100)"); Mono.from(getConnectionFactory().create()) .flatMapMany(connection -> Flux.from(connection .createBatch() .add("INSERT INTO test VALUES(200)") .add("SELECT value FROM test") .execute()) .concatWith(close(connection))) .as(StepVerifier::create) .expectNextCount(2).as("one result for each statement") .verifyComplete(); }
@Test default void bindNull() { Mono.from(getConnectionFactory().create()) .flatMapMany(connection -> Flux.from(connection .createStatement(String.format("INSERT INTO test VALUES(%s)", getPlaceholder(0))) .bindNull(getIdentifier(0), Integer.class).add() .execute()) .concatWith(close(connection))) .as(StepVerifier::create) .expectNextCount(1).as("rows inserted") .verifyComplete(); }
default void check(Flux<Payload> payloads) { getClient() .requestChannel(payloads) .as(StepVerifier::create) .expectNextCount(512) .as("expected 512 items") .expectComplete() .verify(getTimeout()); }
@Test public void recursiveCountdownLoopDepth() { for (int i = 0; i < 1000; i = (i < 100 ? i + 1 : i + 50)) { String tag = "i = " + i + ", strategy = depth"; List<Integer> list = new ArrayList<>(); StepVerifier.create(Flux.just(i) .expand(countDown)) .expectSubscription() .recordWith(() -> list) .expectNextCount(i + 1) .as(tag) .verifyComplete(); for (int j = 0; j <= i; j++) { assertThat(list.get(j).intValue()) .as(tag + ", " + list) .isEqualTo(i - j); } } }
@Test public void recursiveCountdownLoop() { for (int i = 0; i < 1000; i = (i < 100 ? i + 1 : i + 50)) { String tag = "i = " + i + ", strategy = breadth"; List<Integer> list = new ArrayList<>(); StepVerifier.create(Flux.just(i) .expand(countDown)) .expectSubscription() .recordWith(() -> list) .expectNextCount(i + 1) .as(tag) .verifyComplete(); for (int j = 0; j <= i; j++) { assertThat(list.get(j).intValue()) .as(tag + ", " + list) .isEqualTo(i - j); } } }
@Test public void expireAfterTtlNormal() { VirtualTimeScheduler vts = VirtualTimeScheduler.create(); AtomicInteger subCount = new AtomicInteger(); Mono<Integer> source = Mono.defer(() -> Mono.just(subCount.incrementAndGet())); Mono<Integer> cached = source.cache(Duration.ofMillis(100), vts) .hide(); StepVerifier.create(cached) .expectNoFusionSupport() .expectNext(1) .as("first subscription caches 1") .verifyComplete(); vts.advanceTimeBy(Duration.ofMillis(110)); StepVerifier.create(cached) .expectNext(2) .as("cached value should expire") .verifyComplete(); assertThat(subCount.get()).isEqualTo(2); }
@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)"); }
@Test public void expireAfterTtlConditional() { VirtualTimeScheduler vts = VirtualTimeScheduler.create(); AtomicInteger subCount = new AtomicInteger(); Mono<Integer> source = Mono.defer(() -> Mono.just(subCount.incrementAndGet())); Mono<Integer> cached = source.cache(Duration.ofMillis(100), vts) .hide() .filter(always -> true); StepVerifier.create(cached) .expectNoFusionSupport() .expectNext(1) .as("first subscription caches 1") .verifyComplete(); vts.advanceTimeBy(Duration.ofMillis(110)); StepVerifier.create(cached) .expectNext(2) .as("cached value should expire") .verifyComplete(); assertThat(subCount.get()).isEqualTo(2); }
@Test public void doesntResubscribeConditional() { AtomicInteger subCount = new AtomicInteger(); Mono<Integer> source = Mono.defer(() -> Mono.just(subCount.incrementAndGet())); Mono<Integer> cached = source.cache(Duration.ofMillis(100)) .hide() .filter(always -> true); StepVerifier.create(cached) .expectNoFusionSupport() .expectNext(1) .as("first subscription caches 1") .verifyComplete(); StepVerifier.create(cached) .expectNext(1) .as("second subscription uses cache") .verifyComplete(); assertThat(subCount.get()).isEqualTo(1); }
@Test public void testWithDescription() { assertThatExceptionOfType(AssertionError.class) .isThrownBy(() -> StepVerifier.create(Flux.just("foo", "bar", "baz"), 3) .expectNext("foo") .as("first") .expectNext("bar") .as("second") .expectNext("bar") .as("third") .as("this is ignored") .expectComplete() .log() .verify()) .withMessageStartingWith("expectation \"third\" failed"); }
@Test public void coldDisallowsOverflow() { TestPublisher<String> publisher = TestPublisher.createCold(); StepVerifier.create(publisher, 1) .then(() -> publisher.next("foo")).as("should pass") .then(() -> publisher.emit("bar")).as("should fail") .expectNext("foo") .expectErrorMatches(e -> e instanceof IllegalStateException && "Can't deliver value due to lack of requests".equals(e.getMessage())) .verify(); publisher.assertNoRequestOverflow(); }
@Test public void coldAllowsMultipleReplayOnSubscribe() { TestPublisher<String> publisher = TestPublisher.createCold(); publisher.emit("A", "B"); StepVerifier.create(publisher) .expectNextCount(2).as("first") .verifyComplete(); StepVerifier.create(publisher) .expectNextCount(2).as("second") .verifyComplete(); }
@Test public void normalDisallowsOverflow() { TestPublisher<String> publisher = TestPublisher.create(); StepVerifier.create(publisher, 1) .then(() -> publisher.next("foo")).as("should pass") .then(() -> publisher.emit("bar")).as("should fail") .expectNext("foo") .expectErrorMatches(e -> e instanceof IllegalStateException && "Can't deliver value due to lack of requests".equals(e.getMessage())) .verify(); publisher.assertNoRequestOverflow(); }