All Downloads are FREE. Search and download functionalities are using the official Maven repository.

reactor.test.publisher.TestPublisher Maven / Gradle / Ivy

There is a newer version: 3.7.0
Show newest version
/*
 * Copyright (c) 2017-2022 VMware Inc. or its affiliates, 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
 *
 *   https://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.test.publisher;

import java.util.EnumSet;
import java.util.Objects;

import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.annotation.Nullable;

/**
 * A {@link Publisher} that you can directly manipulate, triggering
 * {@link #next(Object) onNext}, {@link #complete() onComplete} and
 * {@link #error(Throwable) onError} events, for testing purposes.
 * You can assert the state of the publisher using its {@code assertXXX} methods,
 * usually inside a {@link reactor.test.StepVerifier}'s
 * {@link reactor.test.StepVerifier.Step#then(Runnable) then} callback.
 * 

* The TestPublisher can also be made more lenient towards the RS spec * and allow "spec violations", as enumerated in {@link Violation}. Use the * {@link #createNoncompliant(Violation, Violation...)} factory method to create such * a misbehaving publisher. *

* TestPublisher are generally hot, directly propagating signals to currently subscribed * downstreams and only replaying the first termination signal to subsequent subscribers. * TestPublishers are also generally not safe to use from multiple parallel threads. * * @author Simon Basle */ public abstract class TestPublisher implements Publisher, PublisherProbe { /** * Create a standard hot {@link TestPublisher}. * * @param the type of the publisher * @return the new {@link TestPublisher} */ public static TestPublisher create() { return new DefaultTestPublisher<>(); } /** * Create a {@link Violation noncompliant} hot {@link TestPublisher} * with a given set of reactive streams spec violations that will be overlooked. * * @param first the first allowed {@link Violation} * @param rest additional optional violations * @param the type of the publisher * @return the new noncompliant {@link TestPublisher} */ public static TestPublisher createNoncompliant(Violation first, Violation... rest) { return new DefaultTestPublisher<>(first, rest); } /** * Create a cold {@link TestPublisher}, which can be subscribed to by multiple * subscribers. It buffers the {@link #next(Object)} events and tracks how many * elements have been seen by each subscriber in order to correctly replay the * buffer. *

* The publisher honors backpressure, holding off emitting newest items * from the buffer if the subscriber doesn't have enough request. * * @param the type of the publisher * @return the new {@link TestPublisher} */ public static TestPublisher createCold() { return new ColdTestPublisher<>(false, EnumSet.noneOf(Violation.class)); } /** * Create a cold {@link TestPublisher}, which can be subscribed to by multiple * subscribers. It buffers the {@link #next(Object)} events and tracks how many * elements have been seen by each subscriber in order to correctly replay the * buffer. *

* The returned publisher will emit an overflow error if a new subscriber's * first request is lower than the current buffer size, or if a new element * is pushed to a registered subscriber that has zero pending demand. * * @param the type of the publisher * @return the new {@link TestPublisher} */ public static TestPublisher createColdNonBuffering() { return new ColdTestPublisher<>(true, EnumSet.noneOf(Violation.class)); } /** * Create a cold {@link TestPublisher}, which can be subscribed to by multiple * subscribers. It buffers the {@link #next(Object)} events and tracks how many * elements have been seen by each subscriber in order to correctly replay the * buffer. *

* The returned publisher will be non-compliant to the spec according to one or more {@link Violation}s. In addition, * its behavior when there is more data than {@link Subscription#request(long) requested} can be set via {@code errorOnOverflow}. * * @param the type of the publisher * @param errorOnOverflow whether to throw an exception if there are more values than request (true) or buffer values until request becomes available (false) * @return the new {@link TestPublisher} */ public static TestPublisher createColdNonCompliant(boolean errorOnOverflow, Violation firstViolation, Violation... otherViolations) { return new ColdTestPublisher<>(errorOnOverflow, EnumSet.of(firstViolation, otherViolations)); } /** * Convenience method to wrap this {@link TestPublisher} to a {@link Flux}. */ public abstract Flux flux(); /** * Convenience method to wrap this {@link TestPublisher} to a {@link Mono}. */ public abstract Mono mono(); /** * Assert that the current minimum request of all this publisher's subscribers * is >= {@code n}. * * @param n the expected minimum request * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher assertMinRequested(long n); /** * Assert that the current maximum request of all this publisher's subscribers * is <= {@code n}. Can be {@link Long#MAX_VALUE} in case a subscriber has made * an unbounded request. * * @param n the expected maximum request including {@link Long#MAX_VALUE} * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher assertMaxRequested(long n); /** * Asserts that this publisher has subscribers. * * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher assertSubscribers(); /** * Asserts that this publisher has exactly n subscribers. * * @param n the expected number of subscribers * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher assertSubscribers(int n); /** * Asserts that this publisher has no subscribers. * * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher assertNoSubscribers(); /** * Asserts that this publisher has had at least one subscriber that has been cancelled. * * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher assertCancelled(); /** * Asserts that this publisher has had at least n subscribers that have been cancelled. * * @param n the expected number of subscribers to have been cancelled. * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher assertCancelled(int n); /** * Asserts that this publisher has had no cancelled subscribers. * * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher assertNotCancelled(); /** * Asserts that this publisher has had subscriber that saw request overflow, * that is received an onNext event despite having a requested amount of 0 at * the time. * * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher assertRequestOverflow(); /** * Asserts that this publisher has had no subscriber with request overflow. * Request overflow is receiving an onNext event despite having a requested amount * of 0 at that time. * * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher assertNoRequestOverflow(); /** * Send 1 {@link Subscriber#onNext(Object) onNext} signal to the subscribers. * * @param value the item to emit (can be null if the relevant {@link Violation} is set) * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher next(@Nullable T value); /** * Triggers an {@link Subscriber#onError(Throwable) error} signal to the subscribers. * * @param t the {@link Throwable} to trigger * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher error(Throwable t); /** * Triggers {@link Subscriber#onComplete() completion} of this publisher. * * @return this {@link TestPublisher} for chaining. */ public abstract TestPublisher complete(); /** * Send 1-n {@link Subscriber#onNext(Object) onNext} signals to the subscribers. * * @param first the first item to emit * @param rest the optional remaining items to emit * @return this {@link TestPublisher} for chaining. * @see #next(Object) next */ @SafeVarargs public final TestPublisher next(@Nullable T first, T... rest) { Objects.requireNonNull(rest, "rest array is null, please cast to T if null T required"); next(first); for (T t : rest) { next(t); } return this; } /** * Combine emitting items and completing this publisher. * * @param values the values to emit to subscribers * @return this {@link TestPublisher} for chaining. * @see #next(Object) next * @see #complete() complete */ @SafeVarargs public final TestPublisher emit(T... values) { Objects.requireNonNull(values, "values array is null, please cast to T if null T required"); for (T t : values) { next(t); } return complete(); } /** * Possible misbehavior for a {@link TestPublisher}. */ public enum Violation { /** * Allow {@link TestPublisher#next(Object, Object[]) next} calls to be made * despite insufficient request, without triggering an {@link IllegalStateException}. */ REQUEST_OVERFLOW, /** * Allow {@link TestPublisher#next(Object, Object[]) next} calls to be made * with a {@code null} value without triggering a {@link NullPointerException} */ ALLOW_NULL, /** * Allow termination signals to be sent several times in a row. This includes * {@link TestPublisher#complete()}, {@link TestPublisher#error(Throwable)} and * {@link TestPublisher#emit(Object[])}. */ CLEANUP_ON_TERMINATE, /** * Allow the {@link TestPublisher} to ignore cancellation signals and continue * emitting signals as if the cancellation lost race against said signals. */ DEFER_CANCELLATION } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy