/* * Copyright (c) 2011-2017 Pivotal Software Inc, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package reactor.core.publisher; import java.time.Duration; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import org.reactivestreams.Subscriber; import reactor.test.StepVerifier; import reactor.util.function.Tuple2; import static org.assertj.core.api.Assertions.assertThat; public class MonoProcessorTest { @Test(expected = IllegalStateException.class) public void MonoProcessorResultNotAvailable() { MonoProcessor<String> mp = MonoProcessor.create(); mp.block(Duration.ofMillis(1)); } @Test public void MonoProcessorRejectedDoOnTerminate() { MonoProcessor<String> mp = MonoProcessor.create(); AtomicReference<Throwable> ref = new AtomicReference<>(); mp.doOnTerminate((s, f) -> ref.set(f)).subscribe(); mp.onError(new Exception("test")); assertThat(ref.get()).hasMessage("test"); assertThat(mp.isSuccess()).isFalse(); assertThat(mp.isError()).isTrue(); } @Test public void MonoProcessorRejectedSubscribeCallback() { MonoProcessor<String> mp = MonoProcessor.create(); AtomicReference<Throwable> ref = new AtomicReference<>(); mp.subscribe(v -> {}, ref::set); mp.onError(new Exception("test")); assertThat(ref.get()).hasMessage("test"); assertThat(mp.isSuccess()).isFalse(); assertThat(mp.isError()).isTrue(); } @Test public void MonoProcessorSuccessDoOnTerminate() { MonoProcessor<String> mp = MonoProcessor.create(); AtomicReference<String> ref = new AtomicReference<>(); mp.doOnTerminate((s, f) -> ref.set(s)).subscribe(); mp.onNext("test"); assertThat(ref.get()).isEqualToIgnoringCase("test"); assertThat(mp.isSuccess()).isTrue(); assertThat(mp.isError()).isFalse(); } @Test public void MonoProcessorSuccessSubscribeCallback() { MonoProcessor<String> mp = MonoProcessor.create(); AtomicReference<String> ref = new AtomicReference<>(); mp.subscribe(ref::set); mp.onNext("test"); assertThat(ref.get()).isEqualToIgnoringCase("test"); assertThat(mp.isSuccess()).isTrue(); assertThat(mp.isError()).isFalse(); } @Test public void MonoProcessorRejectedDoOnError() { MonoProcessor<String> mp = MonoProcessor.create(); AtomicReference<Throwable> ref = new AtomicReference<>(); mp.doOnError(ref::set).subscribe(); mp.onError(new Exception("test")); assertThat(ref.get()).hasMessage("test"); assertThat(mp.isSuccess()).isFalse(); assertThat(mp.isError()).isTrue(); } @Test(expected = NullPointerException.class) public void MonoProcessorRejectedSubscribeCallbackNull() { MonoProcessor<String> mp = MonoProcessor.create(); mp.subscribe((Subscriber<String>)null); } @Test public void MonoProcessorSuccessDoOnSuccess() { MonoProcessor<String> mp = MonoProcessor.create(); AtomicReference<String> ref = new AtomicReference<>(); mp.doOnSuccess(ref::set).subscribe(); mp.onNext("test"); assertThat(ref.get()).isEqualToIgnoringCase("test"); assertThat(mp.isSuccess()).isTrue(); assertThat(mp.isError()).isFalse(); } @Test public void MonoProcessorSuccessChainTogether() { MonoProcessor<String> mp = MonoProcessor.create(); MonoProcessor<String> mp2 = MonoProcessor.create(); mp.subscribe(mp2); mp.onNext("test"); assertThat(mp2.peek()).isEqualToIgnoringCase("test"); assertThat(mp.isSuccess()).isTrue(); assertThat(mp.isError()).isFalse(); } @Test public void MonoProcessorRejectedChainTogether() { MonoProcessor<String> mp = MonoProcessor.create(); MonoProcessor<String> mp2 = MonoProcessor.create(); mp.subscribe(mp2); mp.onError(new Exception("test")); assertThat(mp2.getError()).hasMessage("test"); assertThat(mp.isSuccess()).isFalse(); assertThat(mp.isError()).isTrue(); } @Test(expected = RuntimeException.class) public void MonoProcessorDoubleFulfill() { MonoProcessor<String> mp = MonoProcessor.create(); mp.onNext("test"); mp.onNext("test"); } @Test public void MonoProcessorNullFulfill() { MonoProcessor<String> mp = MonoProcessor.create(); mp.onNext(null); assertThat(mp.isTerminated()).isTrue(); assertThat(mp.isSuccess()).isTrue(); assertThat(mp.peek()).isNull(); } @Test public void MonoProcessorMapFulfill() { MonoProcessor<Integer> mp = MonoProcessor.create(); mp.onNext(1); MonoProcessor<Integer> mp2 = mp.map(s -> s * 2) .subscribe(); assertThat(mp2.isTerminated()).isTrue(); assertThat(mp2.isSuccess()).isTrue(); assertThat(mp2.peek()).isEqualTo(2); } @Test public void MonoProcessoThenFulfill() { MonoProcessor<Integer> mp = MonoProcessor.create(); mp.onNext(1); MonoProcessor<Integer> mp2 = mp.flatMap(s -> Mono.just(s * 2)) .subscribe(); assertThat(mp2.isTerminated()).isTrue(); assertThat(mp2.isSuccess()).isTrue(); assertThat(mp2.peek()).isEqualTo(2); } @Test public void MonoProcessorMapError() { MonoProcessor<Integer> mp = MonoProcessor.create(); mp.onNext(1); MonoProcessor<Integer> mp2 = MonoProcessor.create(); StepVerifier.create(mp.<Integer>map(s -> { throw new RuntimeException("test"); }).subscribeWith(mp2), 0) .thenRequest(1) .then(() -> { assertThat(mp2.isTerminated()).isTrue(); assertThat(mp2.isSuccess()).isFalse(); assertThat(mp2.getError()).hasMessage("test"); }) .verifyErrorMessage("test"); } @Test(expected = Exception.class) public void MonoProcessorDoubleError() { MonoProcessor<String> mp = MonoProcessor.create(); mp.onError(new Exception("test")); mp.onError(new Exception("test")); } @Test(expected = Exception.class) public void MonoProcessorDoubleSignal() { MonoProcessor<String> mp = MonoProcessor.create(); mp.onNext("test"); mp.onError(new Exception("test")); } @Test public void whenMonoProcessor() { MonoProcessor<Integer> mp = MonoProcessor.create(); MonoProcessor<Integer> mp2 = MonoProcessor.create(); MonoProcessor<Tuple2<Integer, Integer>> mp3 = MonoProcessor.create(); StepVerifier.create(Mono.when(mp, mp2) .subscribeWith(mp3)) .then(() -> assertThat(mp3.isPending()).isTrue()) .then(() -> mp.onNext(1)) .then(() -> assertThat(mp3.isPending()).isTrue()) .then(() -> mp2.onNext(2)) .then(() -> { assertThat(mp3.isTerminated()).isTrue(); assertThat(mp3.isSuccess()).isTrue(); assertThat(mp3.isPending()).isFalse(); assertThat(mp3.peek() .getT1()).isEqualTo(1); assertThat(mp3.peek() .getT2()).isEqualTo(2); }) .expectNextMatches(t -> t.getT1() == 1 && t.getT2() == 2) .verifyComplete(); } @Test public void whenMonoProcessor2() { MonoProcessor<Integer> mp = MonoProcessor.create(); MonoProcessor<Integer> mp3 = MonoProcessor.create(); StepVerifier.create(Mono.when(d -> (Integer)d[0], mp) .subscribeWith(mp3)) .then(() -> assertThat(mp3.isPending()).isTrue()) .then(() -> mp.onNext(1)) .then(() -> { assertThat(mp3.isTerminated()).isTrue(); assertThat(mp3.isSuccess()).isTrue(); assertThat(mp3.isPending()).isFalse(); assertThat(mp3.peek()).isEqualTo(1); }) .expectNext(1) .verifyComplete(); } @Test public void whenMonoProcessorRejected() { MonoProcessor<Integer> mp = MonoProcessor.create(); MonoProcessor<Integer> mp2 = MonoProcessor.create(); MonoProcessor<Tuple2<Integer, Integer>> mp3 = MonoProcessor.create(); StepVerifier.create(Mono.when(mp, mp2) .subscribeWith(mp3)) .then(() -> assertThat(mp3.isPending()).isTrue()) .then(() -> mp.onError(new Exception("test"))) .then(() -> { assertThat(mp3.isTerminated()).isTrue(); assertThat(mp3.isSuccess()).isFalse(); assertThat(mp3.isPending()).isFalse(); assertThat(mp3.getError()).hasMessage("test"); }) .verifyErrorMessage("test"); } @Test public void filterMonoProcessor() { MonoProcessor<Integer> mp = MonoProcessor.create(); MonoProcessor<Integer> mp2 = MonoProcessor.create(); StepVerifier.create(mp.filter(s -> s % 2 == 0).subscribeWith(mp2)) .then(() -> mp.onNext(2)) .then(() -> assertThat(mp2.isError()).isFalse()) .then(() -> assertThat(mp2.isSuccess()).isTrue()) .then(() -> assertThat(mp2.peek()).isEqualTo(2)) .then(() -> assertThat(mp2.isTerminated()).isTrue()) .expectNext(2) .verifyComplete(); } @Test public void filterMonoProcessorNot() { MonoProcessor<Integer> mp = MonoProcessor.create(); MonoProcessor<Integer> mp2 = MonoProcessor.create(); StepVerifier.create(mp.filter(s -> s % 2 == 0).subscribeWith(mp2)) .then(() -> mp.onNext(1)) .then(() -> assertThat(mp2.isError()).isFalse()) .then(() -> assertThat(mp2.isSuccess()).isTrue()) .then(() -> assertThat(mp2.peek()).isNull()) .then(() -> assertThat(mp2.isTerminated()).isTrue()) .verifyComplete(); } @Test public void filterMonoProcessorError() { MonoProcessor<Integer> mp = MonoProcessor.create(); MonoProcessor<Integer> mp2 = MonoProcessor.create(); StepVerifier.create(mp.filter(s -> {throw new RuntimeException("test"); }) .subscribeWith (mp2)) .then(() -> mp.onNext(2)) .then(() -> assertThat(mp2.isError()).isTrue()) .then(() -> assertThat(mp2.isSuccess()).isFalse()) .then(() -> assertThat(mp2.getError()).hasMessage("test")) .then(() -> assertThat(mp2.isTerminated()).isTrue()) .verifyErrorMessage("test"); } @Test public void doOnSuccessMonoProcessorError() { MonoProcessor<Integer> mp = MonoProcessor.create(); MonoProcessor<Integer> mp2 = MonoProcessor.create(); AtomicReference<Throwable> ref = new AtomicReference<>(); StepVerifier.create(mp.doOnSuccess(s -> {throw new RuntimeException("test"); }) .doOnError(ref::set) .subscribeWith (mp2)) .then(() -> mp.onNext(2)) .then(() -> assertThat(mp2.isError()).isTrue()) .then(() -> assertThat(ref.get()).hasMessage("test")) .then(() -> assertThat(mp2.isSuccess()).isFalse()) .then(() -> assertThat(mp2.getError()).hasMessage("test")) .then(() -> assertThat(mp2.isTerminated()).isTrue()) .verifyErrorMessage("test"); } @Test public void fluxCancelledByMonoProcessor() { AtomicLong cancelCounter = new AtomicLong(); Flux.range(1, 10) .doOnCancel(cancelCounter::incrementAndGet) .publishNext() .subscribe(); assertThat(cancelCounter.get()).isEqualTo(1); } @Test public void monoNotCancelledByMonoProcessor() { AtomicLong cancelCounter = new AtomicLong(); MonoProcessor<String> monoProcessor = Mono.just("foo") .doOnCancel(cancelCounter::incrementAndGet) .subscribe(); assertThat(cancelCounter.get()).isEqualTo(0); } }