/*
* Copyright 2002-2016 the original author or authors.
*
* 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 org.springframework.core.convert.support;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import org.junit.Before;
import org.junit.Test;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxProcessor;
import reactor.core.publisher.Mono;
import rx.Completable;
import rx.Observable;
import rx.Single;
import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ReactiveTypeDescriptor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* Unit tests for {@link ReactiveAdapterRegistry}.
* @author Rossen Stoyanchev
*/
@SuppressWarnings("unchecked")
public class ReactiveAdapterRegistryTests {
private ReactiveAdapterRegistry registry;
@Before
public void setUp() throws Exception {
this.registry = new ReactiveAdapterRegistry();
}
@Test
public void defaultAdapterRegistrations() throws Exception {
// Reactor
assertNotNull(getAdapter(Mono.class));
assertNotNull(getAdapter(Flux.class));
// Publisher
assertNotNull(getAdapter(Publisher.class));
// Completable
assertNotNull(getAdapter(CompletableFuture.class));
// RxJava 1
assertNotNull(getAdapter(Observable.class));
assertNotNull(getAdapter(Single.class));
assertNotNull(getAdapter(Completable.class));
// RxJava 2
assertNotNull(getAdapter(Flowable.class));
assertNotNull(getAdapter(io.reactivex.Observable.class));
assertNotNull(getAdapter(io.reactivex.Single.class));
assertNotNull(getAdapter(Maybe.class));
assertNotNull(getAdapter(io.reactivex.Completable.class));
}
@Test
public void getAdapterForReactiveSubType() throws Exception {
ReactiveAdapter adapter1 = getAdapter(Flux.class);
ReactiveAdapter adapter2 = getAdapter(FluxProcessor.class);
assertSame(adapter1, adapter2);
this.registry.registerReactiveType(
ReactiveTypeDescriptor.multiValue(FluxProcessor.class, FluxProcessor::empty),
o -> (FluxProcessor<?, ?>) o,
FluxProcessor::from);
ReactiveAdapter adapter3 = getAdapter(FluxProcessor.class);
assertNotNull(adapter3);
assertNotSame(adapter1, adapter3);
}
@Test
public void publisherToFlux() throws Exception {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Publisher<Integer> source = Flowable.fromIterable(sequence);
Object target = getAdapter(Flux.class).fromPublisher(source);
assertTrue(target instanceof Flux);
assertEquals(sequence, ((Flux<Integer>) target).collectList().block(Duration.ofMillis(1000)));
}
// TODO: publisherToMono/CompletableFuture vs Single (ISE on multiple elements)?
@Test
public void publisherToMono() throws Exception {
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
Object target = getAdapter(Mono.class).fromPublisher(source);
assertTrue(target instanceof Mono);
assertEquals(new Integer(1), ((Mono<Integer>) target).block(Duration.ofMillis(1000)));
}
@Test
public void publisherToCompletableFuture() throws Exception {
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
Object target = getAdapter(CompletableFuture.class).fromPublisher(source);
assertTrue(target instanceof CompletableFuture);
assertEquals(new Integer(1), ((CompletableFuture<Integer>) target).get());
}
@Test
public void publisherToRxObservable() throws Exception {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Publisher<Integer> source = Flowable.fromIterable(sequence);
Object target = getAdapter(rx.Observable.class).fromPublisher(source);
assertTrue(target instanceof rx.Observable);
assertEquals(sequence, ((rx.Observable) target).toList().toBlocking().first());
}
@Test
public void publisherToRxSingle() throws Exception {
Publisher<Integer> source = Flowable.fromArray(1);
Object target = getAdapter(rx.Single.class).fromPublisher(source);
assertTrue(target instanceof rx.Single);
assertEquals(new Integer(1), ((rx.Single<Integer>) target).toBlocking().value());
}
@Test
public void publisherToRxCompletable() throws Exception {
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
Object target = getAdapter(rx.Completable.class).fromPublisher(source);
assertTrue(target instanceof rx.Completable);
assertNull(((rx.Completable) target).get());
}
@Test
public void publisherToReactivexFlowable() throws Exception {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Publisher<Integer> source = Flux.fromIterable(sequence);
Object target = getAdapter(io.reactivex.Flowable.class).fromPublisher(source);
assertTrue(target instanceof io.reactivex.Flowable);
assertEquals(sequence, ((io.reactivex.Flowable) target).toList().blockingGet());
}
@Test
public void publisherToReactivexObservable() throws Exception {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Publisher<Integer> source = Flowable.fromIterable(sequence);
Object target = getAdapter(io.reactivex.Observable.class).fromPublisher(source);
assertTrue(target instanceof io.reactivex.Observable);
assertEquals(sequence, ((io.reactivex.Observable) target).toList().blockingGet());
}
@Test
public void publisherToReactivexSingle() throws Exception {
Publisher<Integer> source = Flowable.fromArray(1);
Object target = getAdapter(io.reactivex.Single.class).fromPublisher(source);
assertTrue(target instanceof io.reactivex.Single);
assertEquals(new Integer(1), ((io.reactivex.Single<Integer>) target).blockingGet());
}
@Test
public void publisherToReactivexCompletable() throws Exception {
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
Object target = getAdapter(io.reactivex.Completable.class).fromPublisher(source);
assertTrue(target instanceof io.reactivex.Completable);
assertNull(((io.reactivex.Completable) target).blockingGet());
}
@Test
public void rxObservableToPublisher() throws Exception {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Object source = rx.Observable.from(sequence);
Object target = getAdapter(rx.Observable.class).toPublisher(source);
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
assertEquals(sequence, ((Flux<Integer>) target).collectList().block(Duration.ofMillis(1000)));
}
@Test
public void rxSingleToPublisher() throws Exception {
Object source = rx.Single.just(1);
Object target = getAdapter(rx.Single.class).toPublisher(source);
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
assertEquals(new Integer(1), ((Mono<Integer>) target).block(Duration.ofMillis(1000)));
}
@Test
public void rxCompletableToPublisher() throws Exception {
Object source = rx.Completable.complete();
Object target = getAdapter(rx.Completable.class).toPublisher(source);
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
((Mono<Void>) target).block(Duration.ofMillis(1000));
}
@Test
public void reactivexFlowableToPublisher() throws Exception {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Object source = io.reactivex.Flowable.fromIterable(sequence);
Object target = getAdapter(io.reactivex.Flowable.class).toPublisher(source);
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
assertEquals(sequence, ((Flux<Integer>) target).collectList().block(Duration.ofMillis(1000)));
}
@Test
public void reactivexObservableToPublisher() throws Exception {
List<Integer> sequence = Arrays.asList(1, 2, 3);
Object source = io.reactivex.Observable.fromIterable(sequence);
Object target = getAdapter(io.reactivex.Observable.class).toPublisher(source);
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
assertEquals(sequence, ((Flux<Integer>) target).collectList().block(Duration.ofMillis(1000)));
}
@Test
public void reactivexSingleToPublisher() throws Exception {
Object source = io.reactivex.Single.just(1);
Object target = getAdapter(io.reactivex.Single.class).toPublisher(source);
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
assertEquals(new Integer(1), ((Mono<Integer>) target).block(Duration.ofMillis(1000)));
}
@Test
public void reactivexCompletableToPublisher() throws Exception {
Object source = io.reactivex.Completable.complete();
Object target = getAdapter(io.reactivex.Completable.class).toPublisher(source);
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
((Mono<Void>) target).block(Duration.ofMillis(1000));
}
@Test
public void CompletableFutureToPublisher() throws Exception {
CompletableFuture<Integer> future = new CompletableFuture();
future.complete(1);
Object target = getAdapter(CompletableFuture.class).toPublisher(future);
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
assertEquals(new Integer(1), ((Mono<Integer>) target).block(Duration.ofMillis(1000)));
}
private ReactiveAdapter getAdapter(Class<?> reactiveType) {
return this.registry.getAdapter(reactiveType);
}
}