@Test public void equalsIgnoresContext() { Signal<String> next1 = Signal.next("foo"); Signal<String> next2 = Signal.next("foo", Context.of("bar", "baz")); assertThat(next1.getContext().isEmpty()).as("next1 context empty").isTrue(); assertThat(next2.getContext().isEmpty()).as("next2 context not empty").isFalse(); assertThat(next1).isEqualTo(next2); } }
@Test public void nextError() { List<Tuple2<Signal, Context>> signalsAndContext = new ArrayList<>(); Mono.just(0) .map(i -> 10 / i) .doOnEach(s -> signalsAndContext.add(Tuples.of(s,s.getContext()))) .subscriberContext(Context.of("foo", "bar")) .subscribe(); assertThat(signalsAndContext) .hasSize(1) .allSatisfy(t2 -> { assertThat(t2.getT1()) .isNotNull(); assertThat(t2.getT2().getOrDefault("foo", "baz")) .isEqualTo("bar"); }); assertThat(signalsAndContext.stream().map(t2 -> t2.getT1().getType())) .containsExactly(SignalType.ON_ERROR); } }
@Test public void nextComplete() { List<Tuple2<Signal, Context>> signalsAndContext = new ArrayList<>(); Mono.just(1) .hide() .doOnEach(s -> signalsAndContext.add(Tuples.of(s, s.getContext()))) .subscriberContext(Context.of("foo", "bar")) .subscribe(); assertThat(signalsAndContext) .hasSize(2) .allSatisfy(t2 -> { assertThat(t2.getT1()) .isNotNull(); assertThat(t2.getT2().getOrDefault("foo", "baz")) .isEqualTo("bar"); }); assertThat(signalsAndContext.stream().map(t2 -> t2.getT1().getType())) .containsExactly(SignalType.ON_NEXT, SignalType.ON_COMPLETE); }
@Test public void errorStateWithContext(){ Context context = Context.of("foo", "bar"); Signal<Integer> s = Signal.error(e, context); assertThat(s.getContext().isEmpty()).as("has context").isFalse(); assertThat(s.isOnComplete()).isFalse(); assertThat(s.isOnSubscribe()).isFalse(); assertThat(s.hasError()).isTrue(); assertThat(s.hasValue()).isFalse(); assertThat(s).isEqualTo(Signal.error(e)); assertThat(s).isNotEqualTo(Signal.error(new Exception("test2"))); assertThat(s).isNotEqualTo(Signal.complete()); assertThat(s).isNotEqualTo(Signal.subscribe(Operators.emptySubscription())); assertThat(s).isNotEqualTo(Signal.next(1)); assertThat(s.hashCode()).isEqualTo(Signal.error(e).hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.error(new Exception("test2")).hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.complete().hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.next(1).hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.subscribe(Operators.emptySubscription()).hashCode()); assertThat(Signal.isComplete(s)).isFalse(); assertThat(Signal.isError(s)).isTrue(); assertThat(s.getThrowable()).isEqualTo(e); assertThat(s.getType()).isEqualTo(SignalType.ON_ERROR); assertThat(s.toString()).contains("onError"); StepVerifier.create(Flux.<Integer>from(sub -> { sub.onSubscribe(Operators.emptySubscription()); s.accept(sub); })) .verifyErrorMessage("test"); }
@Test public void completeStateWithContext(){ Context context = Context.of("foo", "bar"); Signal<Integer> s = Signal.complete(context); assertThat(s.getContext().isEmpty()).as("has context").isFalse(); assertThat(s.isOnComplete()).isTrue(); assertThat(s.isOnSubscribe()).isFalse(); assertThat(s.hasError()).isFalse(); assertThat(s.hasValue()).isFalse(); assertThat(s).isEqualTo(Signal.complete()); assertThat(s).isNotEqualTo(Signal.error(e)); assertThat(s).isNotEqualTo(Signal.subscribe(Operators.emptySubscription())); assertThat(s).isNotEqualTo(Signal.next(1)); assertThat(s.hashCode()).isEqualTo(Signal.complete().hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.error(e).hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.next(1).hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.subscribe(Operators.emptySubscription()).hashCode()); assertThat(Signal.isComplete(s)).isTrue(); assertThat(Signal.isError(s)).isFalse(); assertThat(s.getType()).isEqualTo(SignalType.ON_COMPLETE); assertThat(s.toString()).contains("onComplete"); StepVerifier.create(Flux.<Integer>from(sub -> { sub.onSubscribe(Operators.emptySubscription()); s.accept(sub); })) .verifyComplete(); }
Signal<Integer> s = Signal.next(1, context); assertThat(s.getContext().isEmpty()).as("has context").isFalse();
@Test public void subscribeStateWithContext(){ Context context = Context.of("foo", "bar"); Signal<Integer> s = Signal.subscribe(Operators.emptySubscription(), context); assertThat(s.getContext().isEmpty()).as("has context").isFalse(); assertThat(s.isOnComplete()).isFalse(); assertThat(s.isOnSubscribe()).isTrue(); assertThat(s.hasError()).isFalse(); assertThat(s.hasValue()).isFalse(); assertThat(s).isEqualTo(Signal.subscribe(Operators.emptySubscription())); assertThat(s).isNotEqualTo(Signal.subscribe(Operators.cancelledSubscription())); assertThat(s).isNotEqualTo(Signal.next(1)); assertThat(s).isNotEqualTo(Signal.error(e)); assertThat(s).isNotEqualTo(Signal.complete()); assertThat(s.hashCode()).isEqualTo(Signal.subscribe(Operators.emptySubscription()).hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.subscribe(Operators.cancelledSubscription()).hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.next(1).hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.error(e).hashCode()); assertThat(s.hashCode()).isNotEqualTo(Signal.complete().hashCode()); assertThat(Signal.isComplete(s)).isFalse(); assertThat(Signal.isError(s)).isFalse(); assertThat(s.getSubscription()).isEqualTo(Operators.emptySubscription()); assertThat(s.getType()).isEqualTo(SignalType.ON_SUBSCRIBE); assertThat(s.toString()).contains("onSubscribe"); StepVerifier.create(Flux.<Integer>from(s::accept)) .expectSubscription() .thenCancel() .verify(); } @Test
@Test public void nextCompleteAndErrorHaveContext() { Context context = Context.of("foo", "bar"); List<Signal> signals = new ArrayList<>(); StepVerifier.create(Flux.just("hello") .doOnEach(signals::add), StepVerifierOptions.create().withInitialContext(context)) .expectNext("hello") .verifyComplete(); assertThat(signals) .allSatisfy(signal -> assertThat(signal.getContext().hasKey("foo")) .as("has Context value") .isTrue()); }
Flux.error(new IllegalStateException("boom")) .doOnEach(sig -> { retriesLeft.add(sig.getContext().get("retriesLeft")); if (!sig.isOnNext()) { contextPerRetry.add(sig.getContext());
Flux.error(new IllegalStateException("boom")) .doOnEach(sig -> { retriesLeft.add(sig.getContext().get("retriesLeft")); if (!sig.isOnNext()) { contextPerRetry.add(sig.getContext());
.doOnEach(sig -> { if (sig.isOnComplete()) { Context ctx = sig.getContext(); contexts.add(ctx); repeats.add("emitted " + ctx.get("emitted") + " elements this attempt, " + ctx.get("repeatsLeft") + " repeats left");
.doOnEach(sig -> { if (sig.isOnComplete()) { Context ctx = sig.getContext(); contexts.add(ctx); repeats.add("emitted " + ctx.get("emitted") + " elements this attempt, " + ctx.get("repeatsLeft") + " repeats left");
@Override public Mono<ClientResponse> filter(ClientRequest clientRequest, ExchangeFunction exchangeFunction) { return exchangeFunction.exchange(clientRequest).doOnEach((signal) -> { if (!signal.isOnComplete()) { Long startTime = signal.getContext().get(METRICS_WEBCLIENT_START_TIME); ClientResponse clientResponse = signal.get(); Throwable throwable = signal.getThrowable(); Iterable<Tag> tags = this.tagProvider.tags(clientRequest, clientResponse, throwable); Timer.builder(this.metricName).tags(tags) .description("Timer of WebClient operation") .register(this.meterRegistry) .record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS); } }).subscriberContext((context) -> context.put(METRICS_WEBCLIENT_START_TIME, System.nanoTime())); }
@Override public Publisher<CoreEvent> apply(Publisher<CoreEvent> publisher) { Flux<CoreEvent> schedulerTrackingPublisher = from(publisher) .doOnEach(signal -> signal.getContext().getOrEmpty(PROCESSOR_SCHEDULER_CONTEXT_KEY) .ifPresent(sch -> schedulers.add(((Scheduler) sch).getName()))); if (getProcessingType() == CPU_LITE_ASYNC) { return from(schedulerTrackingPublisher).transform(processorPublisher -> Processor.super.apply(schedulerTrackingPublisher)) .publishOn(fromExecutorService(custom)).onErrorStop(); } else { return Processor.super.apply(schedulerTrackingPublisher); } }
/** * Intended for use with Flux.doOnEach, this method allows processing * on a item (e.g., logging) to be done with MDC set on the * thread. * @param consumer the action to be performed on the emitted item * @param <R> The item type * @return a signal consumer to be passed to Flux.doOnEach */ public static <R> Consumer<Signal<R>> wrapForItem(Consumer<R> consumer) { return signal -> { if (signal.isOnNext()) { wrapCall(signal.getContext(), () -> { consumer.accept(signal.get()); return null; }); } }; }
private Mono<Void> applyWebsocketHandler(HttpClientWSOperations ops, Mono<Void> handshake, BiFunction<? super WebsocketInbound, ? super WebsocketOutbound, ? extends Publisher<Void>> websocketHandler) { if (websocketHandler != noopHandler()) { handshake = handshake.doOnEach(signal -> { if(!signal.hasError()) { websocketHandler.apply(ops, ops) .subscribe(new WebsocketSubscriber(ops, signal.getContext())); } }); } return handshake; }
final Mono<Void> withWebsocketSupport(String url, @Nullable String protocols, int maxFramePayloadLength, BiFunction<? super WebsocketInbound, ? super WebsocketOutbound, ? extends Publisher<Void>> websocketHandler) { Objects.requireNonNull(websocketHandler, "websocketHandler"); if (markSentHeaders()) { WebsocketServerOperations ops = new WebsocketServerOperations(url, protocols, maxFramePayloadLength, this); if (rebind(ops)) { return FutureMono.from(ops.handshakerResult) .doOnEach(signal -> { if(!signal.hasError() && (protocols == null || ops.selectedSubprotocol() != null)) { websocketHandler.apply(ops, ops) .subscribe(new WebsocketSubscriber(ops, signal.getContext())); } }); } } else { log.error(format(channel(), "Cannot enable websocket if headers have already been sent")); } return Mono.error(new IllegalStateException("Failed to upgrade to websocket")); }
final Mono<Void> withWebsocketSupport(String url, @Nullable String protocols, int maxFramePayloadLength, BiFunction<? super WebsocketInbound, ? super WebsocketOutbound, ? extends Publisher<Void>> websocketHandler) { Objects.requireNonNull(websocketHandler, "websocketHandler"); if (markSentHeaders()) { WebsocketServerOperations ops = new WebsocketServerOperations(url, protocols, maxFramePayloadLength, this); if (rebind(ops)) { return FutureMono.from(ops.handshakerResult) .doOnEach(signal -> { if(!signal.hasError() && (protocols == null || ops.selectedSubprotocol() != null)) { websocketHandler.apply(ops, ops) .subscribe(new WebsocketSubscriber(ops, signal.getContext())); } }); } } else { log.error(format(channel(), "Cannot enable websocket if headers have already been sent")); } return Mono.error(new IllegalStateException("Failed to upgrade to websocket")); }
final Mono<Void> withWebsocketSupport(String url, String protocols, BiFunction<? super WebsocketInbound, ? super WebsocketOutbound, ? extends Publisher<Void>> websocketHandler) { Objects.requireNonNull(websocketHandler, "websocketHandler"); if (markSentHeaders()) { HttpServerWSOperations ops = new HttpServerWSOperations(url, protocols, this); if (replace(ops)) { return FutureMono.from(ops.handshakerResult) .doOnEach(signal -> { if(!signal.hasError()) { websocketHandler.apply(ops, ops) .subscribe(new WebsocketSubscriber(ops, signal.getContext())); } }); } } else { log.error(format(channel(), "Cannot enable websocket if headers have already been sent")); } return Mono.error(new IllegalStateException("Failed to upgrade to websocket")); }