@Override public void accept(SynchronousSink<DataBuffer> sink) { boolean release = true; DataBuffer dataBuffer = this.dataBufferFactory.allocateBuffer(this.bufferSize); try { int read; ByteBuffer byteBuffer = dataBuffer.asByteBuffer(0, dataBuffer.capacity()); if ((read = this.channel.read(byteBuffer)) >= 0) { dataBuffer.writePosition(read); release = false; sink.next(dataBuffer); } else { sink.complete(); } } catch (IOException ex) { sink.error(ex); } finally { if (release) { release(dataBuffer); } } } }
@Test public void nextAfterErrorFused() { StepVerifier.create(Flux.just(1) .handle((v, sink) -> { sink.error(new NullPointerException("boom")); sink.next(2); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot emit after a complete or error")); }
@Test public void completeAfterErrorFused() { StepVerifier.create(Flux.just(1) .handle((v, sink) -> { sink.error(new NullPointerException("boom")); sink.complete(); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot complete after a complete or error")); }
@Test public void errorAfterMultipleItems() throws Exception { IllegalStateException error = new IllegalStateException("boo"); Flux<String> publisher = Flux.generate(() -> 0, (idx , subscriber) -> { int i = ++idx; subscriber.next(String.valueOf(i)); if (i == 3) { subscriber.error(error); } return i; }); Mono<Void> completion = publisher.as(this::sendOperator); Signal<Void> signal = completion.materialize().block(); assertNotNull(signal); assertSame("Unexpected signal: " + signal, error, signal.getThrowable()); assertEquals(3, this.writer.items.size()); assertEquals("1", this.writer.items.get(0)); assertEquals("2", this.writer.items.get(1)); assertEquals("3", this.writer.items.get(2)); assertSame(error, this.writer.error); }
@Test public void errorAfterCompleteFused() { StepVerifier.create(Flux.just(1) .handle((v, sink) -> { sink.complete(); sink.error(new NullPointerException("boom")); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot error after a complete or error")); }
@Override public void accept(SynchronousSink<DataBuffer> sink) { boolean release = true; DataBuffer dataBuffer = this.dataBufferFactory.allocateBuffer(this.bufferSize); try { int read; ByteBuffer byteBuffer = dataBuffer.asByteBuffer(0, dataBuffer.capacity()); if ((read = this.channel.read(byteBuffer)) >= 0) { dataBuffer.writePosition(read); release = false; sink.next(dataBuffer); } else { sink.complete(); } } catch (IOException ex) { sink.error(ex); } finally { if (release) { release(dataBuffer); } } } }
@Test public void generatorMultipleOnErrors() { AssertSubscriber<Integer> ts = AssertSubscriber.create(); Flux.<Integer>generate(o -> { o.error(new RuntimeException("forced failure")); o.error(new RuntimeException("forced failure")); }).subscribe(ts); ts.assertNoValues() .assertNotComplete() .assertError(RuntimeException.class) .assertErrorMessage("forced failure"); }
@Test public void nextAfterErrorFusedConditional() { StepVerifier.create(Flux.just(1) .filter(i -> true) .handle((v, sink) -> { sink.error(new NullPointerException("boom")); sink.next(2); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot emit after a complete or error")); }
@Test public void completeAfterErrorFusedConditional() { StepVerifier.create(Flux.just(1) .filter(i -> true) .handle((v, sink) -> { sink.error(new NullPointerException("boom")); sink.complete(); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot complete after a complete or error")); }
@Test public void nextAfterErrorNormal() { StepVerifier.create(Flux.just(1) .hide() .handle((v, sink) -> { sink.error(new NullPointerException("boom")); sink.next(2); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot emit after a complete or error")); }
@Test public void errorAfterCompleteNormal() { StepVerifier.create(Flux.just(1) .hide() .handle((v, sink) -> { sink.complete(); sink.error(new NullPointerException("boom")); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot error after a complete or error")); }
@Test public void errorAfterCompleteFusedConditional() { StepVerifier.create(Flux.just(1) .filter(i -> true) .handle((v, sink) -> { sink.complete(); sink.error(new NullPointerException("boom")); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot error after a complete or error")); }
@Test public void completeAfterErrorNormal() { StepVerifier.create(Flux.just(1) .hide() .handle((v, sink) -> { sink.error(new NullPointerException("boom")); sink.complete(); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot complete after a complete or error")); }
@Test public void errorAfterCompleteNormalConditional() { StepVerifier.create(Flux.just(1) .hide() .filter(i -> true) .handle((v, sink) -> { sink.complete(); sink.error(new NullPointerException("boom")); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot error after a complete or error")); }
@Test public void completeAfterErrorNormalConditional() { StepVerifier.create(Flux.just(1) .hide() .filter(i -> true) .handle((v, sink) -> { sink.error(new NullPointerException("boom")); sink.complete(); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot complete after a complete or error")); }
@Test public void nextAfterErrorNormalConditional() { StepVerifier.create(Flux.just(1) .hide() .filter(i -> true) .handle((v, sink) -> { sink.error(new NullPointerException("boom")); sink.next(2); })) .verifyErrorSatisfies(e -> assertThat(e).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot emit after a complete or error")); }
@Test public void generateError() { AssertSubscriber<Integer> ts = AssertSubscriber.create(); Flux.<Integer>generate(o -> { o.error(new RuntimeException("forced failure")); }).subscribe(ts); ts.assertNoValues() .assertNotComplete() .assertError(RuntimeException.class) .assertErrorMessage("forced failure"); }
@Test public void retryErrorPropagatedFromWorkQueueSubscriberCold() throws Exception { AtomicInteger errors = new AtomicInteger(3); WorkQueueProcessor<Integer> wq = WorkQueueProcessor.<Integer>builder().autoCancel(false).build(); AtomicInteger onNextSignals = new AtomicInteger(); wq.onNext(1); wq.onNext(2); wq.onNext(3); wq.onComplete(); StepVerifier.create(wq.log("wq", Level.FINE) .doOnNext(e -> onNextSignals.incrementAndGet()).<Integer>handle( (s1, sink) -> { if (errors.decrementAndGet() > 0) { sink.error(new RuntimeException()); } else { sink.next(s1); } }).retry()) .expectNext(1, 2, 3) .verifyComplete(); assertThat(onNextSignals.get(), equalTo(5)); while (wq.downstreamCount() != 0 && Thread.activeCount() > 1) { } }
@Test() public void retryNoThreadLeak() throws Exception { WorkQueueProcessor<Integer> wq = WorkQueueProcessor.<Integer>builder().autoCancel(false).build(); wq.handle((integer, sink) -> sink.error(new RuntimeException())) .retry(10) .subscribe(); wq.onNext(1); wq.onNext(2); wq.onNext(3); wq.onComplete(); while (wq.downstreamCount() != 0 && Thread.activeCount() > 1) { } }
@Override protected List<Scenario<String, String>> scenarios_operatorError() { return Arrays.asList( scenario(f -> f.handle((s, d) -> { throw exception(); })), scenario(f -> f.handle((s, d) -> d.error(exception()))), scenario(f -> f.handle((s, d) -> { d.next(item(0)); d.next(item(1)); })), scenario(f -> f.handle((s, d) -> { d.next(null); })) ); }