diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/AbstractCommand.java b/hystrix-core/src/main/java/com/netflix/hystrix/AbstractCommand.java index 5ce0388c1..a2e455273 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/AbstractCommand.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/AbstractCommand.java @@ -62,8 +62,6 @@ import com.netflix.hystrix.util.HystrixTimer.TimerListener; /* package */abstract class AbstractCommand implements HystrixInvokableInfo, HystrixObservable { - // TODO make this package private - private static final Logger logger = LoggerFactory.getLogger(AbstractCommand.class); protected final HystrixCircuitBreaker circuitBreaker; protected final HystrixThreadPool threadPool; @@ -385,7 +383,6 @@ public void call(Subscriber observer) { invocationStartTime = System.currentTimeMillis(); - getRunObservableDecoratedForMetricsAndErrorHandling(performAsyncTimeout) .doOnTerminate(new Action0() { @@ -779,6 +776,7 @@ public Observable call(Throwable t) { Exception e = originalException; Exception fe = getExceptionFromThrowable(t); + if (fe instanceof UnsupportedOperationException) { logger.debug("No fallback for HystrixCommand. ", fe); // debug only since we're throwing the exception and someone higher will do something with it diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTest.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTest.java index be10cd5b3..ae1470d0e 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTest.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTest.java @@ -27,6 +27,7 @@ import org.junit.Before; import org.junit.Test; +import rx.Observable; import rx.Observer; import rx.Scheduler; import rx.functions.Action1; @@ -1992,7 +1993,7 @@ public void run() { } @Test - public void testRejectedExecutionSemaphoreWithFallback() { + public void testRejectedExecutionSemaphoreWithFallbackViaExecute() { final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); final ArrayBlockingQueue results = new ArrayBlockingQueue(2); @@ -2054,6 +2055,71 @@ public void run() { assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); } + @Test + public void testRejectedExecutionSemaphoreWithFallbackViaObserve() { + final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); + final ArrayBlockingQueue> results = new ArrayBlockingQueue>(2); + + final AtomicBoolean exceptionReceived = new AtomicBoolean(); + + Runnable r = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() { + + @Override + public void run() { + try { + results.add(new TestSemaphoreCommandWithFallback(circuitBreaker, 1, 200, false).observe()); + } catch (Exception e) { + e.printStackTrace(); + exceptionReceived.set(true); + } + } + + }); + + // 2 threads, the second should be rejected by the semaphore and return fallback + Thread t1 = new Thread(r); + Thread t2 = new Thread(r); + + t1.start(); + t2.start(); + try { + t1.join(); + t2.join(); + } catch (Exception e) { + e.printStackTrace(); + fail("failed waiting on threads"); + } + + if (exceptionReceived.get()) { + fail("We should have received a fallback response"); + } + + final List blockingList = Observable.merge(results).toList().toBlocking().single(); + + // both threads should have returned values + assertEquals(2, blockingList.size()); + // should contain both a true and false result + assertTrue(blockingList.contains(Boolean.TRUE)); + assertTrue(blockingList.contains(Boolean.FALSE)); + + assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); + assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); + assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); + assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); + assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); + assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); + // the rest should not be involved in this test + assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); + assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); + assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); + + System.out.println("**** DONE"); + + assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); + } + /** * Tests that semaphores are counted separately for commands with unique keys */ diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java index ff726b5c7..4c52cfcb3 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java @@ -36,6 +36,7 @@ import rx.Subscriber; import rx.functions.Action0; import rx.functions.Action1; +import rx.functions.Func0; import rx.functions.Func1; import rx.observers.TestSubscriber; import rx.schedulers.Schedulers; @@ -117,10 +118,10 @@ public void call(Subscriber sub) { } /** - * Test a successful command execution. + * Test a successful semaphore-isolated command execution. */ @Test - public void testExecutionSuccess() { + public void testSempahoreIsolatedObserveSuccess() { try { TestHystrixCommand command = new SuccessfulTestCommand(); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); @@ -158,11 +159,54 @@ public void testExecutionSuccess() { } } + /** + * Test a successful thread-isolated command execution. + */ + @Test + public void testThreadIsolatedObserveSuccess() { + try { + TestHystrixCommand command = new SuccessfulThreadIsolatedTestCommand(); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); + assertEquals(true, command.observe().toBlocking().single()); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); + + assertEquals(null, command.getFailedExecutionException()); + + assertTrue(command.getExecutionTimeInMilliseconds() > -1); + assertTrue(command.isSuccessfulExecution()); + assertFalse(command.isResponseFromFallback()); + + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); + + assertEquals(0, command.builder.metrics.getHealthCounts().getErrorPercentage()); + + assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); + + // thread isolated + assertTrue(command.isExecutedInThread()); + } catch (Exception e) { + e.printStackTrace(); + fail("We received an exception."); + } + } + + /** * Test that a command can not be executed multiple times. */ @Test - public void testExecutionMultipleTimes() { + public void testSempahoreIsolatedObserveMultipleTimes() { SuccessfulTestCommand command = new SuccessfulTestCommand(); assertFalse(command.isExecutionComplete()); // first should succeed @@ -200,7 +244,7 @@ public void testExecutionMultipleTimes() { * Test a command execution that throws an HystrixException and didn't implement getFallback. */ @Test - public void testExecutionKnownFailureWithNoFallback() { + public void testSemaphoreIsolatedObserveKnownFailureWithNoFallback() { TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); TestHystrixCommand command = new KnownFailureTestCommandWithoutFallback(circuitBreaker); try { @@ -246,7 +290,7 @@ public void testExecutionKnownFailureWithNoFallback() { * Test a command execution that throws an unknown exception (not HystrixException) and didn't implement getFallback. */ @Test - public void testExecutionUnknownFailureWithNoFallback() { + public void testSemaphoreIsolatedObserveUnknownFailureWithNoFallback() { TestHystrixCommand command = new UnknownFailureTestCommandWithoutFallback(); try { command.observe().toBlocking().single(); @@ -289,7 +333,7 @@ public void testExecutionUnknownFailureWithNoFallback() { * Test a command execution that fails but has a fallback. */ @Test - public void testExecutionFailureWithFallback() { + public void tesSemaphoreIsolatedtObserveFailureWithFallback() { TestHystrixCommand command = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker()); try { assertEquals(false, command.observe().toBlocking().single()); @@ -325,31 +369,30 @@ public void testExecutionFailureWithFallback() { } /** - * Test a command execution that fails, has getFallback implemented but that fails as well. + * Test a command execution that fails but has a fallback. */ @Test - public void testExecutionFailureWithFallbackFailure() { - TestHystrixCommand command = new KnownFailureTestCommandWithFallbackFailure(); + public void testThreadIsolatedObserveFailureWithFallback() { + TestHystrixCommand command = new KnownFailureThreadIsolatedTestCommandWithFallback(new TestCircuitBreaker()); try { - command.observe().toBlocking().single(); - fail("we shouldn't get here"); - } catch (HystrixRuntimeException e) { - System.out.println("------------------------------------------------"); + assertEquals(false, command.observe().toBlocking().single()); + } catch (Exception e) { e.printStackTrace(); - System.out.println("------------------------------------------------"); - assertNotNull(e.getFallbackException()); + fail("We should have received a response from the fallback."); } + assertEquals("we failed with a simulated async issue", command.getFailedExecutionException().getMessage()); + assertTrue(command.getExecutionTimeInMilliseconds() > -1); assertTrue(command.isFailedExecution()); - assertFalse(command.isResponseFromFallback()); + assertTrue(command.isResponseFromFallback()); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); @@ -360,33 +403,35 @@ public void testExecutionFailureWithFallbackFailure() { assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - // semaphore isolated - assertFalse(command.isExecutedInThread()); + // thread isolated + assertTrue(command.isExecutedInThread()); } /** - * Test a successful command execution (asynchronously). + * Test a command execution that fails, has getFallback implemented but that fails as well. */ @Test - public void testQueueSuccess() { - TestHystrixCommand command = new SuccessfulTestCommand(); + public void testSemaphoreIsolatedObserveFailureWithFallbackFailure() { + TestHystrixCommand command = new KnownFailureTestCommandWithFallbackFailure(); try { - Future future = command.observe().toBlocking().toFuture(); - assertEquals(true, future.get()); - } catch (Exception e) { + command.observe().toBlocking().single(); + fail("we shouldn't get here"); + } catch (HystrixRuntimeException e) { + System.out.println("------------------------------------------------"); e.printStackTrace(); - fail("We received an exception."); + System.out.println("------------------------------------------------"); + assertNotNull(e.getFallbackException()); } assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isSuccessfulExecution()); + assertTrue(command.isFailedExecution()); assertFalse(command.isResponseFromFallback()); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); @@ -394,7 +439,7 @@ public void testQueueSuccess() { assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - assertEquals(0, command.builder.metrics.getHealthCounts().getErrorPercentage()); + assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); @@ -403,71 +448,59 @@ public void testQueueSuccess() { } /** - * Test a command execution (asynchronously) that throws an HystrixException and didn't implement getFallback. + * Test a command execution that fails but has a fallback. */ @Test - public void testQueueKnownFailureWithNoFallback() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - TestHystrixCommand command = new KnownFailureTestCommandWithoutFallback(circuitBreaker); + public void testThreadIsolatedObserveFailureWithFailingFallback() { + TestHystrixCommand command = new KnownFailureThreadIsolatedTestCommandWithFailingFallback(new TestCircuitBreaker()); try { - command.observe().toBlocking().toFuture().get(); - fail("we shouldn't get here"); + assertEquals(false, command.observe().toBlocking().single()); + fail("Should receive no response"); } catch (Exception e) { e.printStackTrace(); - if (e.getCause() instanceof HystrixRuntimeException) { - HystrixRuntimeException de = (HystrixRuntimeException) e.getCause(); - - assertNotNull(de.getFallbackException()); - assertNotNull(de.getImplementingClass()); - } else { - fail("the cause should be HystrixRuntimeException"); - } } + assertEquals("we failed with a simulated async issue", command.getFailedExecutionException().getMessage()); + assertTrue(command.getExecutionTimeInMilliseconds() > -1); assertTrue(command.isFailedExecution()); assertFalse(command.isResponseFromFallback()); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - assertEquals(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); + assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - // semaphore isolated - assertFalse(command.isExecutedInThread()); + // thread isolated + assertTrue(command.isExecutedInThread()); } /** - * Test a command execution (asynchronously) that throws an unknown exception (not HystrixException) and didn't implement getFallback. + * Test a command execution that fails with no fallback. */ @Test - public void testQueueUnknownFailureWithNoFallback() { - TestHystrixCommand command = new UnknownFailureTestCommandWithoutFallback(); + public void testThreadIsolatedObserveFailureWithNoFallback() { + TestHystrixCommand command = new KnownFailureThreadIsolatedTestCommandWithNoFallback(new TestCircuitBreaker()); try { - command.observe().toBlocking().toFuture().get(); - fail("we shouldn't get here"); + assertEquals(false, command.observe().toBlocking().single()); + fail("Should receive no response"); } catch (Exception e) { e.printStackTrace(); - if (e.getCause() instanceof HystrixRuntimeException) { - HystrixRuntimeException de = (HystrixRuntimeException) e.getCause(); - assertNotNull(de.getFallbackException()); - assertNotNull(de.getImplementingClass()); - } else { - fail("the cause should be HystrixRuntimeException"); - } } + assertEquals("we failed with a simulated async issue", command.getFailedExecutionException().getMessage()); + assertTrue(command.getExecutionTimeInMilliseconds() > -1); assertTrue(command.isFailedExecution()); assertFalse(command.isResponseFromFallback()); @@ -488,38 +521,39 @@ public void testQueueUnknownFailureWithNoFallback() { assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - // semaphore isolated - assertFalse(command.isExecutedInThread()); + // thread isolated + assertTrue(command.isExecutedInThread()); } /** - * Test a command execution (asynchronously) that fails but has a fallback. + * Test a command execution that fails with no fallback. */ @Test - public void testQueueFailureWithFallback() { - TestHystrixCommand command = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker()); + public void testSemaphoreIsolatedObserveFailureWithTimeoutAndFallback() { + TestHystrixCommand command = new KnownFailureSemaphoreIsolatedTimeoutTestCommandWithFallback(new TestCircuitBreaker()); try { - Future future = command.observe().toBlocking().toFuture(); - assertEquals(false, future.get()); + assertEquals(false, command.observe().toBlocking().single()); } catch (Exception e) { e.printStackTrace(); fail("We should have received a response from the fallback."); } + assertNull(command.getFailedExecutionException()); + assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); + assertFalse(command.isFailedExecution()); assertTrue(command.isResponseFromFallback()); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); @@ -531,153 +565,42 @@ public void testQueueFailureWithFallback() { } /** - * Test a command execution (asynchronously) that fails, has getFallback implemented but that fails as well. + * Test a command execution that fails with no fallback. */ @Test - public void testQueueFailureWithFallbackFailure() { - TestHystrixCommand command = new KnownFailureTestCommandWithFallbackFailure(); + public void testThreadIsolatedObserveFailureWithTimeoutAndFallback() { + TestHystrixCommand command = new KnownFailureThreadIsolatedTimeoutTestCommandWithFallback(new TestCircuitBreaker()); try { - command.observe().toBlocking().toFuture().get(); - fail("we shouldn't get here"); + assertEquals(false, command.observe().toBlocking().single()); } catch (Exception e) { - if (e.getCause() instanceof HystrixRuntimeException) { - HystrixRuntimeException de = (HystrixRuntimeException) e.getCause(); - e.printStackTrace(); - assertNotNull(de.getFallbackException()); - } else { - fail("the cause should be HystrixRuntimeException"); - } + e.printStackTrace(); + fail("We should have received a response from the fallback."); } + assertNull(command.getFailedExecutionException()); + assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - assertFalse(command.isResponseFromFallback()); + assertFalse(command.isFailedExecution()); + assertTrue(command.isResponseFromFallback()); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a successful command execution. - */ - @Test - public void testObserveSuccess() { - try { - TestHystrixCommand command = new SuccessfulTestCommand(); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - - assertEquals(true, command.observe().toBlocking().single()); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - - assertEquals(null, command.getFailedExecutionException()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isSuccessfulExecution()); - assertFalse(command.isResponseFromFallback()); - - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(0, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } catch (Exception e) { - e.printStackTrace(); - fail("We received an exception."); - } - } - - /** - * Test a successful command execution. - */ - @Test - public void testObserveSuccessWithFallback() { - try { - final TestHystrixCommand command = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker()); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - - final CountDownLatch latch = new CountDownLatch(1); - - command.observe().subscribe(new Subscriber() { - @Override - public void onCompleted() { - System.out.println("*** onCompleted"); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - - latch.countDown(); - } - - @Override - public void onError(Throwable e) { - System.out.println("*** onError : " + e); - fail(e.getMessage()); - } - - @Override - public void onNext(Boolean b) { - System.out.println("*** onNext : " + b); - assertEquals(false, b); - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertFalse(command.isSuccessfulExecution()); - assertTrue(command.isFailedExecution()); - assertTrue(command.isResponseFromFallback()); - } - }); - - latch.await(1000, TimeUnit.MILLISECONDS); - - } catch (Exception e) { - e.printStackTrace(); - fail("We received an exception."); - } + // thread isolated + assertTrue(command.isExecutedInThread()); } /** @@ -1176,7 +1099,7 @@ public void testExecutionTimeoutWithNoFallbackUsingSemaphoreIsolation() { command.observe().toBlocking().single(); fail("we shouldn't get here"); } catch (Exception e) { - // e.printStackTrace(); + e.printStackTrace(); if (e instanceof HystrixRuntimeException) { HystrixRuntimeException de = (HystrixRuntimeException) e; assertNotNull(de.getFallbackException()); @@ -1216,377 +1139,17 @@ public void testExecutionTimeoutWithNoFallbackUsingSemaphoreIsolation() { } /** - * Test a command execution timeout where the command implemented getFallback. - */ - @Test - public void testExecutionTimeoutWithFallbackUsingSemaphoreIsolation() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS, ExecutionIsolationStrategy.SEMAPHORE); - try { - assertEquals(false, command.observe().toBlocking().single()); - // the time should be 50+ since we timeout at 50ms - assertTrue("Execution Time is: " + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50); - assertTrue(command.isResponseTimedOut()); - assertTrue(command.isResponseFromFallback()); - } catch (Exception e) { - e.printStackTrace(); - fail("We should have received a response from the fallback."); - } - - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a command execution timeout where the command implemented getFallback but it fails. - */ - @Test - public void testExecutionTimeoutFallbackFailureUsingSemaphoreIsolation() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_FAILURE, ExecutionIsolationStrategy.SEMAPHORE); - try { - command.observe().toBlocking().single(); - fail("we shouldn't get here"); - } catch (Exception e) { - if (e instanceof HystrixRuntimeException) { - HystrixRuntimeException de = (HystrixRuntimeException) e; - assertNotNull(de.getFallbackException()); - assertFalse(de.getFallbackException() instanceof UnsupportedOperationException); - assertNotNull(de.getImplementingClass()); - assertNotNull(de.getCause()); - assertTrue(de.getCause() instanceof TimeoutException); - } else { - fail("the exception should be HystrixRuntimeException"); - } - } - // the time should be 50+ since we timeout at 50ms - assertTrue("Execution Time is: " + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a command execution timeout where the command didn't implement getFallback. - */ - @Test - public void testExecutionTimeoutWithNoFallbackUsingThreadIsolation() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_NOT_IMPLEMENTED, ExecutionIsolationStrategy.THREAD); - try { - command.observe().toBlocking().single(); - fail("we shouldn't get here"); - } catch (Exception e) { - // e.printStackTrace(); - if (e instanceof HystrixRuntimeException) { - HystrixRuntimeException de = (HystrixRuntimeException) e; - assertNotNull(de.getFallbackException()); - assertTrue(de.getFallbackException() instanceof UnsupportedOperationException); - assertNotNull(de.getImplementingClass()); - assertNotNull(de.getCause()); - assertTrue(de.getCause() instanceof TimeoutException); - } else { - fail("the exception should be HystrixRuntimeException"); - } - } - // the time should be 50+ since we timeout at 50ms - assertTrue("Execution Time is: " + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50); - - assertTrue(command.isResponseTimedOut()); - assertFalse(command.isResponseFromFallback()); - assertFalse(command.isResponseRejected()); - - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // thread isolated - assertTrue(command.isExecutedInThread()); - } - - /** - * Test a command execution timeout where the command implemented getFallback. - */ - @Test - public void testExecutionTimeoutWithFallbackUsingThreadIsolation() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS, ExecutionIsolationStrategy.THREAD); - try { - assertEquals(false, command.observe().toBlocking().single()); - // the time should be 50+ since we timeout at 50ms - assertTrue("Execution Time is: " + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50); - assertTrue(command.isResponseTimedOut()); - assertTrue(command.isResponseFromFallback()); - } catch (Exception e) { - e.printStackTrace(); - fail("We should have received a response from the fallback."); - } - - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // thread isolated - assertTrue(command.isExecutedInThread()); - } - - /** - * Test a command execution timeout where the command implemented getFallback but it fails. - */ - @Test - public void testExecutionTimeoutFallbackFailureUsingThreadIsolation() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_FAILURE, ExecutionIsolationStrategy.THREAD); - try { - command.observe().toBlocking().single(); - fail("we shouldn't get here"); - } catch (Exception e) { - if (e instanceof HystrixRuntimeException) { - HystrixRuntimeException de = (HystrixRuntimeException) e; - assertNotNull(de.getFallbackException()); - assertFalse(de.getFallbackException() instanceof UnsupportedOperationException); - assertNotNull(de.getImplementingClass()); - assertNotNull(de.getCause()); - assertTrue(de.getCause() instanceof TimeoutException); - } else { - fail("the exception should be HystrixRuntimeException"); - } - } - // the time should be 50+ since we timeout at 50ms - assertTrue("Execution Time is: " + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // thread isolated - assertTrue(command.isExecutedInThread()); - } - - /** - * Test that the circuit-breaker counts a command execution timeout as a 'timeout' and not just failure. - */ - @Test - public void testCircuitBreakerOnExecutionTimeout() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS); - try { - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - - command.observe().toBlocking().single(); - - assertTrue(command.isResponseFromFallback()); - assertFalse(command.isCircuitBreakerOpen()); - assertFalse(command.isResponseShortCircuited()); - - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - - } catch (Exception e) { - e.printStackTrace(); - fail("We should have received a response from the fallback."); - } - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isResponseTimedOut()); - - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test that the command finishing AFTER a timeout (because thread continues in background) does not register a SUCCESS - */ - @Test - public void testCountersOnExecutionTimeout() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS); - try { - command.observe().toBlocking().single(); - - /* wait long enough for the command to have finished */ - Thread.sleep(200); - - /* response should still be the same as 'testCircuitBreakerOnExecutionTimeout' */ - assertTrue(command.isResponseFromFallback()); - assertFalse(command.isCircuitBreakerOpen()); - assertFalse(command.isResponseShortCircuited()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isResponseTimedOut()); - assertFalse(command.isSuccessfulExecution()); - - /* failure and timeout count should be the same as 'testCircuitBreakerOnExecutionTimeout' */ - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - - /* we should NOT have a 'success' counter */ - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - - } catch (Exception e) { - e.printStackTrace(); - fail("We should have received a response from the fallback."); - } - - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a queued command execution timeout where the command didn't implement getFallback. - *

- * We specifically want to protect against developers queuing commands and using observe().toBlocking().toFuture().get() without a timeout (such as observe().toBlocking().toFuture().get(3000, - * TimeUnit.Milliseconds)) and ending up blocking - * indefinitely by skipping the timeout protection of the observe().toBlocking().single() command. - */ - @Test - public void testQueuedExecutionTimeoutWithNoFallback() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_NOT_IMPLEMENTED); - try { - command.observe().toBlocking().toFuture().get(); - fail("we shouldn't get here"); - } catch (Exception e) { - e.printStackTrace(); - if (e instanceof ExecutionException && e.getCause() instanceof HystrixRuntimeException) { - HystrixRuntimeException de = (HystrixRuntimeException) e.getCause(); - assertNotNull(de.getFallbackException()); - assertTrue(de.getFallbackException() instanceof UnsupportedOperationException); - assertNotNull(de.getImplementingClass()); - assertNotNull(de.getCause()); - assertTrue(de.getCause() instanceof TimeoutException); - } else { - fail("the exception should be ExecutionException with cause as HystrixRuntimeException"); - } - } - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isResponseTimedOut()); - - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a queued command execution timeout where the command implemented getFallback. - *

- * We specifically want to protect against developers queuing commands and using observe().toBlocking().toFuture().get() without a timeout (such as observe().toBlocking().toFuture().get(3000, - * TimeUnit.Milliseconds)) and ending up blocking - * indefinitely by skipping the timeout protection of the observe().toBlocking().single() command. + * Test a command execution timeout where the command implemented getFallback. */ @Test - public void testQueuedExecutionTimeoutWithFallback() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS); + public void testExecutionTimeoutWithFallbackUsingSemaphoreIsolation() { + TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS, ExecutionIsolationStrategy.SEMAPHORE); try { - assertEquals(false, command.observe().toBlocking().toFuture().get()); + assertEquals(false, command.observe().toBlocking().single()); + // the time should be 50+ since we timeout at 50ms + assertTrue("Execution Time is: " + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50); + assertTrue(command.isResponseTimedOut()); + assertTrue(command.isResponseFromFallback()); } catch (Exception e) { e.printStackTrace(); fail("We should have received a response from the fallback."); @@ -1613,31 +1176,29 @@ public void testQueuedExecutionTimeoutWithFallback() { } /** - * Test a queued command execution timeout where the command implemented getFallback but it fails. - *

- * We specifically want to protect against developers queuing commands and using observe().toBlocking().toFuture().get() without a timeout (such as observe().toBlocking().toFuture().get(3000, - * TimeUnit.Milliseconds)) and ending up blocking - * indefinitely by skipping the timeout protection of the observe().toBlocking().single() command. + * Test a command execution timeout where the command implemented getFallback but it fails. */ @Test - public void testQueuedExecutionTimeoutFallbackFailure() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_FAILURE); + public void testExecutionTimeoutFallbackFailureUsingSemaphoreIsolation() { + TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_FAILURE, ExecutionIsolationStrategy.SEMAPHORE); try { - command.observe().toBlocking().toFuture().get(); + command.observe().toBlocking().single(); fail("we shouldn't get here"); } catch (Exception e) { - if (e instanceof ExecutionException && e.getCause() instanceof HystrixRuntimeException) { - HystrixRuntimeException de = (HystrixRuntimeException) e.getCause(); + if (e instanceof HystrixRuntimeException) { + e.printStackTrace(); + HystrixRuntimeException de = (HystrixRuntimeException) e; assertNotNull(de.getFallbackException()); assertFalse(de.getFallbackException() instanceof UnsupportedOperationException); assertNotNull(de.getImplementingClass()); assertNotNull(de.getCause()); assertTrue(de.getCause() instanceof TimeoutException); } else { - fail("the exception should be ExecutionException with cause as HystrixRuntimeException"); + fail("the exception should be HystrixRuntimeException"); } } - + // the time should be 50+ since we timeout at 50ms + assertTrue("Execution Time is: " + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); @@ -1659,15 +1220,11 @@ public void testQueuedExecutionTimeoutFallbackFailure() { } /** - * Test a queued command execution timeout where the command didn't implement getFallback. - *

- * We specifically want to protect against developers queuing commands and using observe().toBlocking().toFuture().get() without a timeout (such as observe().toBlocking().toFuture().get(3000, - * TimeUnit.Milliseconds)) and ending up blocking - * indefinitely by skipping the timeout protection of the observe().toBlocking().single() command. + * Test a command execution timeout where the command didn't implement getFallback. */ @Test - public void testObservedExecutionTimeoutWithNoFallback() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_NOT_IMPLEMENTED); + public void testExecutionTimeoutWithNoFallbackUsingThreadIsolation() { + TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_NOT_IMPLEMENTED, ExecutionIsolationStrategy.THREAD); try { command.observe().toBlocking().single(); fail("we shouldn't get here"); @@ -1681,12 +1238,15 @@ public void testObservedExecutionTimeoutWithNoFallback() { assertNotNull(de.getCause()); assertTrue(de.getCause() instanceof TimeoutException); } else { - fail("the exception should be ExecutionException with cause as HystrixRuntimeException"); + fail("the exception should be HystrixRuntimeException"); } } + // the time should be 50+ since we timeout at 50ms + assertTrue("Execution Time is: " + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50); - assertTrue(command.getExecutionTimeInMilliseconds() > -1); assertTrue(command.isResponseTimedOut()); + assertFalse(command.isResponseFromFallback()); + assertFalse(command.isResponseRejected()); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); @@ -1704,22 +1264,22 @@ public void testObservedExecutionTimeoutWithNoFallback() { assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - // semaphore isolated - assertFalse(command.isExecutedInThread()); + // thread isolated + assertTrue(command.isExecutedInThread()); } /** - * Test a queued command execution timeout where the command implemented getFallback. - *

- * We specifically want to protect against developers queuing commands and using observe().toBlocking().toFuture().get() without a timeout (such as observe().toBlocking().toFuture().get(3000, - * TimeUnit.Milliseconds)) and ending up blocking - * indefinitely by skipping the timeout protection of the observe().toBlocking().single() command. + * Test a command execution timeout where the command implemented getFallback. */ @Test - public void testObservedExecutionTimeoutWithFallback() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS); + public void testExecutionTimeoutWithFallbackUsingThreadIsolation() { + TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS, ExecutionIsolationStrategy.THREAD); try { assertEquals(false, command.observe().toBlocking().single()); + // the time should be 50+ since we timeout at 50ms + assertTrue("Execution Time is: " + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50); + assertTrue(command.isResponseTimedOut()); + assertTrue(command.isResponseFromFallback()); } catch (Exception e) { e.printStackTrace(); fail("We should have received a response from the fallback."); @@ -1741,20 +1301,16 @@ public void testObservedExecutionTimeoutWithFallback() { assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - // semaphore isolated - assertFalse(command.isExecutedInThread()); + // thread isolated + assertTrue(command.isExecutedInThread()); } /** - * Test a queued command execution timeout where the command implemented getFallback but it fails. - *

- * We specifically want to protect against developers queuing commands and using observe().toBlocking().toFuture().get() without a timeout (such as observe().toBlocking().toFuture().get(3000, - * TimeUnit.Milliseconds)) and ending up blocking - * indefinitely by skipping the timeout protection of the observe().toBlocking().single() command. + * Test a command execution timeout where the command implemented getFallback but it fails. */ @Test - public void testObservedExecutionTimeoutFallbackFailure() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_FAILURE); + public void testExecutionTimeoutFallbackFailureUsingThreadIsolation() { + TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_FAILURE, ExecutionIsolationStrategy.THREAD); try { command.observe().toBlocking().single(); fail("we shouldn't get here"); @@ -1767,10 +1323,11 @@ public void testObservedExecutionTimeoutFallbackFailure() { assertNotNull(de.getCause()); assertTrue(de.getCause() instanceof TimeoutException); } else { - fail("the exception should be ExecutionException with cause as HystrixRuntimeException"); + fail("the exception should be HystrixRuntimeException"); } } - + // the time should be 50+ since we timeout at 50ms + assertTrue("Execution Time is: " + command.getExecutionTimeInMilliseconds(), command.getExecutionTimeInMilliseconds() >= 50); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); @@ -1787,6 +1344,107 @@ public void testObservedExecutionTimeoutFallbackFailure() { assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); + // thread isolated + assertTrue(command.isExecutedInThread()); + } + + /** + * Test that the circuit-breaker counts a command execution timeout as a 'timeout' and not just failure. + */ + @Test + public void testCircuitBreakerOnExecutionTimeout() { + TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS); + try { + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + + command.observe().toBlocking().single(); + + assertTrue(command.isResponseFromFallback()); + assertFalse(command.isCircuitBreakerOpen()); + assertFalse(command.isResponseShortCircuited()); + + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); + + } catch (Exception e) { + e.printStackTrace(); + fail("We should have received a response from the fallback."); + } + + assertTrue(command.getExecutionTimeInMilliseconds() > -1); + assertTrue(command.isResponseTimedOut()); + + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); + + assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); + + assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); + + // semaphore isolated + assertFalse(command.isExecutedInThread()); + } + + /** + * Test that the command finishing AFTER a timeout (because thread continues in background) does not register a SUCCESS + */ + @Test + public void testCountersOnExecutionTimeout() { + TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS); + try { + command.observe().toBlocking().single(); + + /* wait long enough for the command to have finished */ + Thread.sleep(200); + + /* response should still be the same as 'testCircuitBreakerOnExecutionTimeout' */ + assertTrue(command.isResponseFromFallback()); + assertFalse(command.isCircuitBreakerOpen()); + assertFalse(command.isResponseShortCircuited()); + + assertTrue(command.getExecutionTimeInMilliseconds() > -1); + assertTrue(command.isResponseTimedOut()); + assertFalse(command.isSuccessfulExecution()); + + /* failure and timeout count should be the same as 'testCircuitBreakerOnExecutionTimeout' */ + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + + /* we should NOT have a 'success' counter */ + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); + + } catch (Exception e) { + e.printStackTrace(); + fail("We should have received a response from the fallback."); + } + + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); + assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); + assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); + + assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); + + assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); + // semaphore isolated assertFalse(command.isExecutedInThread()); } @@ -6487,7 +6145,11 @@ public void testExecutionPartialSuccessWithMoreIntelligentFallback() { } static TestCommandBuilder testPropsBuilder() { - return new TestCommandBuilder(); + return new TestCommandBuilder(ExecutionIsolationStrategy.SEMAPHORE); + } + + static TestCommandBuilder testPropsBuilder(ExecutionIsolationStrategy isolationStrategy) { + return new TestCommandBuilder(isolationStrategy); } static class TestCommandBuilder { @@ -6497,13 +6159,17 @@ static class TestCommandBuilder { HystrixThreadPoolKey threadPoolKey = null; HystrixCircuitBreaker circuitBreaker = _cb; HystrixThreadPool threadPool = null; - HystrixCommandProperties.Setter commandPropertiesDefaults = HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE); + HystrixCommandProperties.Setter commandPropertiesDefaults; HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults = HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder(); HystrixCommandMetrics metrics = _cb.metrics; TryableSemaphoreActual fallbackSemaphore = null; TryableSemaphoreActual executionSemaphore = null; TestExecutionHook executionHook = new TestExecutionHook(); + TestCommandBuilder(ExecutionIsolationStrategy isolationStrategy) { + this.commandPropertiesDefaults = HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolationStrategy); + } + TestCommandBuilder setOwner(HystrixCommandGroupKey owner) { this.owner = owner; return this; @@ -6578,6 +6244,26 @@ protected Observable construct() { } + /** + * Successful execution - no fallback implementation. + */ + private static class SuccessfulThreadIsolatedTestCommand extends TestHystrixCommand { + + public SuccessfulThreadIsolatedTestCommand() { + this(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)); + } + + public SuccessfulThreadIsolatedTestCommand(HystrixCommandProperties.Setter properties) { + super(testPropsBuilder().setCommandPropertiesDefaults(properties)); + } + + @Override + protected Observable construct() { + return Observable.just(true); + } + + } + /** * Successful execution - no fallback implementation. */ @@ -6769,6 +6455,86 @@ protected Observable resumeWithFallback() { } } + /** + * Failing execution - successful fallback implementation. + */ + private static class KnownFailureThreadIsolatedTestCommandWithFallback extends TestHystrixCommand { + + public KnownFailureThreadIsolatedTestCommandWithFallback(TestCircuitBreaker circuitBreaker) { + super(testPropsBuilder(ExecutionIsolationStrategy.THREAD).setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)); + } + + @Override + protected Observable construct() { + return Observable.error(new RuntimeException("we failed with a simulated async issue")); + } + + @Override + protected Observable resumeWithFallback() { + return Observable.just(false); + } + } + + /** + * Failing execution - successful fallback implementation. + */ + private static class KnownFailureSemaphoreIsolatedTimeoutTestCommandWithFallback extends TestHystrixCommand { + + public KnownFailureSemaphoreIsolatedTimeoutTestCommandWithFallback(TestCircuitBreaker circuitBreaker) { + super(testPropsBuilder(ExecutionIsolationStrategy.SEMAPHORE).setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)); + } + + @Override + protected Observable construct() { + return Observable.defer(new Func0>() { + @Override + public Observable call() { + try { + Thread.sleep(2000); + } catch (InterruptedException ie) { + return Observable.error(ie); + } + return Observable.error(new RuntimeException("we failed with a simulated async issue")); + } + }); + } + + @Override + protected Observable resumeWithFallback() { + return Observable.just(false).observeOn(Schedulers.computation()); + } + } + + /** + * Failing execution - successful fallback implementation. + */ + private static class KnownFailureThreadIsolatedTimeoutTestCommandWithFallback extends TestHystrixCommand { + + public KnownFailureThreadIsolatedTimeoutTestCommandWithFallback(TestCircuitBreaker circuitBreaker) { + super(testPropsBuilder(ExecutionIsolationStrategy.THREAD).setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)); + } + + @Override + protected Observable construct() { + return Observable.defer(new Func0>() { + @Override + public Observable call() { + try { + Thread.sleep(2000); + } catch (InterruptedException ie) { + return Observable.error(ie); + } + return Observable.error(new RuntimeException("we failed with a simulated async issue")); + } + }); + } + + @Override + protected Observable resumeWithFallback() { + return Observable.just(false).observeOn(Schedulers.computation()); + } + } + /** * Failed execution - fallback implementation throws exception. */ @@ -6791,6 +6557,41 @@ protected Observable resumeWithFallback() { } } + /** + * Failing execution - failing fallback implementation. + */ + private static class KnownFailureThreadIsolatedTestCommandWithFailingFallback extends TestHystrixCommand { + + public KnownFailureThreadIsolatedTestCommandWithFailingFallback(TestCircuitBreaker circuitBreaker) { + super(testPropsBuilder(ExecutionIsolationStrategy.THREAD).setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)); + } + + @Override + protected Observable construct() { + return Observable.error(new RuntimeException("we failed with a simulated async issue")); + } + + @Override + protected Observable resumeWithFallback() { + return Observable.error(new RuntimeException("we failed with a simulated async fallback issue")); + } + } + + /** + * Failing execution - failing fallback implementation. + */ + private static class KnownFailureThreadIsolatedTestCommandWithNoFallback extends TestHystrixCommand { + + public KnownFailureThreadIsolatedTestCommandWithNoFallback(TestCircuitBreaker circuitBreaker) { + super(testPropsBuilder(ExecutionIsolationStrategy.THREAD).setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)); + } + + @Override + protected Observable construct() { + return Observable.error(new RuntimeException("we failed with a simulated async issue")); + } + } + /** * A Command implementation that supports caching. */