Skip to content

Commit daf3ecc

Browse files
andrey-radchenkoakarnokd
authored andcommitted
Added unit test singleJust() to expose the hanging subscriber. (#154) (#156)
* Added unit test singleJust() to expose the hanging SingleAsPublisherSubscriber bug. (#154) * Fixed the hanging SingleAsPublisherSubscriber bug. (#154)
1 parent 65efd1f commit daf3ecc

File tree

2 files changed

+57
-36
lines changed

2 files changed

+57
-36
lines changed

Diff for: rxjava-reactive-streams/src/main/java/rx/internal/reactivestreams/SingleAsPublisher.java

+23-19
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,23 @@
1616

1717
package rx.internal.reactivestreams;
1818

19-
import java.util.concurrent.atomic.AtomicInteger;
20-
2119
import org.reactivestreams.Publisher;
2220
import org.reactivestreams.Subscriber;
2321
import org.reactivestreams.Subscription;
22+
import rx.Single;
23+
import rx.SingleSubscriber;
2424

25-
import rx.*;
25+
import java.util.concurrent.atomic.AtomicInteger;
2626

2727
/**
2828
* Wraps a Single and exposes it as a Publisher.
2929
*
3030
* @param <T> the value type
3131
*/
3232
public final class SingleAsPublisher<T> implements Publisher<T> {
33-
33+
3434
final Single<T> single;
35-
35+
3636
public SingleAsPublisher(Single<T> single) {
3737
this.single = single;
3838
}
@@ -41,31 +41,31 @@ public SingleAsPublisher(Single<T> single) {
4141
public void subscribe(Subscriber<? super T> s) {
4242
SingleAsPublisherSubscriber<T> parent = new SingleAsPublisherSubscriber<T>(s);
4343
s.onSubscribe(parent);
44-
44+
4545
single.subscribe(parent);
4646
}
47-
47+
4848
static final class SingleAsPublisherSubscriber<T> extends SingleSubscriber<T>
4949
implements Subscription {
50-
50+
5151
final Subscriber<? super T> actual;
5252

5353
final AtomicInteger state;
54-
54+
5555
T value;
56-
56+
5757
volatile boolean cancelled;
58-
58+
5959
static final int NO_REQUEST_NO_VALUE = 0;
6060
static final int NO_REQUEST_HAS_VALUE = 1;
6161
static final int HAS_REQUEST_NO_VALUE = 2;
6262
static final int HAS_REQUEST_HAS_VALUE = 3;
63-
63+
6464
public SingleAsPublisherSubscriber(Subscriber<? super T> actual) {
6565
this.actual = actual;
6666
this.state = new AtomicInteger();
6767
}
68-
68+
6969
@Override
7070
public void onSuccess(T value) {
7171
if (cancelled) {
@@ -78,7 +78,7 @@ public void onSuccess(T value) {
7878
}
7979
for (;;) {
8080
int s = state.get();
81-
81+
8282
if (s == NO_REQUEST_HAS_VALUE || s == HAS_REQUEST_HAS_VALUE || cancelled) {
8383
break;
8484
} else
@@ -87,6 +87,7 @@ public void onSuccess(T value) {
8787
if (!cancelled) {
8888
actual.onComplete();
8989
}
90+
return;
9091
} else {
9192
this.value = value;
9293
if (state.compareAndSet(s, NO_REQUEST_HAS_VALUE)) {
@@ -95,7 +96,7 @@ public void onSuccess(T value) {
9596
}
9697
}
9798
}
98-
99+
99100
@Override
100101
public void onError(Throwable error) {
101102
if (cancelled) {
@@ -104,31 +105,34 @@ public void onError(Throwable error) {
104105
state.lazySet(HAS_REQUEST_HAS_VALUE);
105106
actual.onError(error);
106107
}
107-
108+
108109
@Override
109110
public void request(long n) {
110111
if (n > 0) {
111112
for (;;) {
112113
int s = state.get();
113114
if (s == HAS_REQUEST_HAS_VALUE || s == HAS_REQUEST_NO_VALUE || cancelled) {
114115
break;
115-
} else
116+
}
116117
if (s == NO_REQUEST_HAS_VALUE) {
117118
if (state.compareAndSet(s, HAS_REQUEST_HAS_VALUE)) {
118119
T v = value;
119120
value = null;
120-
121+
121122
actual.onNext(v);
122123
if (!cancelled) {
123124
actual.onComplete();
124125
}
125126
}
126127
break;
127128
}
129+
if (state.compareAndSet(NO_REQUEST_NO_VALUE, HAS_REQUEST_NO_VALUE)) {
130+
break;
131+
}
128132
}
129133
}
130134
}
131-
135+
132136
@Override
133137
public void cancel() {
134138
if (!cancelled) {
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
package rx.reactivestreams.test;
22

3-
import static rx.RxReactiveStreams.*;
4-
5-
import java.util.NoSuchElementException;
6-
73
import org.testng.Assert;
84
import org.testng.annotations.Test;
9-
10-
import rx.*;
5+
import rx.Observable;
6+
import rx.Single;
117
import rx.observers.TestSubscriber;
12-
import rx.reactivestreams.test.PublisherAsCompletableTest.*;
8+
import rx.reactivestreams.test.PublisherAsCompletableTest.PublisherEmpty;
9+
import rx.reactivestreams.test.PublisherAsCompletableTest.PublisherFail;
10+
import rx.schedulers.Schedulers;
1311
import rx.subjects.PublishSubject;
1412

13+
import java.util.NoSuchElementException;
14+
import java.util.concurrent.TimeUnit;
15+
16+
import static rx.RxReactiveStreams.toPublisher;
17+
import static rx.RxReactiveStreams.toSingle;
18+
1519
public class PublisherAsSingleTest {
1620

1721
@Test(expectedExceptions = { NullPointerException.class })
@@ -22,18 +26,31 @@ public void nullCheck() {
2226
@Test
2327
public void just() {
2428
TestSubscriber<Object> ts = new TestSubscriber<Object>();
25-
29+
2630
toSingle(toPublisher(Observable.just(1))).subscribe(ts);
2731

2832
ts.assertValue(1);
2933
ts.assertCompleted();
3034
ts.assertNoErrors();
3135
}
3236

37+
@Test
38+
public void singleJust() {
39+
TestSubscriber<Object> ts = new TestSubscriber<Object>();
40+
41+
toSingle(toPublisher(Single.just(1))).subscribeOn(Schedulers.computation()).subscribe(ts);
42+
43+
ts.awaitTerminalEvent(3, TimeUnit.SECONDS);
44+
45+
ts.assertValue(1);
46+
ts.assertCompleted();
47+
ts.assertNoErrors();
48+
}
49+
3350
@Test
3451
public void empty() {
3552
TestSubscriber<Object> ts = new TestSubscriber<Object>();
36-
53+
3754
toSingle(new PublisherEmpty()).subscribe(ts);
3855

3956
ts.assertNoValues();
@@ -44,7 +61,7 @@ public void empty() {
4461
@Test
4562
public void range() {
4663
TestSubscriber<Object> ts = new TestSubscriber<Object>();
47-
64+
4865
toSingle(toPublisher(Observable.range(1, 2))).subscribe(ts);
4966

5067
ts.assertNoValues();
@@ -55,31 +72,31 @@ public void range() {
5572
@Test
5673
public void error() {
5774
TestSubscriber<Object> ts = new TestSubscriber<Object>();
58-
75+
5976
toSingle(new PublisherFail()).subscribe(ts);
60-
77+
6178
ts.assertNoValues();
6279
ts.assertNotCompleted();
6380
ts.assertError(RuntimeException.class);
6481
Assert.assertEquals(ts.getOnErrorEvents().get(0).getMessage(), "Forced failure");
6582
}
66-
83+
6784
@Test
6885
public void cancellation() {
6986
PublishSubject<Object> ps = PublishSubject.create();
7087

7188
TestSubscriber<Object> ts = new TestSubscriber<Object>();
72-
89+
7390
toSingle(toPublisher(ps)).subscribe(ts);
74-
91+
7592
Assert.assertTrue(ps.hasObservers());
7693

7794
ts.unsubscribe();
78-
95+
7996
ts.assertNoValues();
8097
ts.assertNotCompleted();
8198
ts.assertNoErrors();
82-
99+
83100
Assert.assertFalse(ps.hasObservers());
84101
}
85102
}

0 commit comments

Comments
 (0)