Skip to content

Commit 6c8b0ef

Browse files
authored
2.x: fix Flowable.toList() onNext/cancel race (#5247)
1 parent 7c95808 commit 6c8b0ef

File tree

2 files changed

+84
-2
lines changed

2 files changed

+84
-2
lines changed

src/main/java/io/reactivex/internal/operators/flowable/FlowableToList.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ public void onSubscribe(Subscription s) {
6969

7070
@Override
7171
public void onNext(T t) {
72-
value.add(t);
72+
U v = value;
73+
if (v != null) {
74+
v.add(t);
75+
}
7376
}
7477

7578
@Override

src/test/java/io/reactivex/internal/operators/flowable/FlowableToListTest.java

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
package io.reactivex.internal.operators.flowable;
1515

16+
import static org.mockito.ArgumentMatchers.any;
1617
import static org.mockito.Mockito.*;
1718

1819
import java.util.*;
@@ -23,7 +24,6 @@
2324
import org.reactivestreams.Subscriber;
2425

2526
import io.reactivex.*;
26-
import io.reactivex.Flowable;
2727
import io.reactivex.exceptions.TestException;
2828
import io.reactivex.observers.TestObserver;
2929
import io.reactivex.processors.PublishProcessor;
@@ -389,4 +389,83 @@ public Collection<Integer> call() throws Exception {
389389
.assertFailure(NullPointerException.class)
390390
.assertErrorMessage("The collectionSupplier returned a null collection. Null values are generally not allowed in 2.x operators and sources.");
391391
}
392+
393+
@Test
394+
public void onNextCancelRace() {
395+
for (int i = 0; i < 1000; i++) {
396+
final PublishProcessor<Integer> pp = PublishProcessor.create();
397+
final TestObserver<List<Integer>> ts = pp.toList().test();
398+
399+
Runnable r1 = new Runnable() {
400+
@Override
401+
public void run() {
402+
pp.onNext(1);
403+
}
404+
};
405+
Runnable r2 = new Runnable() {
406+
@Override
407+
public void run() {
408+
ts.cancel();
409+
}
410+
};
411+
412+
TestHelper.race(r1, r2);
413+
}
414+
415+
}
416+
417+
@Test
418+
public void onNextCancelRaceFlowable() {
419+
for (int i = 0; i < 1000; i++) {
420+
final PublishProcessor<Integer> pp = PublishProcessor.create();
421+
final TestSubscriber<List<Integer>> ts = pp.toList().toFlowable().test();
422+
423+
Runnable r1 = new Runnable() {
424+
@Override
425+
public void run() {
426+
pp.onNext(1);
427+
}
428+
};
429+
Runnable r2 = new Runnable() {
430+
@Override
431+
public void run() {
432+
ts.cancel();
433+
}
434+
};
435+
436+
TestHelper.race(r1, r2);
437+
}
438+
439+
}
440+
441+
@Test
442+
public void onCompleteCancelRaceFlowable() {
443+
for (int i = 0; i < 1000; i++) {
444+
final PublishProcessor<Integer> pp = PublishProcessor.create();
445+
final TestSubscriber<List<Integer>> ts = pp.toList().toFlowable().test();
446+
447+
pp.onNext(1);
448+
449+
Runnable r1 = new Runnable() {
450+
@Override
451+
public void run() {
452+
pp.onComplete();
453+
}
454+
};
455+
Runnable r2 = new Runnable() {
456+
@Override
457+
public void run() {
458+
ts.cancel();
459+
}
460+
};
461+
462+
TestHelper.race(r1, r2);
463+
464+
if (ts.valueCount() != 0) {
465+
ts.assertValue(Arrays.asList(1))
466+
.assertNoErrors();
467+
}
468+
}
469+
470+
}
392471
}

0 commit comments

Comments
 (0)