@@ -73,8 +73,9 @@ public Subscription call(final Observer<T> observer) {
73
73
// subscribe to the original Observable and remember the subscription
74
74
subscription .wrap (originalSequence .subscribe (new Observer <T >() {
75
75
public void onNext (T value ) {
76
- // forward the successful calls
77
- observer .onNext (value );
76
+ // forward the successful calls unless resumed
77
+ if (subscriptionRef .get ()==subscription )
78
+ observer .onNext (value );
78
79
}
79
80
80
81
/**
@@ -83,8 +84,8 @@ public void onNext(T value) {
83
84
public void onError (Exception ex ) {
84
85
/* remember what the current subscription is so we can determine if someone unsubscribes concurrently */
85
86
AtomicObservableSubscription currentSubscription = subscriptionRef .get ();
86
- // check that we have not been unsubscribed before we can process the error
87
- if (currentSubscription != null ) {
87
+ // check that we have not been unsubscribed and not already resumed before we can process the error
88
+ if (currentSubscription == subscription ) {
88
89
/* error occurred, so switch subscription to the 'resumeSequence' */
89
90
AtomicObservableSubscription innerSubscription = new AtomicObservableSubscription (resumeSequence .subscribe (observer ));
90
91
/* we changed the sequence, so also change the subscription to the one of the 'resumeSequence' instead */
@@ -97,8 +98,9 @@ public void onError(Exception ex) {
97
98
}
98
99
99
100
public void onCompleted () {
100
- // forward the successful calls
101
- observer .onCompleted ();
101
+ // forward the successful calls unless resumed
102
+ if (subscriptionRef .get ()==subscription )
103
+ observer .onCompleted ();
102
104
}
103
105
}));
104
106
@@ -119,7 +121,8 @@ public static class UnitTest {
119
121
@ Test
120
122
public void testResumeNext () {
121
123
Subscription s = mock (Subscription .class );
122
- TestObservable w = new TestObservable (s , "one" );
124
+ // Trigger failure on second element
125
+ TestObservable w = new TestObservable (s , "one" , "fail" , "two" , "three" );
123
126
Observable <String > resume = Observable .from ("twoResume" , "threeResume" );
124
127
Observable <String > observable = Observable .create (onErrorResumeNextViaObservable (w , resume ));
125
128
@@ -140,7 +143,46 @@ public void testResumeNext() {
140
143
verify (aObserver , Mockito .never ()).onNext ("three" );
141
144
verify (aObserver , times (1 )).onNext ("twoResume" );
142
145
verify (aObserver , times (1 )).onNext ("threeResume" );
146
+ }
147
+
148
+ @ Test
149
+ public void testMapResumeAsyncNext () {
150
+ Subscription sr = mock (Subscription .class );
151
+ // Trigger multiple failures
152
+ Observable <String > w = Observable .from ("one" , "fail" , "two" , "three" , "fail" );
153
+ // Resume Observable is async
154
+ TestObservable resume = new TestObservable (sr , "twoResume" , "threeResume" );
155
+
156
+ // Introduce map function that fails intermittently (Map does not prevent this when the observer is a
157
+ // rx.operator incl onErrorResumeNextViaObservable)
158
+ w = w .map (new Func1 <String , String >() {
159
+ public String call (String s ) {
160
+ if ("fail" .equals (s ))
161
+ throw new RuntimeException ("Forced Failure" );
162
+ System .out .println ("BadMapper:" + s );
163
+ return s ;
164
+ }
165
+ });
166
+
167
+ Observable <String > observable = Observable .create (onErrorResumeNextViaObservable (w , resume ));
168
+
169
+ @ SuppressWarnings ("unchecked" )
170
+ Observer <String > aObserver = mock (Observer .class );
171
+ observable .subscribe (aObserver );
172
+
173
+ try {
174
+ resume .t .join ();
175
+ } catch (InterruptedException e ) {
176
+ fail (e .getMessage ());
177
+ }
143
178
179
+ verify (aObserver , Mockito .never ()).onError (any (Exception .class ));
180
+ verify (aObserver , times (1 )).onCompleted ();
181
+ verify (aObserver , times (1 )).onNext ("one" );
182
+ verify (aObserver , Mockito .never ()).onNext ("two" );
183
+ verify (aObserver , Mockito .never ()).onNext ("three" );
184
+ verify (aObserver , times (1 )).onNext ("twoResume" );
185
+ verify (aObserver , times (1 )).onNext ("threeResume" );
144
186
}
145
187
146
188
private static class TestObservable extends Observable <String > {
@@ -164,11 +206,15 @@ public void run() {
164
206
try {
165
207
System .out .println ("running TestObservable thread" );
166
208
for (String s : values ) {
209
+ if ("fail" .equals (s ))
210
+ throw new RuntimeException ("Forced Failure" );
167
211
System .out .println ("TestObservable onNext: " + s );
168
212
observer .onNext (s );
169
213
}
170
- throw new RuntimeException ("Forced Failure" );
214
+ System .out .println ("TestObservable onCompleted" );
215
+ observer .onCompleted ();
171
216
} catch (Exception e ) {
217
+ System .out .println ("TestObservable onError: " + e );
172
218
observer .onError (e );
173
219
}
174
220
}
0 commit comments