/* * Copyright (c) 2011-2016 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.util.Arrays; import java.util.function.BiFunction; import java.util.function.Function; import org.junit.Test; import reactor.test.subscriber.AssertSubscriber; public class FluxGroupJoinTest { final BiFunction<Integer, Flux<Integer>, Flux<Integer>> add2 = (t1, t2s) -> t2s.map(t2 -> t1 + t2); Function<Integer, Flux<Integer>> just(final Flux<Integer> publisher) { return t1 -> publisher; } <T, R> Function<T, Flux<R>> just2(final Flux<R> publisher) { return t1 -> publisher; } @Test public void behaveAsJoin() { AssertSubscriber<Object> ts = AssertSubscriber.create(); DirectProcessor<Integer> source1 = DirectProcessor.create(); DirectProcessor<Integer> source2 = DirectProcessor.create(); Flux<Integer> m = source1.groupJoin(source2, just(Flux.never()), just(Flux.never()), add2) .flatMap(t -> t); m.subscribe(ts); source1.onNext(1); source1.onNext(2); source1.onNext(4); source2.onNext(16); source2.onNext(32); source2.onNext(64); source1.onComplete(); source2.onComplete(); ts.assertValues(17, 18, 20, 33, 34, 36, 65, 66, 68) .assertComplete() .assertNoError(); } class Person { final int id; final String name; public Person(int id, String name) { this.id = id; this.name = name; } } class PersonFruit { final int personId; final String fruit; public PersonFruit(int personId, String fruit) { this.personId = personId; this.fruit = fruit; } } class PPF { final Person person; final Flux<PersonFruit> fruits; public PPF(Person person, Flux<PersonFruit> fruits) { this.person = person; this.fruits = fruits; } } @Test public void normal1() { AssertSubscriber<Object> ts = AssertSubscriber.create(); Flux<Person> source1 = Flux.fromIterable(Arrays.asList(new Person(1, "Joe"), new Person(2, "Mike"), new Person(3, "Charlie"))); Flux<PersonFruit> source2 = Flux.fromIterable(Arrays.asList(new PersonFruit(1, "Strawberry"), new PersonFruit(1, "Apple"), new PersonFruit(3, "Peach"))); Mono<PPF> q = source1.groupJoin(source2, just2(Flux.never()), just2(Flux.never()), PPF::new) .doOnNext(ppf -> ppf.fruits.filter(t1 -> ppf.person.id == t1.personId) .subscribe(t1 -> ts.onNext(Arrays.asList( ppf.person.name, t1.fruit)))) .ignoreElements(); q.subscribe(ts); ts.assertValues(Arrays.asList("Joe", "Strawberry"), Arrays.asList("Joe", "Apple"), Arrays.asList("Charlie", "Peach")) .assertComplete() .assertNoError(); } @Test public void leftThrows() { AssertSubscriber<Object> ts = AssertSubscriber.create(); DirectProcessor<Integer> source1 = DirectProcessor.create(); DirectProcessor<Integer> source2 = DirectProcessor.create(); Flux<Flux<Integer>> m = source1.groupJoin(source2, just(Flux.never()), just(Flux.never()), add2); m.subscribe(ts); source2.onNext(1); source1.onError(new RuntimeException("Forced failure")); ts.assertErrorMessage("Forced failure") .assertNotComplete() .assertNoValues(); } @Test public void rightThrows() { AssertSubscriber<Object> ts = AssertSubscriber.create(); DirectProcessor<Integer> source1 = DirectProcessor.create(); DirectProcessor<Integer> source2 = DirectProcessor.create(); Flux<Flux<Integer>> m = source1.groupJoin(source2, just(Flux.never()), just(Flux.never()), add2); m.subscribe(ts); source1.onNext(1); source2.onError(new RuntimeException("Forced failure")); ts.assertErrorMessage("Forced failure") .assertNotComplete() .assertValueCount(1); } @Test public void leftDurationThrows() { AssertSubscriber<Object> ts = AssertSubscriber.create(); DirectProcessor<Integer> source1 = DirectProcessor.create(); DirectProcessor<Integer> source2 = DirectProcessor.create(); Flux<Integer> duration1 = Flux.error(new RuntimeException("Forced failure")); Flux<Flux<Integer>> m = source1.groupJoin(source2, just(duration1), just(Flux.never()), add2); m.subscribe(ts); source1.onNext(1); ts.assertErrorMessage("Forced failure") .assertNotComplete() .assertNoValues(); } @Test public void rightDurationThrows() { AssertSubscriber<Object> ts = AssertSubscriber.create(); DirectProcessor<Integer> source1 = DirectProcessor.create(); DirectProcessor<Integer> source2 = DirectProcessor.create(); Flux<Integer> duration1 = Flux.error(new RuntimeException("Forced failure")); Flux<Flux<Integer>> m = source1.groupJoin(source2, just(Flux.never()), just(duration1), add2); m.subscribe(ts); source2.onNext(1); ts.assertErrorMessage("Forced failure") .assertNotComplete() .assertNoValues(); } @Test public void leftDurationSelectorThrows() { AssertSubscriber<Object> ts = AssertSubscriber.create(); DirectProcessor<Integer> source1 = DirectProcessor.create(); DirectProcessor<Integer> source2 = DirectProcessor.create(); Function<Integer, Flux<Integer>> fail = t1 -> { throw new RuntimeException("Forced failure"); }; Flux<Flux<Integer>> m = source1.groupJoin(source2, fail, just(Flux.never()), add2); m.subscribe(ts); source1.onNext(1); ts.assertErrorMessage("Forced failure") .assertNotComplete() .assertNoValues(); } @Test public void rightDurationSelectorThrows() { AssertSubscriber<Object> ts = AssertSubscriber.create(); DirectProcessor<Integer> source1 = DirectProcessor.create(); DirectProcessor<Integer> source2 = DirectProcessor.create(); Function<Integer, Flux<Integer>> fail = t1 -> { throw new RuntimeException("Forced failure"); }; Flux<Flux<Integer>> m = source1.groupJoin(source2, just(Flux.never()), fail, add2); m.subscribe(ts); source2.onNext(1); ts.assertErrorMessage("Forced failure") .assertNotComplete() .assertNoValues(); } @Test public void resultSelectorThrows() { AssertSubscriber<Object> ts = AssertSubscriber.create(); DirectProcessor<Integer> source1 = DirectProcessor.create(); DirectProcessor<Integer> source2 = DirectProcessor.create(); BiFunction<Integer, Flux<Integer>, Integer> fail = (t1, t2) -> { throw new RuntimeException("Forced failure"); }; Flux<Integer> m = source1.groupJoin(source2, just(Flux.never()), just(Flux.never()), fail); m.subscribe(ts); source1.onNext(1); source2.onNext(2); ts.assertErrorMessage("Forced failure") .assertNotComplete() .assertNoValues(); } }