/** * Triggers any tasks that have not yet been executed and that are scheduled to be * executed at or before this {@link VirtualTimeScheduler}'s present time. */ public void advanceTime() { advanceTimeBy(Duration.ZERO); }
static void virtualOrRealWait(Duration duration, DefaultVerifySubscriber<?> s) throws Exception { if (s.virtualTimeScheduler == null) { s.completeLatch.await(duration.toMillis(), TimeUnit.MILLISECONDS); } else { s.virtualTimeScheduler.advanceTimeBy(duration); } }
@Test public void downstreamDemandShouldBeAbleToDecreaseOnTimeSpan() { Subscription[] subscriptionsHolder = new Subscription[1]; CoreSubscriber<List<String>> actual = new LambdaSubscriber<>(null, e -> {}, null, s -> subscriptionsHolder[0] = s); VirtualTimeScheduler timeScheduler = VirtualTimeScheduler.getOrSet(); FluxBufferTimeout.BufferTimeoutSubscriber<String, List<String>> test = new FluxBufferTimeout.BufferTimeoutSubscriber<String, List<String>>( actual, 5, 100, timeScheduler.createWorker(), ArrayList::new); Subscription subscription = Operators.emptySubscription(); test.onSubscribe(subscription); subscriptionsHolder[0].request(1); assertThat(test.scan(Scannable.Attr.REQUESTED_FROM_DOWNSTREAM)).isEqualTo(1L); timeScheduler.advanceTimeBy(Duration.ofMillis(100)); assertThat(test.scan(Scannable.Attr.REQUESTED_FROM_DOWNSTREAM)).isEqualTo(1L); test.onNext(String.valueOf("0")); timeScheduler.advanceTimeBy(Duration.ofMillis(100)); assertThat(test.scan(Scannable.Attr.REQUESTED_FROM_DOWNSTREAM)).isEqualTo(0L); }
@Test public void apiTakeSchedulerShortcircuits() { VirtualTimeScheduler vts = VirtualTimeScheduler.create(); StepVerifier.create( Mono.delay(Duration.ofMillis(200)) .take(Duration.ofSeconds(10), vts) ) .then(() -> vts.advanceTimeBy(Duration.ofSeconds(10))) .verifyComplete(); }
@Test public void nestedSchedule() { VirtualTimeScheduler vts = VirtualTimeScheduler.create(); List<Long> singleExecutionsTimestamps = new ArrayList<>(); try { vts.schedule(() -> vts.schedule( () -> singleExecutionsTimestamps.add(vts.now(TimeUnit.MILLISECONDS)), 100, TimeUnit.MILLISECONDS ), 300, TimeUnit.MILLISECONDS); vts.advanceTimeBy(Duration.ofMillis(1000)); assertThat(singleExecutionsTimestamps) .as("single executions") .containsExactly(400L); } finally { vts.dispose(); } }
@Test public void cancelUpstreamOnceWhenCancelled() { VirtualTimeScheduler vts = VirtualTimeScheduler.create(); AtomicLong upstreamCancelCount = new AtomicLong(); Mono<String> source = Mono.just("foo").log().hide() .doOnCancel(() -> upstreamCancelCount.incrementAndGet()); StepVerifier.withVirtualTime( () -> new MonoDelayElement<>(source, 2, TimeUnit.SECONDS, vts), () -> vts, Long.MAX_VALUE) .expectSubscription() .expectNoEvent(Duration.ofSeconds(1)) .thenCancel() .verify(); vts.advanceTimeBy(Duration.ofHours(1)); assertThat(upstreamCancelCount.get()).isEqualTo(1); }
@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(timeout = 3000) public void verifyVirtualTimeOnNextIntervalManual() { VirtualTimeScheduler vts = VirtualTimeScheduler.create(); StepVerifier.withVirtualTime(() -> Flux.interval(Duration.ofMillis(1000), vts) .map(d -> "t" + d)) .then(() -> vts.advanceTimeBy(Duration.ofHours(1))) .expectNextCount(3600) .thenCancel() .verify(); }
@Test public void timedError() throws Exception { VirtualTimeScheduler.getOrSet(); ReplayProcessor<Integer> rp = ReplayProcessor.createTimeout(Duration.ofSeconds(1)); for (int i = 0; i < 5; i++) { rp.onNext(i); } VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(2)); for (int i = 5; i < 10; i++) { rp.onNext(i); } rp.onError(new Exception("test")); StepVerifier.create(rp.hide()) .expectNext(5,6,7,8,9) .verifyErrorMessage("test"); }
@Test public void timedFusedError() throws Exception { VirtualTimeScheduler.getOrSet(); ReplayProcessor<Integer> rp = ReplayProcessor.createTimeout(Duration.ofSeconds(1)); for (int i = 0; i < 5; i++) { rp.onNext(i); } VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(2)); for (int i = 5; i < 10; i++) { rp.onNext(i); } rp.onError(new Exception("test")); StepVerifier.create(rp) .expectFusion(Fuseable.NONE) .expectNext(5,6,7,8,9) .verifyErrorMessage("test"); }
@Test public void cacheFluxTTL2() { VirtualTimeScheduler vts = VirtualTimeScheduler.create(); AtomicInteger i = new AtomicInteger(0); Flux<Integer> source = Flux.defer(() -> Flux.just(i.incrementAndGet())) .cache(Duration.ofMillis(2000), vts); StepVerifier.create(source) .expectNext(1) .verifyComplete(); StepVerifier.create(source) .expectNext(1) .verifyComplete(); vts.advanceTimeBy(Duration.ofSeconds(3)); StepVerifier.create(source) .expectNext(2) .verifyComplete(); }
@Test public void timedAndBoundFusedError() throws Exception { ReplayProcessor<Integer> rp = ReplayProcessor.createSizeAndTimeout(5, Duration.ofSeconds(1)); for (int i = 0; i < 10; i++) { rp.onNext(i); } VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(2)); for (int i = 10; i < 20; i++) { rp.onNext(i); } rp.onError(new Exception("test")); StepVerifier.create(rp) .expectFusion(Fuseable.ASYNC) .expectNext(15,16,17,18,19) .verifyErrorMessage("test"); Assert.assertFalse("Has subscribers?", rp.hasDownstreams()); }
@Test public void shouldNotRetainSubscriptionToSourceWhenComplete() throws Exception { VirtualTimeScheduler scheduler = VirtualTimeScheduler.create(); Duration gracePeriod = Duration.ofMillis(10); Flux<String> f = Flux.just("hello world") .replay(1) .refCount(1, gracePeriod, scheduler); AssertSubscriber<String> s = AssertSubscriber.create(); f.subscribe(s); scheduler.advanceTimeBy(gracePeriod); StepVerifier.create(f.next()) .expectNext("hello world") .verifyComplete(); scheduler.advanceTimeBy(gracePeriod); s.assertValueCount(1).assertNoError().assertComplete(); }
@Test public void timedAndBoundError() throws Exception { ReplayProcessor<Integer> rp = ReplayProcessor.createSizeAndTimeout(5, Duration.ofSeconds(1)); for (int i = 0; i < 10; i++) { rp.onNext(i); } VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(2)); for (int i = 10; i < 20; i++) { rp.onNext(i); } rp.onError(new Exception("test")); StepVerifier.create(rp.hide()) .expectFusion(Fuseable.NONE) .expectNext(15,16,17,18,19) .verifyErrorMessage("test"); Assert.assertFalse("Has subscribers?", rp.hasDownstreams()); }
@Test public void timedFused() throws Exception { VirtualTimeScheduler.getOrSet(); ReplayProcessor<Integer> rp = ReplayProcessor.createTimeout(Duration.ofSeconds(1)); for (int i = 0; i < 5; i++) { rp.onNext(i); } VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(2)); for (int i = 5; i < 10; i++) { rp.onNext(i); } rp.onComplete(); StepVerifier.create(rp) .expectFusion(Fuseable.NONE) .expectNext(5,6,7,8,9) .verifyComplete(); }
@Test public void timedFusedAfter() throws Exception { ReplayProcessor<Integer> rp = ReplayProcessor.createTimeout(Duration.ofSeconds(1)); StepVerifier.create(rp) .expectFusion(Fuseable.NONE) .then(() -> { for (int i = 0; i < 5; i++) { rp.onNext(i); } VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(2)); for (int i = 5; i < 10; i++) { rp.onNext(i); } rp.onComplete(); }) .expectNext(0,1,2,3,4,5,6,7,8,9) .verifyComplete(); }
@Test public void timed() throws Exception { VirtualTimeScheduler.getOrSet(); ReplayProcessor<Integer> rp = ReplayProcessor.createTimeout(Duration.ofSeconds(1)); for (int i = 0; i < 5; i++) { rp.onNext(i); } VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(2)); for (int i = 5; i < 10; i++) { rp.onNext(i); } rp.onComplete(); StepVerifier.create(rp.hide()) .expectFusion(Fuseable.NONE) .expectNext(5,6,7,8,9) .verifyComplete(); }
@Test public void timedAndBoundFused() throws Exception { ReplayProcessor<Integer> rp = ReplayProcessor.createSizeAndTimeout(5, Duration.ofSeconds(1)); for (int i = 0; i < 10; i++) { rp.onNext(i); } VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(2)); for (int i = 10; i < 20; i++) { rp.onNext(i); } rp.onComplete(); StepVerifier.create(rp) .expectFusion(Fuseable.ASYNC) .expectNext(15,16,17,18,19) .verifyComplete(); Assert.assertFalse("Has subscribers?", rp.hasDownstreams()); }
@Test public void timedAndBound() throws Exception { ReplayProcessor<Integer> rp = ReplayProcessor.createSizeAndTimeout(5, Duration.ofSeconds(1)); for (int i = 0; i < 10; i++) { rp.onNext(i); } VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(2)); for (int i = 10; i < 20; i++) { rp.onNext(i); } rp.onComplete(); StepVerifier.create(rp.hide()) .expectFusion(Fuseable.NONE) .expectNext(15,16,17,18,19) .verifyComplete(); Assert.assertFalse("Has subscribers?", rp.hasDownstreams()); }
@Test public void cacheFlux() { Flux<Tuple2<Long, Integer>> source = Flux.just(1, 2, 3) .delayElements(Duration.ofMillis(1000)) .replay() .autoConnect() .elapsed(); StepVerifier.create(source) .then(() -> vts.advanceTimeBy(Duration.ofSeconds(3))) .expectNextMatches(t -> t.getT1() == 1000 && t.getT2() == 1) .expectNextMatches(t -> t.getT1() == 1000 && t.getT2() == 2) .expectNextMatches(t -> t.getT1() == 1000 && t.getT2() == 3) .verifyComplete(); StepVerifier.create(source) .then(() -> vts.advanceTimeBy(Duration.ofSeconds(3))) .expectNextMatches(t -> t.getT1() == 0 && t.getT2() == 1) .expectNextMatches(t -> t.getT1() == 0 && t.getT2() == 2) .expectNextMatches(t -> t.getT1() == 0 && t.getT2() == 3) .verifyComplete(); }