/** * Copyright 2016 Netflix, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.netflix.hystrix.contrib.javanica.test.common.observable; import com.netflix.hystrix.HystrixEventType; import com.netflix.hystrix.HystrixRequestLog; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.ObservableExecutionMode; import com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest; import com.netflix.hystrix.contrib.javanica.test.common.domain.User; import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Test; import rx.Completable; import rx.Observable; import rx.Observer; import rx.Single; import rx.Subscriber; import rx.functions.Action1; import rx.functions.Func0; import static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * Created by dmgcodevil */ public abstract class BasicObservableTest extends BasicHystrixTest { private UserService userService; protected abstract UserService createUserService(); @Before public void setUp() throws Exception { userService = createUserService(); } @Test public void testGetUserByIdSuccess() { // blocking Observable<User> observable = userService.getUser("1", "name: "); assertEquals("name: 1", observable.toBlocking().single().getName()); // non-blocking // - this is a verbose anonymous inner-class approach and doesn't do assertions Observable<User> fUser = userService.getUser("1", "name: "); fUser.subscribe(new Observer<User>() { @Override public void onCompleted() { // nothing needed here } @Override public void onError(Throwable e) { e.printStackTrace(); } @Override public void onNext(User v) { System.out.println("onNext: " + v); } }); Observable<User> fs = userService.getUser("1", "name: "); fs.subscribe(new Action1<User>() { @Override public void call(User user) { assertEquals("name: 1", user.getName()); } }); assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getUser"); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.SUCCESS)); } @Test public void testGetCompletableUser(){ userService.getCompletableUser("1", "name: "); com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getCompletableUser"); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.SUCCESS)); } @Test public void testGetCompletableUserWithRegularFallback() { Completable completable = userService.getCompletableUserWithRegularFallback(null, "name: "); completable.<User>toObservable().subscribe(new Action1<User>() { @Override public void call(User user) { assertEquals("default_id", user.getId()); } }); com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getCompletableUserWithRegularFallback"); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE)); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS)); } @Test public void testGetCompletableUserWithRxFallback() { Completable completable = userService.getCompletableUserWithRxFallback(null, "name: "); completable.<User>toObservable().subscribe(new Action1<User>() { @Override public void call(User user) { assertEquals("default_id", user.getId()); } }); com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getCompletableUserWithRxFallback"); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE)); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS)); } @Test public void testGetSingleUser() { final String id = "1"; Single<User> user = userService.getSingleUser(id, "name: "); user.subscribe(new Action1<User>() { @Override public void call(User user) { assertEquals(id, user.getId()); } }); com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getSingleUser"); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.SUCCESS)); } @Test public void testGetSingleUserWithRegularFallback(){ Single<User> user = userService.getSingleUserWithRegularFallback(null, "name: "); user.subscribe(new Action1<User>() { @Override public void call(User user) { assertEquals("default_id", user.getId()); } }); com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getSingleUserWithRegularFallback"); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE)); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS)); } @Test public void testGetSingleUserWithRxFallback(){ Single<User> user = userService.getSingleUserWithRxFallback(null, "name: "); user.subscribe(new Action1<User>() { @Override public void call(User user) { assertEquals("default_id", user.getId()); } }); com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getSingleUserWithRxFallback"); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE)); assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS)); } @Test public void testGetUserWithRegularFallback() { final User exUser = new User("def", "def"); Observable<User> userObservable = userService.getUserRegularFallback(" ", ""); // blocking assertEquals(exUser, userObservable.toBlocking().single()); assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getUserRegularFallback"); // confirm that command has failed assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE)); // and that fallback was successful assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS)); } @Test public void testGetUserWithRxFallback() { final User exUser = new User("def", "def"); // blocking assertEquals(exUser, userService.getUserRxFallback(" ", "").toBlocking().single()); assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); com.netflix.hystrix.HystrixInvokableInfo getUserCommand = getHystrixCommandByKey("getUserRxFallback"); // confirm that command has failed assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FAILURE)); // and that fallback was successful assertTrue(getUserCommand.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS)); } @Test public void testGetUserWithRxCommandFallback() { final User exUser = new User("def", "def"); // blocking Observable<User> userObservable = userService.getUserRxCommandFallback(" ", ""); assertEquals(exUser, userObservable.toBlocking().single()); assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); com.netflix.hystrix.HystrixInvokableInfo getUserRxCommandFallback = getHystrixCommandByKey("getUserRxCommandFallback"); com.netflix.hystrix.HystrixInvokableInfo rxCommandFallback = getHystrixCommandByKey("rxCommandFallback"); // confirm that command has failed assertTrue(getUserRxCommandFallback.getExecutionEvents().contains(HystrixEventType.FAILURE)); assertTrue(getUserRxCommandFallback.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS)); // and that fallback command was successful assertTrue(rxCommandFallback.getExecutionEvents().contains(HystrixEventType.SUCCESS)); } public static class UserService { private User regularFallback(String id, String name) { return new User("def", "def"); } private Observable<User> rxFallback(String id, String name) { return Observable.just(new User("def", "def")); } @HystrixCommand(observableExecutionMode = ObservableExecutionMode.EAGER) private Observable<User> rxCommandFallback(String id, String name, Throwable throwable) { if (throwable instanceof GetUserException && "getUserRxCommandFallback has failed".equals(throwable.getMessage())) { return Observable.just(new User("def", "def")); } else { throw new IllegalStateException(); } } @HystrixCommand public Observable<User> getUser(final String id, final String name) { validate(id, name, "getUser has failed"); return createObservable(id, name); } @HystrixCommand public Completable getCompletableUser(final String id, final String name) { validate(id, name, "getCompletableUser has failed"); return createObservable(id, name).toCompletable(); } @HystrixCommand(fallbackMethod = "completableUserRegularFallback") public Completable getCompletableUserWithRegularFallback(final String id, final String name) { return getCompletableUser(id, name); } @HystrixCommand(fallbackMethod = "completableUserRxFallback") public Completable getCompletableUserWithRxFallback(final String id, final String name) { return getCompletableUser(id, name); } public User completableUserRegularFallback(final String id, final String name) { return new User("default_id", "default_name"); } public Completable completableUserRxFallback(final String id, final String name) { return Completable.fromCallable(new Func0<User>() { @Override public User call() { return new User("default_id", "default_name"); } }); } @HystrixCommand public Single<User> getSingleUser(final String id, final String name) { validate(id, name, "getSingleUser has failed"); return createObservable(id, name).toSingle(); } @HystrixCommand(fallbackMethod = "singleUserRegularFallback") public Single<User> getSingleUserWithRegularFallback(final String id, final String name) { return getSingleUser(id, name); } @HystrixCommand(fallbackMethod = "singleUserRxFallback") public Single<User> getSingleUserWithRxFallback(final String id, final String name) { return getSingleUser(id, name); } User singleUserRegularFallback(final String id, final String name) { return new User("default_id", "default_name"); } Single<User> singleUserRxFallback(final String id, final String name) { return createObservable("default_id", "default_name").toSingle(); } @HystrixCommand(fallbackMethod = "regularFallback", observableExecutionMode = ObservableExecutionMode.LAZY) public Observable<User> getUserRegularFallback(final String id, final String name) { validate(id, name, "getUser has failed"); return createObservable(id, name); } @HystrixCommand(fallbackMethod = "rxFallback") public Observable<User> getUserRxFallback(final String id, final String name) { validate(id, name, "getUserRxFallback has failed"); return createObservable(id, name); } @HystrixCommand(fallbackMethod = "rxCommandFallback", observableExecutionMode = ObservableExecutionMode.LAZY) public Observable<User> getUserRxCommandFallback(final String id, final String name) { validate(id, name, "getUserRxCommandFallback has failed"); return createObservable(id, name); } private Observable<User> createObservable(final String id, final String name) { return Observable.create(new Observable.OnSubscribe<User>() { @Override public void call(Subscriber<? super User> observer) { try { if (!observer.isUnsubscribed()) { observer.onNext(new User(id, name + id)); observer.onCompleted(); } } catch (Exception e) { observer.onError(e); } } }); } private void validate(String id, String name, String errorMsg) { if (StringUtils.isBlank(id) || StringUtils.isBlank(name)) { throw new GetUserException(errorMsg); } } private static final class GetUserException extends RuntimeException { public GetUserException(String message) { super(message); } } } }