Skip to content
This repository was archived by the owner on Nov 1, 2024. It is now read-only.

Commit bba4029

Browse files
authored
Merge pull request #7 from jroper/tck-test-overhaul
Updated to newer TCK and fixed a number of bugs
2 parents fd82c86 + 76fb595 commit bba4029

File tree

10 files changed

+138
-195
lines changed

10 files changed

+138
-195
lines changed

akka/src/main/java/com/lightbend/microprofile/reactive/streams/akka/AkkaEngine.java

+34-30
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ else if (size == 1) {
197197
return Source.from(stage.getElements());
198198
});
199199
addSourceStage(Stage.PublisherStage.class, stage -> Source.fromPublisher(stage.getRsPublisher()));
200-
addSourceStage(Stage.Concat.class, stage -> buildSource(stage.getFirst()).concat(buildSource(stage.getSecond())));
200+
addSourceStage(Stage.Concat.class, stage -> buildSource(stage.getFirst())
201+
.concat(buildSource(stage.getSecond())));
201202
addSourceStage(Stage.Failed.class, stage -> Source.failed(stage.getError()));
202203

203204
// Flows
@@ -281,35 +282,38 @@ public akka.stream.Graph<SourceShape<Object>, NotUsed> apply(Throwable x, boolea
281282
// Sinks
282283
addSinkStage(Stage.FindFirst.class, stage -> Sink.headOption());
283284
addSinkStage(Stage.Collect.class, stage -> {
284-
Collector collector = stage.getCollector();
285-
BiConsumer accumulator = collector.accumulator();
286-
Object firstContainer = collector.supplier().get();
287-
if (firstContainer == null) {
288-
firstContainer = NULL;
289-
}
290-
Sink<Object, CompletionStage<Object>> sink = Sink.fold(firstContainer, (resultContainer, in) -> {
291-
if (resultContainer == NULL) {
292-
accumulator.accept(null, in);
293-
}
294-
else {
295-
accumulator.accept(resultContainer, in);
296-
}
297-
return resultContainer;
298-
});
299-
if (collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH) && firstContainer != NULL) {
300-
return sink;
301-
}
302-
else {
303-
return sink.mapMaterializedValue(result -> result.thenApply(r -> {
304-
if (r == NULL) {
305-
return collector.finisher().apply(null);
306-
}
307-
else {
308-
return collector.finisher().apply(r);
309-
}
310-
}));
311-
}
312-
});
285+
Collector collector = stage.getCollector();
286+
// Lazy inited sink so that exceptions thrown by supplier get propagated through completion stage, not directly.
287+
return Sink.lazyInitAsync(() -> {
288+
BiConsumer accumulator = collector.accumulator();
289+
Object firstContainer = collector.supplier().get();
290+
if (firstContainer == null) {
291+
firstContainer = NULL;
292+
}
293+
return CompletableFuture.completedFuture(Sink.fold(firstContainer, (resultContainer, in) -> {
294+
if (resultContainer == NULL) {
295+
accumulator.accept(null, in);
296+
} else {
297+
accumulator.accept(resultContainer, in);
298+
}
299+
return resultContainer;
300+
}));
301+
}).mapMaterializedValue(asyncMaybeResult -> asyncMaybeResult.thenCompose(maybeResult -> {
302+
CompletionStage<Object> resultContainer;
303+
if (maybeResult.isPresent()) {
304+
resultContainer = maybeResult.get();
305+
} else {
306+
resultContainer = CompletableFuture.completedFuture(collector.supplier().get());
307+
}
308+
return resultContainer.thenApply(container -> {
309+
if (collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH) && resultContainer != NULL) {
310+
return container;
311+
} else {
312+
return collector.finisher().apply(container);
313+
}
314+
});
315+
}));
316+
});
313317
addSinkStage(Stage.SubscriberStage.class, stage ->
314318
Flow.create()
315319
.viaMat(new TerminationWatcher(), Keep.right())

akka/src/test/java/com/lightbend/microprofile/reactive/streams/akka/AkkaReactiveStreamsTckTest.java

-8
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@
88
import akka.stream.ActorMaterializer;
99
import akka.stream.Materializer;
1010
import org.eclipse.microprofile.reactive.streams.spi.ReactiveStreamsEngine;
11-
import org.eclipse.microprofile.reactive.streams.tck.CancelStageVerification;
12-
import org.eclipse.microprofile.reactive.streams.tck.FlatMapStageVerification;
1311
import org.eclipse.microprofile.reactive.streams.tck.ReactiveStreamsTck;
14-
import org.reactivestreams.tck.IdentityProcessorVerification;
1512
import org.reactivestreams.tck.TestEnvironment;
1613
import org.testng.annotations.AfterSuite;
1714

@@ -40,9 +37,4 @@ protected AkkaEngine createEngine() {
4037
materializer = ActorMaterializer.create(system);
4138
return new AkkaEngine(materializer);
4239
}
43-
44-
@Override
45-
protected boolean isEnabled(Object test) {
46-
return true;
47-
}
4840
}

bin/buildDeps.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/bash
22

33
# This should be set to the commit hash that is being tracked. Needed even if TRACKING_PR is set.
4-
TRACKING_COMMIT="886a91d5"
4+
TRACKING_COMMIT="0d0c4f50"
55
# To track a particular pull request, put it's number here, otherwise comment it out.
66
# TRACKING_PR="67"
77

zerodep/src/main/java/com/lightbend/microprofile/reactive/streams/zerodep/BuiltGraph.java

+27-41
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,6 @@ private Builder buildGraph(Graph graph, Shape shape) {
269269
}
270270
}
271271

272-
ports.addAll(builderPorts);
273-
stages.addAll(builderStages);
274-
275272
return this;
276273
}
277274

@@ -284,8 +281,22 @@ private void verifyReady() {
284281
for (Port port : builderPorts) {
285282
port.verifyReady();
286283
}
284+
ports.addAll(builderPorts);
285+
}
286+
287+
/**
288+
* Start the stages on this listener
289+
*/
290+
private void startGraph() {
291+
execute(() -> {
292+
for (GraphStage stage : builderStages) {
293+
stages.add(stage);
294+
stage.postStart();
295+
}
296+
});
287297
}
288298

299+
289300
private <T> SubStageInlet<T> inlet() {
290301
Objects.requireNonNull(lastInlet, "Not an inlet graph");
291302
assert result == null;
@@ -360,18 +371,8 @@ private void addStage(Stage stage, StageInlet inlet, Publisher publisher, StageO
360371
addStage(new OfStage(BuiltGraph.this, outlet,
361372
((Stage.Of) stage).getElements()));
362373
} else if (stage instanceof Stage.Concat) {
363-
364-
// Use this builder to build each of the sub stages that are being concatenated as an inlet graph, and then
365-
// capture the last inlet of each to pass to the concat stage.
366-
buildGraph(((Stage.Concat) stage).getFirst(), Shape.INLET);
367-
StageInlet firstInlet = lastInlet;
368-
lastInlet = null;
369-
370-
buildGraph(((Stage.Concat) stage).getSecond(), Shape.INLET);
371-
StageInlet secondInlet = lastInlet;
372-
lastInlet = null;
373-
374-
addStage(new ConcatStage(BuiltGraph.this, firstInlet, secondInlet, outlet));
374+
Stage.Concat concat = (Stage.Concat) stage;
375+
addStage(new ConcatStage(BuiltGraph.this, buildSubInlet(concat.getFirst()), buildSubInlet(concat.getSecond()), outlet));
375376
} else if (stage instanceof Stage.PublisherStage) {
376377
addStage(new ConnectorStage(BuiltGraph.this, ((Stage.PublisherStage) stage).getRsPublisher(), subscriber));
377378
} else if (stage instanceof Stage.Failed) {
@@ -517,17 +518,6 @@ public void execute(Runnable command) {
517518
});
518519
}
519520

520-
/**
521-
* Start the whole graph.
522-
*/
523-
private void startGraph() {
524-
execute(() -> {
525-
for (GraphStage stage : stages) {
526-
stage.postStart();
527-
}
528-
});
529-
}
530-
531521
private void streamFailure(Throwable error) {
532522
// todo handle better
533523
error.printStackTrace();
@@ -558,8 +548,6 @@ final class SubStageInlet<T> implements StageInlet<T> {
558548
private final List<GraphStage> subStages;
559549
private final List<Port> subStagePorts;
560550

561-
private boolean started = false;
562-
563551
private SubStageInlet(StageInlet<T> delegate, List<GraphStage> subStages, List<Port> subStagePorts) {
564552
this.delegate = delegate;
565553
this.subStages = subStages;
@@ -568,20 +556,24 @@ private SubStageInlet(StageInlet<T> delegate, List<GraphStage> subStages, List<P
568556

569557
void start() {
570558
subStagePorts.forEach(Port::verifyReady);
571-
started = true;
572-
subStages.forEach(GraphStage::postStart);
559+
ports.addAll(subStagePorts);
560+
for (GraphStage stage: subStages) {
561+
stages.add(stage);
562+
stage.postStart();
563+
}
573564
}
574565

575566
private void shutdown() {
576-
stages.removeAll(subStages);
577-
ports.removeAll(subStagePorts);
567+
// Do it in a signal, this ensures that if shutdown happens while something is iterating through
568+
// the ports, we don't get a concurrent modification exception.
569+
enqueueSignal(() -> {
570+
stages.removeAll(subStages);
571+
ports.removeAll(subStagePorts);
572+
});
578573
}
579574

580575
@Override
581576
public void pull() {
582-
if (!started) {
583-
throw new IllegalStateException("Pull before the sub stream has been started.");
584-
}
585577
delegate.pull();
586578
}
587579

@@ -602,17 +594,11 @@ public boolean isClosed() {
602594

603595
@Override
604596
public void cancel() {
605-
if (!started) {
606-
throw new IllegalStateException("Cancel before the sub stream has been started.");
607-
}
608597
delegate.cancel();
609598
}
610599

611600
@Override
612601
public T grab() {
613-
if (!started) {
614-
throw new IllegalStateException("Grab before the sub stream has been started.");
615-
}
616602
return delegate.grab();
617603
}
618604

zerodep/src/main/java/com/lightbend/microprofile/reactive/streams/zerodep/CollectStage.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ public CollectStage(BuiltGraph builtGraph, StageInlet<T> inlet,
2323
this.result = result;
2424
this.collector = collector;
2525

26-
container = collector.supplier().get();
2726
inlet.setListener(this);
2827
}
2928

3029
@Override
3130
protected void postStart() {
31+
container = collector.supplier().get();
3232
inlet.pull();
3333
}
3434

zerodep/src/main/java/com/lightbend/microprofile/reactive/streams/zerodep/ConcatStage.java

+47-60
Original file line numberDiff line numberDiff line change
@@ -4,92 +4,79 @@
44

55
package com.lightbend.microprofile.reactive.streams.zerodep;
66

7-
public class ConcatStage<T> extends GraphStage implements OutletListener {
7+
public class ConcatStage<T> extends GraphStage implements InletListener, OutletListener {
88

9-
private final StageInlet<T> first;
10-
private final StageInlet<T> second;
9+
private final BuiltGraph.SubStageInlet<T> first;
10+
private final BuiltGraph.SubStageInlet<T> second;
1111
private final StageOutlet<T> outlet;
1212

13-
private Throwable secondError;
14-
15-
public ConcatStage(BuiltGraph builtGraph, StageInlet<T> first, StageInlet<T> second, StageOutlet<T> outlet) {
13+
public ConcatStage(BuiltGraph builtGraph, BuiltGraph.SubStageInlet<T> first, BuiltGraph.SubStageInlet<T> second, StageOutlet<T> outlet) {
1614
super(builtGraph);
1715
this.first = first;
1816
this.second = second;
1917
this.outlet = outlet;
2018

21-
first.setListener(new FirstInletListener());
22-
second.setListener(new SecondInletListener());
19+
first.setListener(this);
2320
outlet.setListener(this);
2421
}
2522

23+
@Override
24+
protected void postStart() {
25+
first.start();
26+
}
27+
2628
@Override
2729
public void onPull() {
28-
if (first.isClosed()) {
29-
second.pull();
30-
} else {
31-
first.pull();
32-
}
30+
first.pull();
3331
}
3432

3533
@Override
3634
public void onDownstreamFinish() {
37-
if (!first.isClosed()) {
38-
first.cancel();
39-
}
40-
if (!second.isClosed()) {
41-
second.cancel();
42-
}
35+
first.cancel();
36+
// Start up second so we can shut it down, in case it holds any resources.
37+
startAndCancelSecond();
4338
}
4439

45-
private class FirstInletListener implements InletListener {
46-
@Override
47-
public void onPush() {
48-
outlet.push(first.grab());
49-
}
40+
@Override
41+
public void onPush() {
42+
outlet.push(first.grab());
43+
}
5044

51-
@Override
52-
public void onUpstreamFinish() {
53-
if (second.isClosed()) {
54-
if (secondError != null) {
55-
outlet.fail(secondError);
56-
} else {
57-
outlet.complete();
58-
}
59-
} else if (outlet.isAvailable()) {
60-
second.pull();
61-
}
45+
@Override
46+
public void onUpstreamFinish() {
47+
second.forwardTo(outlet);
48+
outlet.forwardTo(second);
49+
second.start();
50+
if (outlet.isAvailable()) {
51+
second.pull();
6252
}
53+
}
6354

64-
@Override
65-
public void onUpstreamFailure(Throwable error) {
66-
outlet.fail(error);
67-
if (!second.isClosed()) {
68-
second.cancel();
69-
}
70-
}
55+
@Override
56+
public void onUpstreamFailure(Throwable error) {
57+
outlet.fail(error);
58+
startAndCancelSecond();
7159
}
7260

73-
private class SecondInletListener implements InletListener {
74-
@Override
75-
public void onPush() {
76-
outlet.push(second.grab());
77-
}
61+
private void startAndCancelSecond() {
62+
try {
63+
second.setListener(new InletListener() {
64+
@Override
65+
public void onPush() {
66+
}
7867

79-
@Override
80-
public void onUpstreamFinish() {
81-
if (first.isClosed()) {
82-
outlet.complete();
83-
}
84-
}
68+
@Override
69+
public void onUpstreamFinish() {
70+
}
8571

86-
@Override
87-
public void onUpstreamFailure(Throwable error) {
88-
if (first.isClosed()) {
89-
outlet.fail(error);
90-
} else {
91-
secondError = error;
92-
}
72+
@Override
73+
public void onUpstreamFailure(Throwable error) {
74+
}
75+
});
76+
second.start();
77+
second.cancel();
78+
} catch (Exception e) {
79+
// Ignore exceptions
9380
}
9481
}
9582
}

0 commit comments

Comments
 (0)