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

reactor.test.subscriber.TestSubscriberBuilder Maven / Gradle / Ivy

There is a newer version: 3.7.0
Show newest version
/*
 * Copyright (c) 2021 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.subscriber;

import java.util.function.Predicate;

import org.reactivestreams.Subscription;

import reactor.core.Fuseable;
import reactor.util.context.Context;
import reactor.util.context.ContextView;

/**
 * A configuration builder used to create a fine-tuned {@link TestSubscriber}, also
 * allowing for a {@link reactor.core.Fuseable.ConditionalSubscriber} variant.
 * Notably, it allows the created instance to enforce fusion compatibility
 * (by assuming a {@link Fuseable} source publisher and expecting a
 * {@link reactor.core.Fuseable.QueueSubscription}).
 * 

* See {@link TestSubscriber#builder()} to obtain a new builder. *

* Note that all methods mutate the builder configuration, so reuse is discouraged. * * @author Simon Baslé */ public final class TestSubscriberBuilder { long initialRequest; Context context; TestSubscriber.FusionRequirement fusionRequirement; int requestedFusionMode; int expectedFusionMode; TestSubscriberBuilder() { this.initialRequest = Long.MAX_VALUE; this.context = Context.empty(); this.fusionRequirement = TestSubscriber.FusionRequirement.NONE; this.requestedFusionMode = Fuseable.NONE; this.expectedFusionMode = Fuseable.NONE; } /** * Enrich the {@link Context} with a single entry. * * @param key the key to put/set in the {@link Context} of the future {@link TestSubscriber} * @param value the value to associate with the key * @return this builder, mutated to have the key/value pair added to the {@link Context} */ public TestSubscriberBuilder contextPut(Object key, Object value) { this.context = context.put(key, value); return this; } /** * Enrich the {@link Context} by putting all entries of the given {@link ContextView} in it. * * @param toAdd the {@link ContextView} to add to the {@link Context} of the future {@link TestSubscriber} * @return this builder, mutated to have all {@link ContextView}'s key/value pairs added to the {@link Context} */ public TestSubscriberBuilder contextPutAll(ContextView toAdd) { this.context = context.putAll(toAdd); return this; } /** * Set the request to be made upon receiving the {@link org.reactivestreams.Subscription} * in {@link org.reactivestreams.Subscriber#onSubscribe(Subscription)}. Default is {@link Long#MAX_VALUE}. * * @param initialRequest the request to be made at subscription * @return this builder, mutated to reflect the new request to be made at subscription */ public TestSubscriberBuilder initialRequest(long initialRequest) { this.initialRequest = initialRequest; return this; } /** * Set the request to be made upon receiving the {@link org.reactivestreams.Subscription} * in {@link org.reactivestreams.Subscriber#onSubscribe(Subscription)} to be an * unbounded request, ie. {@link Long#MAX_VALUE}. * * @return this builder, mutated to reflect an unbounded request is to be made at subscription */ public TestSubscriberBuilder initialRequestUnbounded() { this.initialRequest = Long.MAX_VALUE; return this; } /** * Expect fusion to be possible with the {@link TestSubscriber}, with {@link Fuseable#NONE}) being a special case. * Fusion will be negotiated at subscription, enforcing the need for a {@link reactor.core.Fuseable.QueueSubscription} to be passed. * Furthermore, the fusion mode returned from the negotiation with the {@link reactor.core.Fuseable.QueueSubscription} * is expected to be the same as the provided mode. *

* Use {@code requireFusion(Fuseable.NONE)} to remove any previously fusion requirement, as well as * removing type enforcement on the subscription (a vanilla {@link Subscription} becomes acceptable). * Use {@link #requireNotFuseable()} to strictly enforce that the {@link Subscription} MUST NOT be a {@link reactor.core.Fuseable.QueueSubscription}. * * @param exactMode the requested fusion mode, expected in return from the negotiation with the {@link reactor.core.Fuseable.QueueSubscription} * @return this builder, mutated to require fusion with the given mode */ public TestSubscriberBuilder requireFusion(int exactMode) { return requireFusion(exactMode, exactMode); } /** * Expect fusion to be possible with the {@link TestSubscriber}, with both parameters set to {@link Fuseable#NONE} being a special case. * Fusion will be negotiated at subscription, enforcing the need for a {@link reactor.core.Fuseable.QueueSubscription} to be passed. * Furthermore, the {@code negotiatedMode} is expected to be negotiated by the subscription * in response to requesting {@code requestedMode}. *

* Use {@code requireFusion(Fuseable.NONE, Fuseable.NONE)} to remove any previously fusion requirement, as well as * removing type enforcement on the subscription (a vanilla {@link Subscription} becomes acceptable). * Use {@link #requireNotFuseable()} to strictly enforce that the {@link Subscription} MUST NOT be a {@link reactor.core.Fuseable.QueueSubscription}. * * @param requestedMode the fusion mode requested to the {@link reactor.core.Fuseable.QueueSubscription} * @param negotiatedMode the fusion mode expected from the negotiation with the {@link reactor.core.Fuseable.QueueSubscription} * @return this builder, mutated to require fusion with the given negotiated mode (in response to the given requested mode) */ public TestSubscriberBuilder requireFusion(int requestedMode, int negotiatedMode) { if (requestedMode == negotiatedMode && negotiatedMode == Fuseable.NONE) { this.fusionRequirement = TestSubscriber.FusionRequirement.NONE; } else { this.fusionRequirement = TestSubscriber.FusionRequirement.FUSEABLE; } this.requestedFusionMode = requestedMode; this.expectedFusionMode = negotiatedMode; return this; } /** * Enforce that the {@link Subscription} passed to the {@link TestSubscriber} isn't a {@link reactor.core.Fuseable.QueueSubscription}. * This is stricter than {@code requireFusion(Fuseable.NONE, Fuseable.NONE)}, which merely disables fusion but still accepts * the incoming subscription to be a QueueSubscription. * * @return this builder, mutated to reject all {@link reactor.core.Fuseable.QueueSubscription} */ public TestSubscriberBuilder requireNotFuseable() { this.fusionRequirement = TestSubscriber.FusionRequirement.NOT_FUSEABLE; this.requestedFusionMode = Fuseable.NONE; this.expectedFusionMode = Fuseable.NONE; return this; } /** * Create a {@link reactor.core.Fuseable.ConditionalSubscriber} variant of {@link TestSubscriber} according * to this builder. * The provided {@link Predicate} will be used as the implementation * of {@link reactor.core.Fuseable.ConditionalSubscriber#tryOnNext(Object)}. * * @param tryOnNext the {@link Predicate} to use as the {@link reactor.core.Fuseable.ConditionalSubscriber#tryOnNext tryOnNext} implementation * @param the type of elements received by the {@link TestSubscriber}, defined by the predicate * @return a {@link ConditionalTestSubscriber} */ public ConditionalTestSubscriber buildConditional(Predicate tryOnNext) { return new DefaultConditionalTestSubscriber(this, tryOnNext); } /** * Create a {@link TestSubscriber} according to this builder. * * @param the type of elements to be received by the subscriber * @return a new plain {@link TestSubscriber} */ public TestSubscriber build() { return new DefaultTestSubscriber<>(this); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy