Skip to content

Commit 67fd60a

Browse files
committed
iss1403: added tests for Single and Completable, fixed bugs in GenericObservableCommand related to these RX types
1 parent 8715b71 commit 67fd60a

File tree

4 files changed

+142
-11
lines changed

4 files changed

+142
-11
lines changed

hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/GenericObservableCommand.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ protected Observable resumeWithFallback() {
108108
Object res = commandActions.getFallbackAction().executeWithArgs(executionType, args);
109109
if (res instanceof Observable) {
110110
return (Observable) res;
111+
} else if (res instanceof Single) {
112+
return ((Single) res).toObservable();
113+
} else if (res instanceof Completable) {
114+
return ((Completable) res).toObservable();
111115
} else {
112116
return Observable.just(res);
113117
}

hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/FallbackMethod.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.commons.collections.CollectionUtils;
2626
import org.apache.commons.lang3.StringUtils;
2727
import org.apache.commons.lang3.Validate;
28+
import rx.Completable;
2829

2930
import javax.annotation.Nonnull;
3031
import javax.annotation.Nullable;
@@ -92,6 +93,13 @@ public void validateReturnType(Method commandMethod) {
9293
if (ExecutionType.OBSERVABLE == ExecutionType.getExecutionType(commandReturnType)) {
9394
if (ExecutionType.OBSERVABLE != getExecutionType()) {
9495
Type commandParametrizedType = commandMethod.getGenericReturnType();
96+
97+
// basically any object can be wrapped into Completable, Completable itself ins't parametrized
98+
if(Completable.class.isAssignableFrom(commandMethod.getReturnType())) {
99+
validateCompletableReturnType(commandMethod, method.getReturnType());
100+
return;
101+
}
102+
95103
if (isReturnTypeParametrized(commandMethod)) {
96104
commandParametrizedType = getFirstParametrizedType(commandMethod);
97105
}
@@ -137,6 +145,13 @@ private Type getFirstParametrizedType(Method m) {
137145
return null;
138146
}
139147

148+
// everything can be wrapped into completable except 'void'
149+
private void validateCompletableReturnType(Method commandMethod, Class<?> callbackReturnType) {
150+
if (Void.TYPE == callbackReturnType) {
151+
throw new FallbackDefinitionException(createErrorMsg(commandMethod, method, "fallback cannot return 'void' if command return type is " + Completable.class.getSimpleName()));
152+
}
153+
}
154+
140155
private void validateReturnType(Method commandMethod, Method fallbackMethod) {
141156
if (isGenericReturnType(commandMethod)) {
142157
List<Type> commandParametrizedTypes = flattenTypeVariables(commandMethod.getGenericReturnType());

hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/fallback/BasicGenericFallbackTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.slf4j.helpers.MessageFormatter;
1515
import org.springframework.test.context.junit4.rules.SpringClassRule;
1616
import org.springframework.test.context.junit4.rules.SpringMethodRule;
17+
import rx.Completable;
1718

1819
import java.io.Serializable;
1920
import java.lang.reflect.InvocationTargetException;
@@ -64,6 +65,7 @@ public Object[] methodGenericDefinitionFailure() {
6465
new Object[]{MethodGenericDefinitionFailureCase8.class},
6566
new Object[]{MethodGenericDefinitionFailureCase9.class},
6667
new Object[]{MethodGenericDefinitionFailureCase10.class},
68+
new Object[]{MethodGenericDefinitionFailureCase11.class},
6769

6870
};
6971
}
@@ -247,6 +249,12 @@ public static class MethodGenericDefinitionFailureCase10 {
247249
private GenericEntity<? super Comparable> fallback() { return null; }
248250
}
249251

252+
public static class MethodGenericDefinitionFailureCase11 {
253+
@HystrixCommand(fallbackMethod = "fallback")
254+
public Completable command() { throw new IllegalStateException(); }
255+
private void fallback() { return; }
256+
}
257+
250258
/* ====================================================================== */
251259
/* ===================== GENERIC CLASS DEFINITIONS =====+================ */
252260
/* =========================== SUCCESS CASES ============================ */

hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/observable/BasicObservableTest.java

Lines changed: 115 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import rx.Single;
3131
import rx.Subscriber;
3232
import rx.functions.Action1;
33-
import rx.subjects.ReplaySubject;
33+
import rx.functions.Func0;
3434

3535
import static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey;
3636
import static org.junit.Assert.assertEquals;
@@ -93,19 +93,82 @@ public void call(User user) {
9393
}
9494

9595
@Test
96-
public void testCompletable(){
97-
userService.getUserCompletable("1", "name: ");
98-
com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getUserCompletable");
96+
public void testGetCompletableUser(){
97+
userService.getCompletableUser("1", "name: ");
98+
com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getCompletableUser");
9999
assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.SUCCESS));
100100
}
101101

102102
@Test
103-
public void testSingle(){
104-
userService.getUserSingle("1", "name: ");
105-
com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getUserSingle");
103+
public void testGetCompletableUserWithRegularFallback() {
104+
Completable completable = userService.getCompletableUserWithRegularFallback(null, "name: ");
105+
completable.<User>toObservable().subscribe(new Action1<User>() {
106+
@Override
107+
public void call(User user) {
108+
assertEquals("default_id", user.getId());
109+
}
110+
});
111+
com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getCompletableUserWithRegularFallback");
112+
assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));
113+
assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));
114+
}
115+
116+
@Test
117+
public void testGetCompletableUserWithRxFallback() {
118+
Completable completable = userService.getCompletableUserWithRxFallback(null, "name: ");
119+
completable.<User>toObservable().subscribe(new Action1<User>() {
120+
@Override
121+
public void call(User user) {
122+
assertEquals("default_id", user.getId());
123+
}
124+
});
125+
com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getCompletableUserWithRxFallback");
126+
assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));
127+
assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));
128+
}
129+
130+
@Test
131+
public void testGetSingleUser() {
132+
final String id = "1";
133+
Single<User> user = userService.getSingleUser(id, "name: ");
134+
user.subscribe(new Action1<User>() {
135+
@Override
136+
public void call(User user) {
137+
assertEquals(id, user.getId());
138+
}
139+
});
140+
com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getSingleUser");
106141
assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.SUCCESS));
107142
}
108143

144+
@Test
145+
public void testGetSingleUserWithRegularFallback(){
146+
Single<User> user = userService.getSingleUserWithRegularFallback(null, "name: ");
147+
user.subscribe(new Action1<User>() {
148+
@Override
149+
public void call(User user) {
150+
assertEquals("default_id", user.getId());
151+
}
152+
});
153+
com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getSingleUserWithRegularFallback");
154+
assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));
155+
assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));
156+
}
157+
158+
@Test
159+
public void testGetSingleUserWithRxFallback(){
160+
Single<User> user = userService.getSingleUserWithRxFallback(null, "name: ");
161+
user.subscribe(new Action1<User>() {
162+
@Override
163+
public void call(User user) {
164+
assertEquals("default_id", user.getId());
165+
}
166+
});
167+
com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getSingleUserWithRxFallback");
168+
assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE));
169+
assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS));
170+
}
171+
109172
@Test
110173
public void testGetUserWithRegularFallback() {
111174
final User exUser = new User("def", "def");
@@ -179,17 +242,58 @@ public Observable<User> getUser(final String id, final String name) {
179242
}
180243

181244
@HystrixCommand
182-
public Completable getUserCompletable(final String id, final String name) {
183-
validate(id, name, "getUser has failed");
245+
public Completable getCompletableUser(final String id, final String name) {
246+
validate(id, name, "getCompletableUser has failed");
184247
return createObservable(id, name).toCompletable();
185248
}
186249

250+
@HystrixCommand(fallbackMethod = "completableUserRegularFallback")
251+
public Completable getCompletableUserWithRegularFallback(final String id, final String name) {
252+
return getCompletableUser(id, name);
253+
}
254+
255+
@HystrixCommand(fallbackMethod = "completableUserRxFallback")
256+
public Completable getCompletableUserWithRxFallback(final String id, final String name) {
257+
return getCompletableUser(id, name);
258+
}
259+
260+
public User completableUserRegularFallback(final String id, final String name) {
261+
return new User("default_id", "default_name");
262+
}
263+
264+
public Completable completableUserRxFallback(final String id, final String name) {
265+
return Completable.fromCallable(new Func0<User>() {
266+
@Override
267+
public User call() {
268+
return new User("default_id", "default_name");
269+
}
270+
});
271+
}
272+
187273
@HystrixCommand
188-
public Single getUserSingle(final String id, final String name) {
189-
validate(id, name, "getUser has failed");
274+
public Single<User> getSingleUser(final String id, final String name) {
275+
validate(id, name, "getSingleUser has failed");
190276
return createObservable(id, name).toSingle();
191277
}
192278

279+
@HystrixCommand(fallbackMethod = "singleUserRegularFallback")
280+
public Single<User> getSingleUserWithRegularFallback(final String id, final String name) {
281+
return getSingleUser(id, name);
282+
}
283+
284+
@HystrixCommand(fallbackMethod = "singleUserRxFallback")
285+
public Single<User> getSingleUserWithRxFallback(final String id, final String name) {
286+
return getSingleUser(id, name);
287+
}
288+
289+
User singleUserRegularFallback(final String id, final String name) {
290+
return new User("default_id", "default_name");
291+
}
292+
293+
Single<User> singleUserRxFallback(final String id, final String name) {
294+
return createObservable("default_id", "default_name").toSingle();
295+
}
296+
193297
@HystrixCommand(fallbackMethod = "regularFallback", observableExecutionMode = ObservableExecutionMode.LAZY)
194298
public Observable<User> getUserRegularFallback(final String id, final String name) {
195299
validate(id, name, "getUser has failed");

0 commit comments

Comments
 (0)