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 57fe2afc3..f59137a7d 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/AbstractCommand.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/AbstractCommand.java @@ -65,7 +65,7 @@ import com.netflix.hystrix.util.HystrixTimer; import com.netflix.hystrix.util.HystrixTimer.TimerListener; -/* package */abstract class AbstractCommand implements HystrixExecutableInfo, HystrixObservable { +/* package */abstract class AbstractCommand implements HystrixInvokableInfo, HystrixObservable { // TODO make this package private private static final Logger logger = LoggerFactory.getLogger(AbstractCommand.class); @@ -1146,7 +1146,7 @@ public AbstractCommand getCommand() { } /** - * @return {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixAsyncCommand} objects. + * @return {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixFutureCommand} objects. *

* The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace with, * common business purpose etc. @@ -1175,7 +1175,7 @@ public HystrixThreadPoolKey getThreadPoolKey() { } /** - * The {@link HystrixCommandMetrics} associated with this {@link HystrixAsyncCommand} instance. + * The {@link HystrixCommandMetrics} associated with this {@link HystrixFutureCommand} instance. * * @return HystrixCommandMetrics */ @@ -1184,7 +1184,7 @@ public HystrixCommandMetrics getMetrics() { } /** - * The {@link HystrixCommandProperties} associated with this {@link HystrixAsyncCommand} instance. + * The {@link HystrixCommandProperties} associated with this {@link HystrixFutureCommand} instance. * * @return HystrixCommandProperties */ diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixAsyncCommand.java b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixAsyncCommand.java deleted file mode 100644 index 2816aa002..000000000 --- a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixAsyncCommand.java +++ /dev/null @@ -1,537 +0,0 @@ -/** - * Copyright 2012 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; - -import java.lang.ref.Reference; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import rx.Observable; -import rx.functions.Action0; -import rx.functions.Action1; -import rx.subjects.ReplaySubject; - -import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy; -import com.netflix.hystrix.exception.HystrixBadRequestException; -import com.netflix.hystrix.exception.HystrixRuntimeException; -import com.netflix.hystrix.exception.HystrixRuntimeException.FailureType; -import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook; -import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy; -import com.netflix.hystrix.util.HystrixTimer.TimerListener; - -/** - * Used to wrap code that will execute potentially risky functionality (typically meaning a service call over the network) - * with fault and latency tolerance, statistics and performance metrics capture, circuit breaker and bulkhead functionality. - * This command is essentially a blocking command but provides an Observable facade if used with observe() - * - * @param - * the return type - * - * @ThreadSafe - */ -public abstract class HystrixAsyncCommand extends AbstractCommand implements HystrixExecutable, HystrixExecutableInfo, HystrixObservable { - - /** - * Construct a {@link HystrixAsyncCommand} with defined {@link HystrixCommandGroupKey}. - *

- * The {@link HystrixCommandKey} will be derived from the implementing class name. - * - * @param group - * {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixAsyncCommand} objects. - *

- * The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace with, - * common business purpose etc. - */ - protected HystrixAsyncCommand(HystrixCommandGroupKey group) { - // use 'null' to specify use the default - this(new Setter(group)); - } - - /** - * Construct a {@link HystrixAsyncCommand} with defined {@link Setter} that allows injecting property and strategy overrides and other optional arguments. - *

- * NOTE: The {@link HystrixCommandKey} is used to associate a {@link HystrixAsyncCommand} with {@link HystrixCircuitBreaker}, {@link HystrixCommandMetrics} and other objects. - *

- * Do not create multiple {@link HystrixAsyncCommand} implementations with the same {@link HystrixCommandKey} but different injected default properties as the first instantiated will win. - *

- * Properties passed in via {@link Setter#andCommandPropertiesDefaults} or {@link Setter#andThreadPoolPropertiesDefaults} are cached for the given {@link HystrixCommandKey} for the life of the JVM - * or until {@link Hystrix#reset()} is called. Dynamic properties allow runtime changes. Read more on the Hystrix Wiki. - * - * @param setter - * Fluent interface for constructor arguments - */ - protected HystrixAsyncCommand(Setter setter) { - // use 'null' to specify use the default - this(setter.groupKey, setter.commandKey, setter.threadPoolKey, null, null, setter.commandPropertiesDefaults, setter.threadPoolPropertiesDefaults, null, null, null, null, null); - } - - /** - * Allow constructing a {@link HystrixAsyncCommand} with injection of most aspects of its functionality. - *

- * Some of these never have a legitimate reason for injection except in unit testing. - *

- * Most of the args will revert to a valid default if 'null' is passed in. - */ - /* package for testing */HystrixAsyncCommand(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, - HystrixCommandProperties.Setter commandPropertiesDefaults, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults, - HystrixCommandMetrics metrics, TryableSemaphore fallbackSemaphore, TryableSemaphore executionSemaphore, - HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) { - super(group, key, threadPoolKey, circuitBreaker, threadPool, commandPropertiesDefaults, threadPoolPropertiesDefaults, metrics, fallbackSemaphore, executionSemaphore, propertiesStrategy, executionHook); - } - - /** - * Fluent interface for arguments to the {@link HystrixAsyncCommand} constructor. - *

- * The required arguments are set via the 'with' factory method and optional arguments via the 'and' chained methods. - *

- * Example: - *

 {@code
-     *  Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GroupName"))
-                .andCommandKey(HystrixCommandKey.Factory.asKey("CommandName"))
-                .andEventNotifier(notifier);
-     * } 
- * - * @NotThreadSafe - */ - final public static class Setter { - - protected final HystrixCommandGroupKey groupKey; - protected HystrixCommandKey commandKey; - protected HystrixThreadPoolKey threadPoolKey; - protected HystrixCommandProperties.Setter commandPropertiesDefaults; - protected HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults; - - /** - * Setter factory method containing required values. - *

- * All optional arguments can be set via the chained methods. - * - * @param groupKey - * {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixAsyncCommand} objects. - *

- * The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace - * with, - * common business purpose etc. - */ - protected Setter(HystrixCommandGroupKey groupKey) { - this.groupKey = groupKey; - - // default to using SEMAPHORE for ObservableCommand - commandPropertiesDefaults = setDefaults(HystrixCommandProperties.Setter()); - } - - /** - * Setter factory method with required values. - *

- * All optional arguments can be set via the chained methods. - * - * @param groupKey - * {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixAsyncCommand} objects. - *

- * The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace - * with, - * common business purpose etc. - */ - public static Setter withGroupKey(HystrixCommandGroupKey groupKey) { - return new Setter(groupKey); - } - - /** - * @param commandKey - * {@link HystrixCommandKey} used to identify a {@link HystrixAsyncCommand} instance for statistics, circuit-breaker, properties, etc. - *

- * By default this will be derived from the instance class name. - *

- * NOTE: Every unique {@link HystrixCommandKey} will result in new instances of {@link HystrixCircuitBreaker}, {@link HystrixCommandMetrics} and {@link HystrixCommandProperties}. - * Thus, - * the number of variants should be kept to a finite and reasonable number to avoid high-memory usage or memory leacks. - *

- * Hundreds of keys is fine, tens of thousands is probably not. - * @return Setter for fluent interface via method chaining - */ - public Setter andCommandKey(HystrixCommandKey commandKey) { - this.commandKey = commandKey; - return this; - } - - /** - * Optional - * - * @param commandPropertiesDefaults - * {@link HystrixCommandProperties.Setter} with property overrides for this specific instance of {@link HystrixAsyncCommand}. - *

- * See the {@link HystrixPropertiesStrategy} JavaDocs for more information on properties and order of precedence. - * @return Setter for fluent interface via method chaining - */ - public Setter andCommandPropertiesDefaults(HystrixCommandProperties.Setter commandPropertiesDefaults) { - this.commandPropertiesDefaults = setDefaults(commandPropertiesDefaults); - return this; - } - - private HystrixCommandProperties.Setter setDefaults(HystrixCommandProperties.Setter commandPropertiesDefaults) { - System.out.println("*********** " + commandPropertiesDefaults.getExecutionIsolationStrategy()); - if (commandPropertiesDefaults.getExecutionIsolationStrategy() == null) { - // default to using SEMAPHORE for ObservableCommand if the user didn't set it - commandPropertiesDefaults.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE); - } - return commandPropertiesDefaults; - } - - } - - public static final class HystrixFuture { - final Action0 cancel; - private final Promise promise; - - private HystrixFuture(Promise promise, Action0 cancel) { - this.promise = promise; - this.cancel = cancel; - } - - public static HystrixFuture create(Promise promise, Action0 cancel) { - return new HystrixFuture(promise, cancel); - } - - public static HystrixFuture create(Promise promise) { - return new HystrixFuture(promise, null); - } - - /** - * Attempt cancellation. Not all implementations support this. - */ - public final void cancel() { - if (cancel != null) { - cancel.call(); - } - } - - public Observable asObservable() { - return promise.replay.asObservable(); - } - - public void addListener(Action1 onSuccess, Action1 onError) { - promise.replay.subscribe(onSuccess, onError); - } - } - - public static final class Promise { - private final ReplaySubject replay = ReplaySubject.createWithSize(1); - - private Promise() { - } - - public static Promise create() { - return new Promise(); - } - - public final synchronized void onError(Throwable e) { - replay.onError(e); - } - - public final synchronized void onSuccess(R response) { - replay.onNext(response); - replay.onCompleted(); - } - - public final HystrixFuture createFuture() { - return HystrixFuture.create(this); - } - } - - /** - * Implement this method with code to be executed when the command is invoked. - * - * @return R response type - */ - protected abstract HystrixFuture run(); - - /** - * If {@link #execute()} or {@link #queue()} fails in any way then this method will be invoked to provide an opportunity to return a fallback response. - *

- * This should do work that does not require network transport to produce. - *

- * In other words, this should be a static or cached result that can immediately be returned upon failure. - *

- * If network traffic is wanted for fallback (such as going to MemCache) then the fallback implementation should invoke another {@link HystrixAsyncCommand} instance that protects against that - * network - * access and possibly has another level of fallback that does not involve network access. - *

- * DEFAULT BEHAVIOR: It throws UnsupportedOperationException. - * - * @return R or throw UnsupportedOperationException if not implemented - */ - protected HystrixFuture getFallback() { - throw new UnsupportedOperationException("No fallback available."); - } - - @Override - final protected Observable getExecutionObservable() { - try { - return run().asObservable(); - } catch (Throwable e) { - return Observable.error(e); - } - } - - @Override - final protected Observable getFallbackObservable() { - try { - return getFallback().asObservable(); - } catch (Throwable e) { - e.printStackTrace(); - return Observable.error(e); - } - } - - /** - * Used for synchronous execution of command. - * - * @return R - * Result of {@link #run()} execution or a fallback from {@link #getFallback()} if the command fails for any reason. - * @throws HystrixRuntimeException - * if a failure occurs and a fallback cannot be retrieved - * @throws HystrixBadRequestException - * if invalid arguments or state were used representing a user failure, not a system failure - * @throws IllegalStateException - * if invoked more than once - */ - final public R execute() { - try { - return queue().get(); - } catch (Exception e) { - throw decomposeException(e); - } - } - - /** - * Used for asynchronous execution of command. - *

- * This will queue up the command on the thread pool and return an {@link Future} to get the result once it completes. - *

- * NOTE: If configured to not run in a separate thread, this will have the same effect as {@link #execute()} and will block. - *

- * We don't throw an exception but just flip to synchronous execution so code doesn't need to change in order to switch a command from running on a separate thread to the calling thread. - * - * @return {@code Future} Result of {@link #run()} execution or a fallback from {@link #getFallback()} if the command fails for any reason. - * @throws HystrixRuntimeException - * if a fallback does not exist - *

- *

    - *
  • via {@code Future.get()} in {@link ExecutionException#getCause()} if a failure occurs
  • - *
  • or immediately if the command can not be queued (such as short-circuited, thread-pool/semaphore rejected)
  • - *
- * @throws HystrixBadRequestException - * via {@code Future.get()} in {@link ExecutionException#getCause()} if invalid arguments or state were used representing a user failure, not a system failure - * @throws IllegalStateException - * if invoked more than once - */ - final public Future queue() { - /* - * --- Schedulers.immediate() - * - * We use the 'immediate' schedule since Future.get() is blocking so we don't want to bother doing the callback to the Future on a separate thread - * as we don't need to separate the Hystrix thread from user threads since they are already providing it via the Future.get() call. - * - * --- performAsyncTimeout: false - * - * We pass 'false' to tell the Observable we will block on it so it doesn't schedule an async timeout. - * - * This optimizes for using the calling thread to do the timeout rather than scheduling another thread. - * - * In a tight-loop of executing commands this optimization saves a few microseconds per execution. - * It also just makes no sense to use a separate thread to timeout the command when the calling thread - * is going to sit waiting on it. - */ - final ObservableCommand o = toObservable(false); - final Future f = o.toBlocking().toFuture(); - - /* special handling of error states that throw immediately */ - if (f.isDone()) { - try { - f.get(); - return f; - } catch (Exception e) { - RuntimeException re = decomposeException(e); - if (re instanceof HystrixBadRequestException) { - return f; - } else if (re instanceof HystrixRuntimeException) { - HystrixRuntimeException hre = (HystrixRuntimeException) re; - if (hre.getFailureType() == FailureType.COMMAND_EXCEPTION || hre.getFailureType() == FailureType.TIMEOUT) { - // we don't throw these types from queue() only from queue().get() as they are execution errors - return f; - } else { - // these are errors we throw from queue() as they as rejection type errors - throw hre; - } - } else { - throw re; - } - } - } - - return new Future() { - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return f.cancel(mayInterruptIfRunning); - } - - @Override - public boolean isCancelled() { - return f.isCancelled(); - } - - @Override - public boolean isDone() { - return f.isDone(); - } - - @Override - public R get() throws InterruptedException, ExecutionException { - return performBlockingGetWithTimeout(o, f); - } - - /** - * --- Non-Blocking Timeout (performAsyncTimeout:true) --- - * - * When 'toObservable' is done with non-blocking timeout then timeout functionality is provided - * by a separate HystrixTimer thread that will "tick" and cancel the underlying async Future inside the Observable. - * - * This method allows stealing that responsibility and letting the thread that's going to block anyways - * do the work to reduce pressure on the HystrixTimer. - * - * Blocking via queue().get() on a non-blocking timeout will work it's just less efficient - * as it involves an extra thread and cancels the scheduled action that does the timeout. - * - * --- Blocking Timeout (performAsyncTimeout:false) --- - * - * When blocking timeout is assumed (default behavior for execute/queue flows) then the async - * timeout will not have been scheduled and this will wait in a blocking manner and if a timeout occurs - * trigger the timeout logic that comes from inside the Observable/Observer. - * - * - * --- Examples - * - * Stack for timeout with performAsyncTimeout=false (note the calling thread via get): - * - * at com.netflix.hystrix.HystrixCommand$TimeoutObservable$1$1.tick(HystrixCommand.java:788) - * at com.netflix.hystrix.HystrixCommand$1.performBlockingGetWithTimeout(HystrixCommand.java:536) - * at com.netflix.hystrix.HystrixCommand$1.get(HystrixCommand.java:484) - * at com.netflix.hystrix.HystrixCommand.execute(HystrixCommand.java:413) - * - * - * Stack for timeout with performAsyncTimeout=true (note the HystrixTimer involved): - * - * at com.netflix.hystrix.HystrixCommand$TimeoutObservable$1$1.tick(HystrixCommand.java:799) - * at com.netflix.hystrix.util.HystrixTimer$1.run(HystrixTimer.java:101) - * - * - * - * @param o - * @param f - * @throws InterruptedException - * @throws ExecutionException - */ - protected R performBlockingGetWithTimeout(final ObservableCommand o, final Future f) throws InterruptedException, ExecutionException { - // shortcut if already done - if (f.isDone()) { - return f.get(); - } - - // it's still working so proceed with blocking/timeout logic - AbstractCommand originalCommand = o.getCommand(); - /** - * One thread will get the timeoutTimer if it's set and clear it then do blocking timeout. - *

- * If non-blocking timeout was scheduled this will unschedule it. If it wasn't scheduled it is basically - * a no-op but fits the same interface so blocking and non-blocking flows both work the same. - *

- * This "originalCommand" concept exists because of request caching. We only do the work and timeout logic - * on the original, not the cached responses. However, whichever the first thread is that comes in to block - * will be the one who performs the timeout logic. - *

- * If request caching is disabled then it will always go into here. - */ - if (originalCommand != null) { - Reference timer = originalCommand.timeoutTimer.getAndSet(null); - if (timer != null) { - /** - * If an async timeout was scheduled then: - * - * - We are going to clear the Reference so the scheduler threads stop managing the timeout - * and we'll take over instead since we're going to be blocking on it anyways. - * - * - Other threads (since we won the race) will just wait on the normal Future which will release - * once the Observable is marked as completed (which may come via timeout) - * - * If an async timeout was not scheduled: - * - * - We go through the same flow as we receive the same interfaces just the "timer.clear()" will do nothing. - */ - // get the timer we'll use to perform the timeout - TimerListener l = timer.get(); - // remove the timer from the scheduler - timer.clear(); - - // determine how long we should wait for, taking into account time since work started - // and when this thread came in to block. If invocationTime hasn't been set then assume time remaining is entire timeout value - // as this maybe a case of multiple threads trying to run this command in which one thread wins but even before the winning thread is able to set - // the starttime another thread going via the Cached command route gets here first. - long timeout = originalCommand.properties.executionIsolationThreadTimeoutInMilliseconds().get(); - long timeRemaining = timeout; - long currTime = System.currentTimeMillis(); - if (originalCommand.invocationStartTime != -1) { - timeRemaining = (originalCommand.invocationStartTime - + originalCommand.properties.executionIsolationThreadTimeoutInMilliseconds().get()) - - currTime; - - } - if (timeRemaining > 0) { - // we need to block with the calculated timeout - try { - return f.get(timeRemaining, TimeUnit.MILLISECONDS); - } catch (TimeoutException e) { - if (l != null) { - // this perform the timeout logic on the Observable/Observer - l.tick(); - } - } - } else { - // this means it should have already timed out so do so if it is not completed - if (!f.isDone()) { - if (l != null) { - l.tick(); - } - } - } - } - } - // other threads will block until the "l.tick" occurs and releases the underlying Future. - return f.get(); - } - - @Override - public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - return get(); - } - - }; - - } - -} diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommand.java b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommand.java index e57a28b2f..4e7c8c787 100755 --- a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommand.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommand.java @@ -44,7 +44,7 @@ * * @ThreadSafe */ -public abstract class HystrixCommand extends AbstractCommand implements HystrixExecutable, HystrixExecutableInfo, HystrixObservable { +public abstract class HystrixCommand extends AbstractCommand implements HystrixExecutable, HystrixInvokableInfo, HystrixObservable { /** * Construct a {@link HystrixCommand} with defined {@link HystrixCommandGroupKey}. diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixExecutableInfo.java b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixInvokableInfo.java similarity index 97% rename from hystrix-core/src/main/java/com/netflix/hystrix/HystrixExecutableInfo.java rename to hystrix-core/src/main/java/com/netflix/hystrix/HystrixInvokableInfo.java index ea968eae6..b6a1f1f97 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixExecutableInfo.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixInvokableInfo.java @@ -17,7 +17,7 @@ import java.util.List; -public interface HystrixExecutableInfo { +public interface HystrixInvokableInfo { public HystrixCommandGroupKey getCommandGroup(); diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixObservableCommand.java b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixObservableCommand.java index 8a838f7ed..81f36591e 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixObservableCommand.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixObservableCommand.java @@ -34,7 +34,7 @@ * * @ThreadSafe */ -public abstract class HystrixObservableCommand extends AbstractCommand implements HystrixObservable, HystrixExecutableInfo { +public abstract class HystrixObservableCommand extends AbstractCommand implements HystrixObservable, HystrixInvokableInfo { /** * Construct a {@link HystrixObservableCommand} with defined {@link HystrixCommandGroupKey}. @@ -205,7 +205,7 @@ private HystrixCommandProperties.Setter setDefaults(HystrixCommandProperties.Set * * @return R or UnsupportedOperationException if not implemented */ - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { return Observable.error(new UnsupportedOperationException("No fallback available.")); } @@ -216,6 +216,6 @@ final protected Observable getExecutionObservable() { @Override final protected Observable getFallbackObservable() { - return onFailureResumeWithFallback(); + return resumeWithFallback(); } } diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestLog.java b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestLog.java index 2bd58f605..6722c285f 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestLog.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestLog.java @@ -68,9 +68,9 @@ public void shutdown(HystrixRequestLog value) { private LinkedBlockingQueue> executedCommands = new LinkedBlockingQueue>(MAX_STORAGE); /** - * History of {@link HystrixExecutableInfo} executed in this request. + * History of {@link HystrixInvokableInfo} executed in this request. */ - private LinkedBlockingQueue> allExecutedCommands = new LinkedBlockingQueue>(MAX_STORAGE); + private LinkedBlockingQueue> allExecutedCommands = new LinkedBlockingQueue>(MAX_STORAGE); // prevent public instantiation private HystrixRequestLog() { @@ -112,7 +112,7 @@ public Collection> getExecutedCommands() { * * @return {@code Collection>} */ - public Collection> getAllExecutedCommands() { + public Collection> getAllExecutedCommands() { return Collections.unmodifiableCollection(allExecutedCommands); } @@ -122,7 +122,7 @@ public Collection> getAllExecutedCommands() { * @param command * {@code HystrixCommand} */ - /* package */void addExecutedCommand(HystrixExecutableInfo command) { + /* package */void addExecutedCommand(HystrixInvokableInfo command) { if (!allExecutedCommands.offer(command)) { // see RequestLog: Reduce Chance of Memory Leak https://github.com/Netflix/Hystrix/issues/53 logger.warn("RequestLog ignoring command after reaching limit of " + MAX_STORAGE + ". See https://github.com/Netflix/Hystrix/issues/53 for more information."); @@ -169,7 +169,7 @@ public String getExecutedCommandsAsString() { StringBuilder builder = new StringBuilder(); int estimatedLength = 0; - for (HystrixExecutableInfo command : allExecutedCommands) { + for (HystrixInvokableInfo command : allExecutedCommands) { builder.setLength(0); builder.append(command.getCommandKey().name()); diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixAsyncCommandTest.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixAsyncCommandTest.java deleted file mode 100644 index 375b64fcc..000000000 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixAsyncCommandTest.java +++ /dev/null @@ -1,7084 +0,0 @@ -package com.netflix.hystrix; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import rx.Notification; -import rx.Observable; -import rx.Observable.OnSubscribe; -import rx.Observer; -import rx.Scheduler; -import rx.Subscriber; -import rx.functions.Action0; -import rx.functions.Action1; -import rx.functions.Func1; -import rx.observers.TestSubscriber; -import rx.schedulers.Schedulers; - -import com.netflix.config.ConfigurationManager; -import com.netflix.hystrix.AbstractCommand.TryableSemaphoreActual; -import com.netflix.hystrix.HystrixCircuitBreakerTest.TestCircuitBreaker; -import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy; -import com.netflix.hystrix.exception.HystrixBadRequestException; -import com.netflix.hystrix.exception.HystrixRuntimeException; -import com.netflix.hystrix.exception.HystrixRuntimeException.FailureType; -import com.netflix.hystrix.strategy.HystrixPlugins; -import com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable; -import com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler; -import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; -import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook; -import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy; -import com.netflix.hystrix.strategy.properties.HystrixProperty; -import com.netflix.hystrix.util.HystrixRollingNumberEvent; - -public class HystrixAsyncCommandTest { - - @Before - public void prepareForTest() { - /* we must call this to simulate a new request lifecycle running and clearing caches */ - HystrixRequestContext.initializeContext(); - } - - @After - public void cleanup() { - // instead of storing the reference from initialize we'll just get the current state and shutdown - if (HystrixRequestContext.getContextForCurrentThread() != null) { - // it could have been set NULL by the test - HystrixRequestContext.getContextForCurrentThread().shutdown(); - } - - // force properties to be clean as well - ConfigurationManager.getConfigInstance().clear(); - - /* - * RxJava will create one worker for each processor when we schedule Observables in the - * Schedulers.computation(). Any leftovers here might lead to a congestion in a following - * thread. To ensure all existing threads have completed we now schedule some observables - * that will execute in distinct threads due to the latch.. - */ - int count = Runtime.getRuntime().availableProcessors(); - final CountDownLatch latch = new CountDownLatch(count); - ArrayList> futures = new ArrayList>(); - for (int i = 0; i < count; ++i) { - futures.add(Observable.create(new OnSubscribe() { - @Override - public void call(Subscriber sub) { - latch.countDown(); - try { - latch.await(); - sub.onNext(true); - sub.onCompleted(); - } catch (InterruptedException e) { - sub.onError(e); - } - } - }).subscribeOn(Schedulers.computation()).toBlocking().toFuture()); - } - for (Future future : futures) { - try { - future.get(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - throw new RuntimeException(e); - } - } - - //TODO commented out as it has issues when built from command-line even though it works from IDE - // HystrixCommandKey key = Hystrix.getCurrentThreadExecutingCommand(); - // if (key != null) { - // throw new IllegalStateException("should be null but got: " + key); - // } - } - - /** - * Test a successful command execution. - */ - @Test - public void testExecutionSuccess() { - 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()); - - 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 that a command can not be executed multiple times. - */ - @Test - public void testExecutionMultipleTimes() { - SuccessfulTestCommand command = new SuccessfulTestCommand(); - assertFalse(command.isExecutionComplete()); - // first should succeed - assertEquals(true, command.observe().toBlocking().single()); - System.out.println(">> completed, checking metrics"); - assertTrue(command.isExecutionComplete()); - assertFalse(command.isExecutedInThread()); - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isSuccessfulExecution()); - try { - // second should fail - command.observe().toBlocking().single(); - fail("we should not allow this ... it breaks the state of request logs"); - } catch (IllegalStateException e) { - e.printStackTrace(); - // we want to get here - } - - try { - // queue should also fail - command.observe().toBlocking().toFuture(); - fail("we should not allow this ... it breaks the state of request logs"); - } catch (IllegalStateException e) { - e.printStackTrace(); - // we want to get here - } - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a command execution that throws an HystrixException and didn't implement getFallback. - */ - @Test - public void testExecutionKnownFailureWithNoFallback() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - TestHystrixCommand command = new KnownFailureTestCommandWithoutFallback(circuitBreaker); - try { - command.observe().toBlocking().single(); - fail("we shouldn't get here"); - } catch (HystrixRuntimeException e) { - e.printStackTrace(); - assertNotNull(e.getFallbackException()); - assertNotNull(e.getImplementingClass()); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - } catch (Exception e) { - e.printStackTrace(); - fail("We should always get an HystrixRuntimeException when an error occurs."); - } - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - 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(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a command execution that throws an unknown exception (not HystrixException) and didn't implement getFallback. - */ - @Test - public void testExecutionUnknownFailureWithNoFallback() { - TestHystrixCommand command = new UnknownFailureTestCommandWithoutFallback(); - try { - command.observe().toBlocking().single(); - fail("we shouldn't get here"); - } catch (HystrixRuntimeException e) { - e.printStackTrace(); - assertNotNull(e.getFallbackException()); - assertNotNull(e.getImplementingClass()); - - } catch (Exception e) { - e.printStackTrace(); - fail("We should always get an HystrixRuntimeException when an error occurs."); - } - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - 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(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, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a command execution that fails but has a fallback. - */ - @Test - public void testExecutionFailureWithFallback() { - TestHystrixCommand command = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker()); - try { - assertEquals(false, command.observe().toBlocking().single()); - } catch (Exception e) { - e.printStackTrace(); - fail("We should have received a response from the fallback."); - } - - assertEquals("we failed with a simulated issue", command.getFailedExecutionException().getMessage()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - 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.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(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 that fails, has getFallback implemented but that fails as well. - */ - @Test - public void testExecutionFailureWithFallbackFailure() { - TestHystrixCommand command = new KnownFailureTestCommandWithFallbackFailure(); - try { - command.observe().toBlocking().single(); - fail("we shouldn't get here"); - } catch (HystrixRuntimeException e) { - System.out.println("------------------------------------------------"); - e.printStackTrace(); - System.out.println("------------------------------------------------"); - assertNotNull(e.getFallbackException()); - } - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - 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, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a successful command execution (asynchronously). - */ - @Test - public void testQueueSuccess() { - TestHystrixCommand command = new SuccessfulTestCommand(); - try { - Future future = command.observe().toBlocking().toFuture(); - assertEquals(true, future.get()); - } catch (Exception e) { - e.printStackTrace(); - fail("We received an exception."); - } - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isSuccessfulExecution()); - - 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.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.TIMEOUT)); - 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()); - } - - /** - * Test a command execution (asynchronously) that throws an HystrixException and didn't implement getFallback. - */ - @Test - public void testQueueKnownFailureWithNoFallback() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - TestHystrixCommand command = new KnownFailureTestCommandWithoutFallback(circuitBreaker); - try { - command.observe().toBlocking().toFuture().get(); - fail("we shouldn't get here"); - } 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"); - } - } - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - 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(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a command execution (asynchronously) that throws an unknown exception (not HystrixException) and didn't implement getFallback. - */ - @Test - public void testQueueUnknownFailureWithNoFallback() { - TestHystrixCommand command = new UnknownFailureTestCommandWithoutFallback(); - try { - command.observe().toBlocking().toFuture().get(); - fail("we shouldn't get here"); - } 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"); - } - } - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - 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(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, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a command execution (asynchronously) that fails but has a fallback. - */ - @Test - public void testQueueFailureWithFallback() { - TestHystrixCommand command = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker()); - try { - Future future = command.observe().toBlocking().toFuture(); - assertEquals(false, future.get()); - } catch (Exception e) { - e.printStackTrace(); - fail("We should have received a response from the fallback."); - } - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - 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.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(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 (asynchronously) that fails, has getFallback implemented but that fails as well. - */ - @Test - public void testQueueFailureWithFallbackFailure() { - TestHystrixCommand command = new KnownFailureTestCommandWithFallbackFailure(); - try { - command.observe().toBlocking().toFuture().get(); - fail("we shouldn't get here"); - } 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"); - } - } - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - 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, 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()); - - 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 testObserveOnScheduler() throws Exception { - * - * System.out.println("test observeOn begins"); - * final AtomicReference commandThread = new AtomicReference(); - * final AtomicReference subscribeThread = new AtomicReference(); - * - * TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder()) { - * @Override - * protected Observable run() { - * commandThread.set(Thread.currentThread()); - * return Observable.just(true); - * } - * }; - * - * final CountDownLatch latch = new CountDownLatch(1); - * - * Scheduler customScheduler = new Scheduler() { - * - * private final Scheduler self = this; - * @Override - * public Subscription schedule(T state, Func2 action) { - * return schedule(state, action, 0, TimeUnit.MILLISECONDS); - * } - * @Override - * public Subscription schedule(final T state, final Func2 action, long delayTime, TimeUnit unit) { - * new Thread("RxScheduledThread") { - * @Override - * public void run() { - * System.out.println("in schedule"); - * action.call(self, state); - * } - * }.start(); - * - * // not testing unsubscribe behavior - * return Subscriptions.empty(); - * } - * - * }; - * - * command.toObservable(customScheduler).subscribe(new Observer() { - * @Override - * public void onCompleted() { - * latch.countDown(); - * - * } - * @Override - * public void onError(Throwable e) { - * latch.countDown(); - * e.printStackTrace(); - * - * } - * @Override - * public void onNext(Boolean args) { - * subscribeThread.set(Thread.currentThread()); - * } - * }); - * - * if (!latch.await(2000, TimeUnit.MILLISECONDS)) { - * fail("timed out"); - * } - * - * assertNotNull(commandThread.get()); - * assertNotNull(subscribeThread.get()); - * - * System.out.println("subscribeThread: " + subscribeThread.get().getName()); - * assertTrue(commandThread.get().getName().startsWith("main")); - * //assertTrue(subscribeThread.get().getName().equals("RxScheduledThread")); - * assertTrue(subscribeThread.get().getName().equals("main")); - * } - */ - /** - * Test a successful command execution. - * - * @Test - * public void testObserveOnComputationSchedulerByDefaultForThreadIsolation() throws Exception { - * - * final AtomicReference commandThread = new AtomicReference(); - * final AtomicReference subscribeThread = new AtomicReference(); - * - * TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder()) { - * @Override - * protected Observable run() { - * commandThread.set(Thread.currentThread()); - * return Observable.just(true); - * } - * }; - * - * final CountDownLatch latch = new CountDownLatch(1); - * - * command.toObservable().subscribe(new Observer() { - * @Override - * public void onCompleted() { - * latch.countDown(); - * - * } - * @Override - * public void onError(Throwable e) { - * latch.countDown(); - * e.printStackTrace(); - * - * } - * @Override - * public void onNext(Boolean args) { - * subscribeThread.set(Thread.currentThread()); - * } - * }); - * - * if (!latch.await(2000, TimeUnit.MILLISECONDS)) { - * fail("timed out"); - * } - * - * assertNotNull(commandThread.get()); - * assertNotNull(subscribeThread.get()); - * - * System.out.println("Command Thread: " + commandThread.get()); - * System.out.println("Subscribe Thread: " + subscribeThread.get()); - * - * //assertTrue(commandThread.get().getName().startsWith("hystrix-")); - * //assertTrue(subscribeThread.get().getName().startsWith("RxComputationThreadPool")); - * - * assertTrue(commandThread.get().getName().startsWith("main")); - * assertTrue(subscribeThread.get().getName().startsWith("main")); - * } - */ - - /** - * Test a successful command execution. - */ - @Test - public void testObserveOnImmediateSchedulerByDefaultForSemaphoreIsolation() throws Exception { - - final AtomicReference commandThread = new AtomicReference(); - final AtomicReference subscribeThread = new AtomicReference(); - - TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder() - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE))) { - - @Override - protected HystrixFuture run() { - commandThread.set(Thread.currentThread()); - return HystrixFutureUtil.just(true); - } - }; - - final CountDownLatch latch = new CountDownLatch(1); - - command.toObservable().subscribe(new Observer() { - - @Override - public void onCompleted() { - latch.countDown(); - - } - - @Override - public void onError(Throwable e) { - latch.countDown(); - e.printStackTrace(); - - } - - @Override - public void onNext(Boolean args) { - subscribeThread.set(Thread.currentThread()); - } - }); - - if (!latch.await(2000, TimeUnit.MILLISECONDS)) { - fail("timed out"); - } - - assertNotNull(commandThread.get()); - assertNotNull(subscribeThread.get()); - - System.out.println("Command Thread: " + commandThread.get()); - System.out.println("Subscribe Thread: " + subscribeThread.get()); - - String mainThreadName = Thread.currentThread().getName(); - - // semaphore should be on the calling thread - assertTrue(commandThread.get().getName().equals(mainThreadName)); - System.out.println("testObserveOnImmediateSchedulerByDefaultForSemaphoreIsolation: " + subscribeThread.get() + " => " + mainThreadName); - assertTrue(subscribeThread.get().getName().equals(mainThreadName)); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test that the circuit-breaker will 'trip' and prevent command execution on subsequent calls. - */ - @Test - public void testCircuitBreakerTripsAfterFailures() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - /* fail 3 times and then it should trip the circuit and stop executing */ - // failure 1 - KnownFailureTestCommandWithFallback attempt1 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt1.observe().toBlocking().single(); - assertTrue(attempt1.isResponseFromFallback()); - assertFalse(attempt1.isCircuitBreakerOpen()); - assertFalse(attempt1.isResponseShortCircuited()); - - // failure 2 - KnownFailureTestCommandWithFallback attempt2 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt2.observe().toBlocking().single(); - assertTrue(attempt2.isResponseFromFallback()); - assertFalse(attempt2.isCircuitBreakerOpen()); - assertFalse(attempt2.isResponseShortCircuited()); - - // failure 3 - KnownFailureTestCommandWithFallback attempt3 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt3.observe().toBlocking().single(); - assertTrue(attempt3.isResponseFromFallback()); - assertFalse(attempt3.isResponseShortCircuited()); - // it should now be 'open' and prevent further executions - assertTrue(attempt3.isCircuitBreakerOpen()); - - // attempt 4 - KnownFailureTestCommandWithFallback attempt4 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt4.observe().toBlocking().single(); - assertTrue(attempt4.isResponseFromFallback()); - // this should now be true as the response will be short-circuited - assertTrue(attempt4.isResponseShortCircuited()); - // this should remain open - assertTrue(attempt4.isCircuitBreakerOpen()); - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(3, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(4, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(1, 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(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - /** - * Test that the circuit-breaker will 'trip' and prevent command execution on subsequent calls. - */ - @Test - public void testCircuitBreakerTripsAfterFailuresViaQueue() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - try { - /* fail 3 times and then it should trip the circuit and stop executing */ - // failure 1 - KnownFailureTestCommandWithFallback attempt1 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt1.observe().toBlocking().toFuture().get(); - assertTrue(attempt1.isResponseFromFallback()); - assertFalse(attempt1.isCircuitBreakerOpen()); - assertFalse(attempt1.isResponseShortCircuited()); - - // failure 2 - KnownFailureTestCommandWithFallback attempt2 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt2.observe().toBlocking().toFuture().get(); - assertTrue(attempt2.isResponseFromFallback()); - assertFalse(attempt2.isCircuitBreakerOpen()); - assertFalse(attempt2.isResponseShortCircuited()); - - // failure 3 - KnownFailureTestCommandWithFallback attempt3 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt3.observe().toBlocking().toFuture().get(); - assertTrue(attempt3.isResponseFromFallback()); - assertFalse(attempt3.isResponseShortCircuited()); - // it should now be 'open' and prevent further executions - assertTrue(attempt3.isCircuitBreakerOpen()); - - // attempt 4 - KnownFailureTestCommandWithFallback attempt4 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt4.observe().toBlocking().toFuture().get(); - assertTrue(attempt4.isResponseFromFallback()); - // this should now be true as the response will be short-circuited - assertTrue(attempt4.isResponseShortCircuited()); - // this should remain open - assertTrue(attempt4.isCircuitBreakerOpen()); - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(3, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(4, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(1, 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(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } catch (Exception e) { - e.printStackTrace(); - fail("We should have received fallbacks."); - } - } - - /** - * Test that the circuit-breaker is shared across HystrixCommand objects with the same CommandKey. - *

- * This will test HystrixCommand objects with a single circuit-breaker (as if each injected with same CommandKey) - *

- * Multiple HystrixCommand objects with the same dependency use the same circuit-breaker. - */ - @Test - public void testCircuitBreakerAcrossMultipleCommandsButSameCircuitBreaker() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - /* fail 3 times and then it should trip the circuit and stop executing */ - // failure 1 - KnownFailureTestCommandWithFallback attempt1 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt1.observe().toBlocking().single(); - assertTrue(attempt1.isResponseFromFallback()); - assertFalse(attempt1.isCircuitBreakerOpen()); - assertFalse(attempt1.isResponseShortCircuited()); - - // failure 2 with a different command, same circuit breaker - KnownFailureTestCommandWithoutFallback attempt2 = new KnownFailureTestCommandWithoutFallback(circuitBreaker); - try { - attempt2.observe().toBlocking().single(); - } catch (Exception e) { - // ignore ... this doesn't have a fallback so will throw an exception - } - assertTrue(attempt2.isFailedExecution()); - assertFalse(attempt2.isResponseFromFallback()); // false because no fallback - assertFalse(attempt2.isCircuitBreakerOpen()); - assertFalse(attempt2.isResponseShortCircuited()); - - // failure 3 of the Hystrix, 2nd for this particular HystrixCommand - KnownFailureTestCommandWithFallback attempt3 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt3.observe().toBlocking().single(); - assertTrue(attempt2.isFailedExecution()); - assertTrue(attempt3.isResponseFromFallback()); - assertFalse(attempt3.isResponseShortCircuited()); - - // it should now be 'open' and prevent further executions - // after having 3 failures on the Hystrix that these 2 different HystrixCommand objects are for - assertTrue(attempt3.isCircuitBreakerOpen()); - - // attempt 4 - KnownFailureTestCommandWithFallback attempt4 = new KnownFailureTestCommandWithFallback(circuitBreaker); - attempt4.observe().toBlocking().single(); - assertTrue(attempt4.isResponseFromFallback()); - // this should now be true as the response will be short-circuited - assertTrue(attempt4.isResponseShortCircuited()); - // this should remain open - assertTrue(attempt4.isCircuitBreakerOpen()); - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(3, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(3, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(1, 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(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - /** - * Test that the circuit-breaker is different between HystrixCommand objects with a different Hystrix. - */ - @Test - public void testCircuitBreakerAcrossMultipleCommandsAndDifferentDependency() { - TestCircuitBreaker circuitBreaker_one = new TestCircuitBreaker(); - TestCircuitBreaker circuitBreaker_two = new TestCircuitBreaker(); - /* fail 3 times, twice on one Hystrix, once on a different Hystrix ... circuit-breaker should NOT open */ - - // failure 1 - KnownFailureTestCommandWithFallback attempt1 = new KnownFailureTestCommandWithFallback(circuitBreaker_one); - attempt1.observe().toBlocking().single(); - assertTrue(attempt1.isResponseFromFallback()); - assertFalse(attempt1.isCircuitBreakerOpen()); - assertFalse(attempt1.isResponseShortCircuited()); - - // failure 2 with a different HystrixCommand implementation and different Hystrix - KnownFailureTestCommandWithFallback attempt2 = new KnownFailureTestCommandWithFallback(circuitBreaker_two); - attempt2.observe().toBlocking().single(); - assertTrue(attempt2.isResponseFromFallback()); - assertFalse(attempt2.isCircuitBreakerOpen()); - assertFalse(attempt2.isResponseShortCircuited()); - - // failure 3 but only 2nd of the Hystrix.ONE - KnownFailureTestCommandWithFallback attempt3 = new KnownFailureTestCommandWithFallback(circuitBreaker_one); - attempt3.observe().toBlocking().single(); - assertTrue(attempt3.isResponseFromFallback()); - assertFalse(attempt3.isResponseShortCircuited()); - - // it should remain 'closed' since we have only had 2 failures on Hystrix.ONE - assertFalse(attempt3.isCircuitBreakerOpen()); - - // this one should also remain closed as it only had 1 failure for Hystrix.TWO - assertFalse(attempt2.isCircuitBreakerOpen()); - - // attempt 4 (3rd attempt for Hystrix.ONE) - KnownFailureTestCommandWithFallback attempt4 = new KnownFailureTestCommandWithFallback(circuitBreaker_one); - attempt4.observe().toBlocking().single(); - // this should NOW flip to true as this is the 3rd failure for Hystrix.ONE - assertTrue(attempt3.isCircuitBreakerOpen()); - assertTrue(attempt3.isResponseFromFallback()); - assertFalse(attempt3.isResponseShortCircuited()); - - // Hystrix.TWO should still remain closed - assertFalse(attempt2.isCircuitBreakerOpen()); - - assertEquals(0, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(3, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(3, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(0, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, circuitBreaker_one.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, circuitBreaker_one.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(0, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(1, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(1, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(0, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, circuitBreaker_two.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, circuitBreaker_two.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - /** - * Test that the circuit-breaker being disabled doesn't wreak havoc. - */ - @Test - public void testExecutionSuccessWithCircuitBreakerDisabled() { - TestHystrixCommand command = new TestCommandWithoutCircuitBreaker(); - try { - assertEquals(true, command.observe().toBlocking().single()); - } catch (Exception e) { - e.printStackTrace(); - fail("We received an exception."); - } - - // we'll still get metrics ... just not the circuit breaker opening/closing - 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.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.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(0, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - /** - * Test a command execution timeout where the command didn't implement getFallback. - */ - @Test - public void testExecutionTimeoutWithNoFallbackUsingSemaphoreIsolation() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_NOT_IMPLEMENTED, ExecutionIsolationStrategy.SEMAPHORE); - 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()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * 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 - public void testQueuedExecutionTimeoutWithFallback() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS); - try { - assertEquals(false, command.observe().toBlocking().toFuture().get()); - } 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 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 - public void testQueuedExecutionTimeoutFallbackFailure() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_FAILURE); - try { - command.observe().toBlocking().toFuture().get(); - fail("we shouldn't get here"); - } catch (Exception e) { - if (e instanceof ExecutionException && e.getCause() instanceof HystrixRuntimeException) { - HystrixRuntimeException de = (HystrixRuntimeException) e.getCause(); - 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"); - } - } - - 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 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 testObservedExecutionTimeoutWithNoFallback() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_NOT_IMPLEMENTED); - 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 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 - public void testObservedExecutionTimeoutWithFallback() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS); - try { - assertEquals(false, command.observe().toBlocking().single()); - } 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 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 - public void testObservedExecutionTimeoutFallbackFailure() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_FAILURE); - 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 ExecutionException with cause as HystrixRuntimeException"); - } - } - - 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 that the circuit-breaker counts a command execution timeout as a 'timeout' and not just failure. - */ - @Test - public void testShortCircuitFallbackCounter() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker().setForceShortCircuit(true); - try { - new KnownFailureTestCommandWithFallback(circuitBreaker).observe().toBlocking().single(); - - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - - KnownFailureTestCommandWithFallback command = new KnownFailureTestCommandWithFallback(circuitBreaker); - command.observe().toBlocking().single(); - assertEquals(2, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - - // will be -1 because it never attempted execution - assertEquals(-1, command.getExecutionTimeInMilliseconds()); - assertTrue(command.isResponseShortCircuited()); - assertFalse(command.isResponseTimedOut()); - - // because it was short-circuited to a fallback we don't count an error - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } catch (Exception e) { - e.printStackTrace(); - fail("We should have received a response from the fallback."); - } - - assertEquals(0, 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_REJECTION)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(2, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(2, 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(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - @Test - public void testExecutionSemaphoreWithQueue() { - final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - // single thread should work - try { - boolean result = new TestSemaphoreCommand(circuitBreaker, 1, 200).observe().toBlocking().toFuture().get(); - assertTrue(result); - } catch (Exception e) { - // we shouldn't fail on this one - throw new RuntimeException(e); - } - - final AtomicBoolean exceptionReceived = new AtomicBoolean(); - - final TryableSemaphoreActual semaphore = - new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(1)); - - Runnable r = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() { - - @Override - public void run() { - try { - new TestSemaphoreCommand(circuitBreaker, semaphore, 200).observe().toBlocking().toFuture().get(); - } catch (Exception e) { - e.printStackTrace(); - exceptionReceived.set(true); - } - } - - }); - // 2 threads, the second should be rejected by the semaphore - 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 expected an exception on the 2nd get"); - } - - assertEquals(2, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - // we don't have a fallback so threw an exception when rejected - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - // not a failure as the command never executed so can't fail - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - // no fallback failure as there isn't a fallback implemented - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - // we should have rejected via semaphore - 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)); - - assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - @Test - public void testExecutionSemaphoreWithExecution() { - final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - // single thread should work - try { - TestSemaphoreCommand command = new TestSemaphoreCommand(circuitBreaker, 1, 200); - boolean result = command.observe().toBlocking().single(); - assertFalse(command.isExecutedInThread()); - assertTrue(result); - } catch (Exception e) { - // we shouldn't fail on this one - throw new RuntimeException(e); - } - - final ArrayBlockingQueue results = new ArrayBlockingQueue(2); - - final AtomicBoolean exceptionReceived = new AtomicBoolean(); - - final TryableSemaphoreActual semaphore = - new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(1)); - - Runnable r = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() { - - @Override - public void run() { - try { - results.add(new TestSemaphoreCommand(circuitBreaker, semaphore, 200).observe().toBlocking().single()); - } catch (Exception e) { - e.printStackTrace(); - exceptionReceived.set(true); - } - } - - }); - // 2 threads, the second should be rejected by the semaphore - 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 expected an exception on the 2nd get"); - } - - // only 1 value is expected as the other should have thrown an exception - assertEquals(1, results.size()); - // should contain only a true result - assertTrue(results.contains(Boolean.TRUE)); - assertFalse(results.contains(Boolean.FALSE)); - - assertEquals(2, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - // no failure ... we throw an exception because of rejection but the command does not fail execution - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - // there is no fallback implemented so no failure can occur on it - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - // we rejected via semaphore - 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)); - - assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - @Test - public void testRejectedExecutionSemaphoreWithFallback() { - 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().toBlocking().single()); - } 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"); - } - - // both threads should have returned values - assertEquals(2, results.size()); - // should contain both a true and false result - assertTrue(results.contains(Boolean.TRUE)); - assertTrue(results.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 - */ - @Test - public void testSemaphorePermitsInUse() { - final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - - // this semaphore will be shared across multiple command instances - final TryableSemaphoreActual sharedSemaphore = - new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(3)); - - // used to wait until all commands have started - final CountDownLatch startLatch = new CountDownLatch(sharedSemaphore.numberOfPermits.get() + 1); - - // used to signal that all command can finish - final CountDownLatch sharedLatch = new CountDownLatch(1); - - final Runnable sharedSemaphoreRunnable = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() { - public void run() { - try { - new LatchedSemaphoreCommand(circuitBreaker, sharedSemaphore, startLatch, sharedLatch).observe().toBlocking().single(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - - // creates group of threads each using command sharing a single semaphore - - // I create extra threads and commands so that I can verify that some of them fail to obtain a semaphore - final int sharedThreadCount = sharedSemaphore.numberOfPermits.get() * 2; - final Thread[] sharedSemaphoreThreads = new Thread[sharedThreadCount]; - for (int i = 0; i < sharedThreadCount; i++) { - sharedSemaphoreThreads[i] = new Thread(sharedSemaphoreRunnable); - } - - // creates thread using isolated semaphore - final TryableSemaphoreActual isolatedSemaphore = - new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(1)); - - final CountDownLatch isolatedLatch = new CountDownLatch(1); - - // tracks failures to obtain semaphores - final AtomicInteger failureCount = new AtomicInteger(); - - final Thread isolatedThread = new Thread(new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() { - public void run() { - try { - new LatchedSemaphoreCommand(circuitBreaker, isolatedSemaphore, startLatch, isolatedLatch).observe().toBlocking().single(); - } catch (Exception e) { - e.printStackTrace(); - failureCount.incrementAndGet(); - } - } - })); - - // verifies no permits in use before starting threads - assertEquals("wrong number of permits for shared semaphore", 0, sharedSemaphore.getNumberOfPermitsUsed()); - assertEquals("wrong number of permits for isolated semaphore", 0, isolatedSemaphore.getNumberOfPermitsUsed()); - - for (int i = 0; i < sharedThreadCount; i++) { - sharedSemaphoreThreads[i].start(); - } - isolatedThread.start(); - - // waits until all commands have started - try { - startLatch.await(1000, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - // verifies that all semaphores are in use - assertEquals("wrong number of permits for shared semaphore", - sharedSemaphore.numberOfPermits.get().longValue(), sharedSemaphore.getNumberOfPermitsUsed()); - assertEquals("wrong number of permits for isolated semaphore", - isolatedSemaphore.numberOfPermits.get().longValue(), isolatedSemaphore.getNumberOfPermitsUsed()); - - // signals commands to finish - sharedLatch.countDown(); - isolatedLatch.countDown(); - - try { - for (int i = 0; i < sharedThreadCount; i++) { - sharedSemaphoreThreads[i].join(); - } - isolatedThread.join(); - } catch (Exception e) { - e.printStackTrace(); - fail("failed waiting on threads"); - } - - // verifies no permits in use after finishing threads - assertEquals("wrong number of permits for shared semaphore", 0, sharedSemaphore.getNumberOfPermitsUsed()); - assertEquals("wrong number of permits for isolated semaphore", 0, isolatedSemaphore.getNumberOfPermitsUsed()); - - // verifies that some executions failed - final int expectedFailures = sharedSemaphore.getNumberOfPermitsUsed(); - assertEquals("failures expected but did not happen", expectedFailures, failureCount.get()); - } - - /** - * Test that HystrixOwner can be passed in dynamically. - */ - @Test - public void testDynamicOwner() { - try { - TestHystrixCommand command = new DynamicOwnerTestCommand(CommandGroupForUnitTest.OWNER_ONE); - 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)); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } catch (Exception e) { - e.printStackTrace(); - fail("We received an exception."); - } - } - - /** - * Test a successful command execution. - */ - @Test - public void testDynamicOwnerFails() { - try { - TestHystrixCommand command = new DynamicOwnerTestCommand(null); - 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()); - fail("we should have thrown an exception as we need an owner"); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } catch (Exception e) { - // success if we get here - } - } - - /** - * Test that HystrixCommandKey can be passed in dynamically. - */ - @Test - public void testDynamicKey() { - try { - DynamicOwnerAndKeyTestCommand command1 = new DynamicOwnerAndKeyTestCommand(CommandGroupForUnitTest.OWNER_ONE, CommandKeyForUnitTest.KEY_ONE); - assertEquals(true, command1.observe().toBlocking().single()); - DynamicOwnerAndKeyTestCommand command2 = new DynamicOwnerAndKeyTestCommand(CommandGroupForUnitTest.OWNER_ONE, CommandKeyForUnitTest.KEY_TWO); - assertEquals(true, command2.observe().toBlocking().single()); - - // 2 different circuit breakers should be created - assertNotSame(command1.getCircuitBreaker(), command2.getCircuitBreaker()); - - // semaphore isolated - assertFalse(command1.isExecutedInThread()); - } catch (Exception e) { - e.printStackTrace(); - fail("We received an exception."); - } - } - - /** - * Test Request scoped caching of commands so that a 2nd duplicate call doesn't execute but returns the previous Future - */ - @Test - public void testRequestCache1UsingThreadIsolation() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - SuccessfulCacheableCommand command1 = new SuccessfulCacheableCommand(circuitBreaker, true, "A"); - SuccessfulCacheableCommand command2 = new SuccessfulCacheableCommand(circuitBreaker, true, "A"); - - assertTrue(command1.isCommandRunningInThread()); - - Future f1 = command1.observe().toBlocking().toFuture(); - Future f2 = command2.observe().toBlocking().toFuture(); - - try { - assertEquals("A", f1.get()); - assertEquals("A", f2.get()); - } catch (Exception e) { - throw new RuntimeException(e); - } - - assertTrue(command1.executed); - // the second one should not have executed as it should have received the cached value instead - assertFalse(command2.executed); - - // the execution log for command1 should show a SUCCESS - assertEquals(1, command1.getExecutionEvents().size()); - assertTrue(command1.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - assertTrue(command1.getExecutionTimeInMilliseconds() > -1); - assertFalse(command1.isResponseFromCache()); - - // the execution log for command2 should show it came from cache - assertEquals(2, command2.getExecutionEvents().size()); // it will include the SUCCESS + RESPONSE_FROM_CACHE - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.RESPONSE_FROM_CACHE)); - assertTrue(command2.getExecutionTimeInMilliseconds() == -1); - assertTrue(command2.isResponseFromCache()); - - 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_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(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(0, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - /** - * Test Request scoped caching doesn't prevent different ones from executing - */ - @Test - public void testRequestCache2UsingThreadIsolation() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - SuccessfulCacheableCommand command1 = new SuccessfulCacheableCommand(circuitBreaker, true, "A"); - SuccessfulCacheableCommand command2 = new SuccessfulCacheableCommand(circuitBreaker, true, "B"); - - assertTrue(command1.isCommandRunningInThread()); - - Future f1 = command1.observe().toBlocking().toFuture(); - Future f2 = command2.observe().toBlocking().toFuture(); - - try { - assertEquals("A", f1.get()); - assertEquals("B", f2.get()); - } catch (Exception e) { - throw new RuntimeException(e); - } - - assertTrue(command1.executed); - // both should execute as they are different - assertTrue(command2.executed); - - // the execution log for command1 should show a SUCCESS - assertEquals(1, command1.getExecutionEvents().size()); - assertTrue(command1.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command2 should show a SUCCESS - assertEquals(1, command2.getExecutionEvents().size()); - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - assertTrue(command2.getExecutionTimeInMilliseconds() > -1); - assertFalse(command2.isResponseFromCache()); - - assertEquals(2, 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_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, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - /** - * Test Request scoped caching with a mixture of commands - */ - @Test - public void testRequestCache3UsingThreadIsolation() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - SuccessfulCacheableCommand command1 = new SuccessfulCacheableCommand(circuitBreaker, true, "A"); - SuccessfulCacheableCommand command2 = new SuccessfulCacheableCommand(circuitBreaker, true, "B"); - SuccessfulCacheableCommand command3 = new SuccessfulCacheableCommand(circuitBreaker, true, "A"); - - assertTrue(command1.isCommandRunningInThread()); - - Future f1 = command1.observe().toBlocking().toFuture(); - Future f2 = command2.observe().toBlocking().toFuture(); - Future f3 = command3.observe().toBlocking().toFuture(); - - try { - assertEquals("A", f1.get()); - assertEquals("B", f2.get()); - assertEquals("A", f3.get()); - } catch (Exception e) { - throw new RuntimeException(e); - } - - assertTrue(command1.executed); - // both should execute as they are different - assertTrue(command2.executed); - // but the 3rd should come from cache - assertFalse(command3.executed); - - // the execution log for command1 should show a SUCCESS - assertEquals(1, command1.getExecutionEvents().size()); - assertTrue(command1.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command2 should show a SUCCESS - assertEquals(1, command2.getExecutionEvents().size()); - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command3 should show it came from cache - assertEquals(2, command3.getExecutionEvents().size()); // it will include the SUCCESS + RESPONSE_FROM_CACHE - assertTrue(command3.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - assertTrue(command3.getExecutionEvents().contains(HystrixEventType.RESPONSE_FROM_CACHE)); - assertTrue(command3.getExecutionTimeInMilliseconds() == -1); - assertTrue(command3.isResponseFromCache()); - - assertEquals(2, 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_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(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(0, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - System.out.println("executedCommand: " + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString()); - assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - /** - * Test Request scoped caching of commands so that a 2nd duplicate call doesn't execute but returns the previous Future - */ - @Test - public void testRequestCacheWithSlowExecution() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - SlowCacheableCommand command1 = new SlowCacheableCommand(circuitBreaker, "A", 200); - SlowCacheableCommand command2 = new SlowCacheableCommand(circuitBreaker, "A", 100); - SlowCacheableCommand command3 = new SlowCacheableCommand(circuitBreaker, "A", 100); - SlowCacheableCommand command4 = new SlowCacheableCommand(circuitBreaker, "A", 100); - - Future f1 = command1.observe().toBlocking().toFuture(); - Future f2 = command2.observe().toBlocking().toFuture(); - Future f3 = command3.observe().toBlocking().toFuture(); - Future f4 = command4.observe().toBlocking().toFuture(); - - try { - assertEquals("A", f2.get()); - assertEquals("A", f3.get()); - assertEquals("A", f4.get()); - - assertEquals("A", f1.get()); - } catch (Exception e) { - throw new RuntimeException(e); - } - - assertTrue(command1.executed); - // the second one should not have executed as it should have received the cached value instead - assertFalse(command2.executed); - assertFalse(command3.executed); - assertFalse(command4.executed); - - // the execution log for command1 should show a SUCCESS - assertEquals(1, command1.getExecutionEvents().size()); - assertTrue(command1.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - assertTrue(command1.getExecutionTimeInMilliseconds() > -1); - assertFalse(command1.isResponseFromCache()); - - // the execution log for command2 should show it came from cache - assertEquals(2, command2.getExecutionEvents().size()); // it will include the SUCCESS + RESPONSE_FROM_CACHE - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.RESPONSE_FROM_CACHE)); - assertTrue(command2.getExecutionTimeInMilliseconds() == -1); - assertTrue(command2.isResponseFromCache()); - - assertTrue(command3.isResponseFromCache()); - assertTrue(command3.getExecutionTimeInMilliseconds() == -1); - assertTrue(command4.isResponseFromCache()); - assertTrue(command4.getExecutionTimeInMilliseconds() == -1); - - 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_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(3, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(0, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - System.out.println("HystrixRequestLog: " + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString()); - - // semaphore isolated - assertFalse(command1.isExecutedInThread()); - assertFalse(command2.isExecutedInThread()); - assertFalse(command3.isExecutedInThread()); - assertFalse(command4.isExecutedInThread()); - } - - /** - * Test Request scoped caching with a mixture of commands - */ - @Test - public void testNoRequestCache3UsingThreadIsolation() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - SuccessfulCacheableCommand command1 = new SuccessfulCacheableCommand(circuitBreaker, false, "A"); - SuccessfulCacheableCommand command2 = new SuccessfulCacheableCommand(circuitBreaker, false, "B"); - SuccessfulCacheableCommand command3 = new SuccessfulCacheableCommand(circuitBreaker, false, "A"); - - assertTrue(command1.isCommandRunningInThread()); - - Future f1 = command1.observe().toBlocking().toFuture(); - Future f2 = command2.observe().toBlocking().toFuture(); - Future f3 = command3.observe().toBlocking().toFuture(); - - try { - assertEquals("A", f1.get()); - assertEquals("B", f2.get()); - assertEquals("A", f3.get()); - } catch (Exception e) { - throw new RuntimeException(e); - } - - assertTrue(command1.executed); - // both should execute as they are different - assertTrue(command2.executed); - // this should also execute since we disabled the cache - assertTrue(command3.executed); - - // the execution log for command1 should show a SUCCESS - assertEquals(1, command1.getExecutionEvents().size()); - assertTrue(command1.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command2 should show a SUCCESS - assertEquals(1, command2.getExecutionEvents().size()); - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command3 should show a SUCCESS - assertEquals(1, command3.getExecutionEvents().size()); - assertTrue(command3.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - assertEquals(3, 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_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, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // thread isolated - assertTrue(command1.isExecutedInThread()); - assertTrue(command2.isExecutedInThread()); - assertTrue(command3.isExecutedInThread()); - } - - /** - * Test Request scoped caching with a mixture of commands - */ - @Test - public void testRequestCacheViaQueueUsingSemaphoreIsolation() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - SuccessfulCacheableCommandViaSemaphore command1 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, "A"); - SuccessfulCacheableCommandViaSemaphore command2 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, "B"); - SuccessfulCacheableCommandViaSemaphore command3 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, "A"); - - assertFalse(command1.isCommandRunningInThread()); - - Future f1 = command1.observe().toBlocking().toFuture(); - Future f2 = command2.observe().toBlocking().toFuture(); - Future f3 = command3.observe().toBlocking().toFuture(); - - try { - assertEquals("A", f1.get()); - assertEquals("B", f2.get()); - assertEquals("A", f3.get()); - } catch (Exception e) { - throw new RuntimeException(e); - } - - assertTrue(command1.executed); - // both should execute as they are different - assertTrue(command2.executed); - // but the 3rd should come from cache - assertFalse(command3.executed); - - // the execution log for command1 should show a SUCCESS - assertEquals(1, command1.getExecutionEvents().size()); - assertTrue(command1.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command2 should show a SUCCESS - assertEquals(1, command2.getExecutionEvents().size()); - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command3 should show it comes from cache - assertEquals(2, command3.getExecutionEvents().size()); // it will include the SUCCESS + RESPONSE_FROM_CACHE - assertTrue(command3.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - assertTrue(command3.getExecutionEvents().contains(HystrixEventType.RESPONSE_FROM_CACHE)); - - assertTrue(command3.isResponseFromCache()); - assertTrue(command3.getExecutionTimeInMilliseconds() == -1); - - assertEquals(2, 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_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(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(0, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command1.isExecutedInThread()); - assertFalse(command2.isExecutedInThread()); - assertFalse(command3.isExecutedInThread()); - } - - /** - * Test Request scoped caching with a mixture of commands - */ - @Test - public void testNoRequestCacheViaQueueUsingSemaphoreIsolation() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - SuccessfulCacheableCommandViaSemaphore command1 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, "A"); - SuccessfulCacheableCommandViaSemaphore command2 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, "B"); - SuccessfulCacheableCommandViaSemaphore command3 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, "A"); - - assertFalse(command1.isCommandRunningInThread()); - - Future f1 = command1.observe().toBlocking().toFuture(); - Future f2 = command2.observe().toBlocking().toFuture(); - Future f3 = command3.observe().toBlocking().toFuture(); - - try { - assertEquals("A", f1.get()); - assertEquals("B", f2.get()); - assertEquals("A", f3.get()); - } catch (Exception e) { - throw new RuntimeException(e); - } - - assertTrue(command1.executed); - // both should execute as they are different - assertTrue(command2.executed); - // this should also execute because caching is disabled - assertTrue(command3.executed); - - // the execution log for command1 should show a SUCCESS - assertEquals(1, command1.getExecutionEvents().size()); - assertTrue(command1.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command2 should show a SUCCESS - assertEquals(1, command2.getExecutionEvents().size()); - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command3 should show a SUCCESS - assertEquals(1, command3.getExecutionEvents().size()); - assertTrue(command3.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - assertEquals(3, 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_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, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command1.isExecutedInThread()); - assertFalse(command2.isExecutedInThread()); - assertFalse(command3.isExecutedInThread()); - } - - /** - * Test Request scoped caching with a mixture of commands - */ - @Test - public void testRequestCacheViaExecuteUsingSemaphoreIsolation() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - SuccessfulCacheableCommandViaSemaphore command1 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, "A"); - SuccessfulCacheableCommandViaSemaphore command2 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, "B"); - SuccessfulCacheableCommandViaSemaphore command3 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, true, "A"); - - assertFalse(command1.isCommandRunningInThread()); - - String f1 = command1.observe().toBlocking().single(); - String f2 = command2.observe().toBlocking().single(); - String f3 = command3.observe().toBlocking().single(); - - assertEquals("A", f1); - assertEquals("B", f2); - assertEquals("A", f3); - - assertTrue(command1.executed); - // both should execute as they are different - assertTrue(command2.executed); - // but the 3rd should come from cache - assertFalse(command3.executed); - - // the execution log for command1 should show a SUCCESS - assertEquals(1, command1.getExecutionEvents().size()); - assertTrue(command1.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command2 should show a SUCCESS - assertEquals(1, command2.getExecutionEvents().size()); - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command3 should show it comes from cache - assertEquals(2, command3.getExecutionEvents().size()); // it will include the SUCCESS + RESPONSE_FROM_CACHE - assertTrue(command3.getExecutionEvents().contains(HystrixEventType.RESPONSE_FROM_CACHE)); - - assertEquals(2, 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_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(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(0, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command1.isExecutedInThread()); - assertFalse(command2.isExecutedInThread()); - assertFalse(command3.isExecutedInThread()); - } - - /** - * Test Request scoped caching with a mixture of commands - */ - @Test - public void testNoRequestCacheViaExecuteUsingSemaphoreIsolation() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - SuccessfulCacheableCommandViaSemaphore command1 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, "A"); - SuccessfulCacheableCommandViaSemaphore command2 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, "B"); - SuccessfulCacheableCommandViaSemaphore command3 = new SuccessfulCacheableCommandViaSemaphore(circuitBreaker, false, "A"); - - assertFalse(command1.isCommandRunningInThread()); - - String f1 = command1.observe().toBlocking().single(); - String f2 = command2.observe().toBlocking().single(); - String f3 = command3.observe().toBlocking().single(); - - assertEquals("A", f1); - assertEquals("B", f2); - assertEquals("A", f3); - - assertTrue(command1.executed); - // both should execute as they are different - assertTrue(command2.executed); - // this should also execute because caching is disabled - assertTrue(command3.executed); - - // the execution log for command1 should show a SUCCESS - assertEquals(1, command1.getExecutionEvents().size()); - assertTrue(command1.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command2 should show a SUCCESS - assertEquals(1, command2.getExecutionEvents().size()); - assertTrue(command2.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - // the execution log for command3 should show a SUCCESS - assertEquals(1, command3.getExecutionEvents().size()); - assertTrue(command3.getExecutionEvents().contains(HystrixEventType.SUCCESS)); - - assertEquals(3, 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_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, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - // semaphore isolated - assertFalse(command1.isExecutedInThread()); - assertFalse(command2.isExecutedInThread()); - assertFalse(command3.isExecutedInThread()); - } - - @Test - public void testNoRequestCacheOnTimeoutThrowsException() throws Exception { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - NoRequestCacheTimeoutWithoutFallback r1 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker); - try { - System.out.println("r1 value: " + r1.observe().toBlocking().single()); - // we should have thrown an exception - fail("expected a timeout"); - } catch (HystrixRuntimeException e) { - assertTrue(r1.isResponseTimedOut()); - // what we want - } - - NoRequestCacheTimeoutWithoutFallback r2 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker); - try { - r2.observe().toBlocking().single(); - // we should have thrown an exception - fail("expected a timeout"); - } catch (HystrixRuntimeException e) { - assertTrue(r2.isResponseTimedOut()); - // what we want - } - - NoRequestCacheTimeoutWithoutFallback r3 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker); - Future f3 = r3.observe().toBlocking().toFuture(); - try { - f3.get(); - // we should have thrown an exception - fail("expected a timeout"); - } catch (ExecutionException e) { - e.printStackTrace(); - assertTrue(r3.isResponseTimedOut()); - // what we want - } - - Thread.sleep(500); // timeout on command is set to 200ms - - NoRequestCacheTimeoutWithoutFallback r4 = new NoRequestCacheTimeoutWithoutFallback(circuitBreaker); - try { - r4.observe().toBlocking().single(); - // we should have thrown an exception - fail("expected a timeout"); - } catch (HystrixRuntimeException e) { - assertTrue(r4.isResponseTimedOut()); - assertFalse(r4.isResponseFromFallback()); - // what we want - } - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(4, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, 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(4, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - @Test - public void testRequestCacheOnTimeoutCausesNullPointerException() throws Exception { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - // Expect it to time out - all results should be false - assertFalse(new RequestCacheNullPointerExceptionCase(circuitBreaker).observe().toBlocking().single()); - assertFalse(new RequestCacheNullPointerExceptionCase(circuitBreaker).observe().toBlocking().single()); // return from cache #1 - assertFalse(new RequestCacheNullPointerExceptionCase(circuitBreaker).observe().toBlocking().single()); // return from cache #2 - Thread.sleep(500); // timeout on command is set to 200ms - Boolean value = new RequestCacheNullPointerExceptionCase(circuitBreaker).observe().toBlocking().single(); // return from cache #3 - assertFalse(value); - RequestCacheNullPointerExceptionCase c = new RequestCacheNullPointerExceptionCase(circuitBreaker); - Future f = c.observe().toBlocking().toFuture(); // return from cache #4 - // the bug is that we're getting a null Future back, rather than a Future that returns false - assertNotNull(f); - assertFalse(f.get()); - - assertTrue(c.isResponseFromFallback()); - assertTrue(c.isResponseTimedOut()); - assertFalse(c.isFailedExecution()); - assertFalse(c.isResponseShortCircuited()); - - assertEquals(0, 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_REJECTION)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(1, 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(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(4, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(5, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - HystrixExecutableInfo[] executeCommands = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixAsyncCommand[] {}); - - System.out.println(":executeCommands[0].getExecutionEvents()" + executeCommands[0].getExecutionEvents()); - assertEquals(2, executeCommands[0].getExecutionEvents().size()); - assertTrue(executeCommands[0].getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS)); - assertTrue(executeCommands[0].getExecutionEvents().contains(HystrixEventType.TIMEOUT)); - assertTrue(executeCommands[0].getExecutionTimeInMilliseconds() > -1); - assertTrue(executeCommands[0].isResponseTimedOut()); - assertTrue(executeCommands[0].isResponseFromFallback()); - assertFalse(executeCommands[0].isResponseFromCache()); - - assertEquals(3, executeCommands[1].getExecutionEvents().size()); // it will include FALLBACK_SUCCESS/TIMEOUT + RESPONSE_FROM_CACHE - assertTrue(executeCommands[1].getExecutionEvents().contains(HystrixEventType.RESPONSE_FROM_CACHE)); - assertTrue(executeCommands[1].getExecutionTimeInMilliseconds() == -1); - assertTrue(executeCommands[1].isResponseFromCache()); - assertTrue(executeCommands[1].isResponseTimedOut()); - assertTrue(executeCommands[1].isResponseFromFallback()); - } - - // - @Test - public void testRequestCacheOnTimeoutThrowsException() throws Exception { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - RequestCacheTimeoutWithoutFallback r1 = new RequestCacheTimeoutWithoutFallback(circuitBreaker); - try { - System.out.println("r1 value: " + r1.observe().toBlocking().single()); - // we should have thrown an exception - fail("expected a timeout"); - } catch (HystrixRuntimeException e) { - assertTrue(r1.isResponseTimedOut()); - // what we want - } - - RequestCacheTimeoutWithoutFallback r2 = new RequestCacheTimeoutWithoutFallback(circuitBreaker); - try { - r2.observe().toBlocking().single(); - // we should have thrown an exception - fail("expected a timeout"); - } catch (HystrixRuntimeException e) { - assertTrue(r2.isResponseTimedOut()); - // what we want - } - - RequestCacheTimeoutWithoutFallback r3 = new RequestCacheTimeoutWithoutFallback(circuitBreaker); - Future f3 = r3.observe().toBlocking().toFuture(); - try { - f3.get(); - // we should have thrown an exception - fail("expected a timeout"); - } catch (ExecutionException e) { - e.printStackTrace(); - assertTrue(r3.isResponseTimedOut()); - // what we want - } - - Thread.sleep(500); // timeout on command is set to 200ms - - RequestCacheTimeoutWithoutFallback r4 = new RequestCacheTimeoutWithoutFallback(circuitBreaker); - try { - r4.observe().toBlocking().single(); - // we should have thrown an exception - fail("expected a timeout"); - } catch (HystrixRuntimeException e) { - assertTrue(r4.isResponseTimedOut()); - assertFalse(r4.isResponseFromFallback()); - // what we want - } - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, 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(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(3, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(4, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - @Test - public void testRequestCacheOnThreadRejectionThrowsException() throws Exception { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - CountDownLatch completionLatch = new CountDownLatch(1); - RequestCacheThreadRejectionWithoutFallback r1 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch); - try { - System.out.println("r1: " + r1.observe().toBlocking().single()); - // we should have thrown an exception - fail("expected a rejection"); - } catch (HystrixRuntimeException e) { - e.printStackTrace(); - assertTrue(r1.isResponseRejected()); - // what we want - } - - RequestCacheThreadRejectionWithoutFallback r2 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch); - try { - System.out.println("r2: " + r2.observe().toBlocking().single()); - // we should have thrown an exception - fail("expected a rejection"); - } catch (HystrixRuntimeException e) { - // e.printStackTrace(); - assertTrue(r2.isResponseRejected()); - // what we want - } - - RequestCacheThreadRejectionWithoutFallback r3 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch); - try { - System.out.println("f3: " + r3.observe().toBlocking().toFuture().get()); - // we should have thrown an exception - fail("expected a rejection"); - } catch (ExecutionException e) { - assertTrue(r3.isResponseRejected()); - assertTrue(e.getCause() instanceof HystrixRuntimeException); - } - - // let the command finish (only 1 should actually be blocked on this due to the response cache) - completionLatch.countDown(); - - // then another after the command has completed - RequestCacheThreadRejectionWithoutFallback r4 = new RequestCacheThreadRejectionWithoutFallback(circuitBreaker, completionLatch); - try { - System.out.println("r4: " + r4.observe().toBlocking().single()); - // we should have thrown an exception - fail("expected a rejection"); - } catch (HystrixRuntimeException e) { - // e.printStackTrace(); - assertTrue(r4.isResponseRejected()); - assertFalse(r4.isResponseFromFallback()); - // what we want - } - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, 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(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(3, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, circuitBreaker.metrics.getHealthCounts().getErrorPercentage()); - - // assertEquals(4, HystrixRequestLog.getCurrentRequest().getExecutedCommands().size()); - } - - /** - * Test that we can do basic execution without a RequestVariable being initialized. - */ - @Test - public void testBasicExecutionWorksWithoutRequestVariable() { - try { - /* force the RequestVariable to not be initialized */ - HystrixRequestContext.setContextOnCurrentThread(null); - - TestHystrixCommand command = new SuccessfulTestCommand(); - assertEquals(true, command.observe().toBlocking().single()); - - TestHystrixCommand command2 = new SuccessfulTestCommand(); - assertEquals(true, command2.observe().toBlocking().toFuture().get()); - - // we should be able to execute without a RequestVariable if ... - // 1) We don't have a cacheKey - // 2) We don't ask for the RequestLog - // 3) We don't do collapsing - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } catch (Exception e) { - e.printStackTrace(); - fail("We received an exception => " + e.getMessage()); - } - } - - /** - * Test that if we try and execute a command with a cacheKey without initializing RequestVariable that it gives an error. - */ - @Test - public void testCacheKeyExecutionRequiresRequestVariable() { - try { - /* force the RequestVariable to not be initialized */ - HystrixRequestContext.setContextOnCurrentThread(null); - - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - - SuccessfulCacheableCommand command = new SuccessfulCacheableCommand(circuitBreaker, true, "one"); - assertEquals(true, command.observe().toBlocking().single()); - - SuccessfulCacheableCommand command2 = new SuccessfulCacheableCommand(circuitBreaker, true, "two"); - assertEquals(true, command2.observe().toBlocking().toFuture().get()); - - fail("We expect an exception because cacheKey requires RequestVariable."); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * Test that a BadRequestException can be thrown and not count towards errors and bypasses fallback. - */ - @Test - public void testBadRequestExceptionViaExecuteInThread() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - try { - new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.THREAD).observe().toBlocking().single(); - fail("we expect to receive a " + HystrixBadRequestException.class.getSimpleName()); - } catch (HystrixBadRequestException e) { - // success - e.printStackTrace(); - } catch (Exception e) { - e.printStackTrace(); - fail("We expect a " + HystrixBadRequestException.class.getSimpleName() + " but got a " + e.getClass().getSimpleName()); - } - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - } - - /** - * Test that a BadRequestException can be thrown and not count towards errors and bypasses fallback. - */ - @Test - public void testBadRequestExceptionViaQueueInThread() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - try { - new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.THREAD).observe().toBlocking().toFuture().get(); - fail("we expect to receive a " + HystrixBadRequestException.class.getSimpleName()); - } catch (ExecutionException e) { - e.printStackTrace(); - if (e.getCause() instanceof HystrixBadRequestException) { - // success - } else { - fail("We expect a " + HystrixBadRequestException.class.getSimpleName() + " but got a " + e.getClass().getSimpleName()); - } - } catch (Exception e) { - e.printStackTrace(); - fail(); - } - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - } - - /** - * Test that BadRequestException behavior works the same on a cached response. - */ - @Test - public void testBadRequestExceptionViaQueueInThreadOnResponseFromCache() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - - // execute once to cache the value - try { - new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.THREAD).observe().toBlocking().single(); - } catch (Throwable e) { - // ignore - } - - try { - new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.THREAD).observe().toBlocking().toFuture().get(); - fail("we expect to receive a " + HystrixBadRequestException.class.getSimpleName()); - } catch (ExecutionException e) { - e.printStackTrace(); - if (e.getCause() instanceof HystrixBadRequestException) { - // success - } else { - fail("We expect a " + HystrixBadRequestException.class.getSimpleName() + " but got a " + e.getClass().getSimpleName()); - } - } catch (Exception e) { - e.printStackTrace(); - fail(); - } - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - } - - /** - * Test that a BadRequestException can be thrown and not count towards errors and bypasses fallback. - */ - @Test - public void testBadRequestExceptionViaExecuteInSemaphore() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - try { - new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.SEMAPHORE).observe().toBlocking().single(); - fail("we expect to receive a " + HystrixBadRequestException.class.getSimpleName()); - } catch (HystrixBadRequestException e) { - // success - e.printStackTrace(); - } catch (Exception e) { - e.printStackTrace(); - fail("We expect a " + HystrixBadRequestException.class.getSimpleName() + " but got a " + e.getClass().getSimpleName()); - } - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - } - - /** - * Test that a BadRequestException can be thrown and not count towards errors and bypasses fallback. - */ - @Test - public void testBadRequestExceptionViaQueueInSemaphore() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - try { - new BadRequestCommand(circuitBreaker, ExecutionIsolationStrategy.SEMAPHORE).observe().toBlocking().toFuture().get(); - fail("we expect to receive a " + HystrixBadRequestException.class.getSimpleName()); - } catch (ExecutionException e) { - e.printStackTrace(); - if (e.getCause() instanceof HystrixBadRequestException) { - // success - } else { - fail("We expect a " + HystrixBadRequestException.class.getSimpleName() + " but got a " + e.getClass().getSimpleName()); - } - } catch (Exception e) { - e.printStackTrace(); - fail(); - } - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - } - - /** - * Test a checked Exception being thrown - */ - @Test - public void testCheckedExceptionViaExecute() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - CommandWithCheckedException command = new CommandWithCheckedException(circuitBreaker); - try { - command.observe().toBlocking().single(); - fail("we expect to receive a " + Exception.class.getSimpleName()); - } catch (Exception e) { - assertEquals("simulated checked exception message", e.getCause().getMessage()); - } - - assertEquals("simulated checked exception message", command.getFailedExecutionException().getMessage()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - } - - /** - * Test a java.lang.Error being thrown - * - * @throws InterruptedException - */ - @Test - public void testCheckedExceptionViaObserve() throws InterruptedException { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - CommandWithCheckedException command = new CommandWithCheckedException(circuitBreaker); - final AtomicReference t = new AtomicReference(); - final CountDownLatch latch = new CountDownLatch(1); - try { - command.observe().subscribe(new Observer() { - - @Override - public void onCompleted() { - latch.countDown(); - } - - @Override - public void onError(Throwable e) { - t.set(e); - latch.countDown(); - } - - @Override - public void onNext(Boolean args) { - - } - - }); - } catch (Exception e) { - e.printStackTrace(); - fail("we should not get anything thrown, it should be emitted via the Observer#onError method"); - } - - latch.await(1, TimeUnit.SECONDS); - assertNotNull(t.get()); - t.get().printStackTrace(); - - assertTrue(t.get() instanceof HystrixRuntimeException); - assertEquals("simulated checked exception message", t.get().getCause().getMessage()); - assertEquals("simulated checked exception message", command.getFailedExecutionException().getMessage()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a java.lang.Error being thrown - */ - @Test - public void testErrorThrownViaExecute() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - CommandWithErrorThrown command = new CommandWithErrorThrown(circuitBreaker); - try { - command.observe().toBlocking().single(); - fail("we expect to receive a " + Error.class.getSimpleName()); - } catch (Exception e) { - // the actual error is an extra cause level deep because Hystrix needs to wrap Throwable/Error as it's public - // methods only support Exception and it's not a strong enough reason to break backwards compatibility and jump to version 2.x - // so HystrixRuntimeException -> wrapper Exception -> actual Error - assertEquals("simulated java.lang.Error message", e.getCause().getCause().getMessage()); - } - - assertEquals("simulated java.lang.Error message", command.getFailedExecutionException().getCause().getMessage()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a java.lang.Error being thrown - */ - @Test - public void testErrorThrownViaQueue() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - CommandWithErrorThrown command = new CommandWithErrorThrown(circuitBreaker); - try { - command.observe().toBlocking().toFuture().get(); - fail("we expect to receive an Exception"); - } catch (Exception e) { - // one cause down from ExecutionException to HystrixRuntime - // then the actual error is an extra cause level deep because Hystrix needs to wrap Throwable/Error as it's public - // methods only support Exception and it's not a strong enough reason to break backwards compatibility and jump to version 2.x - // so ExecutionException -> HystrixRuntimeException -> wrapper Exception -> actual Error - assertEquals("simulated java.lang.Error message", e.getCause().getCause().getCause().getMessage()); - } - - assertEquals("simulated java.lang.Error message", command.getFailedExecutionException().getCause().getMessage()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a java.lang.Error being thrown - * - * @throws InterruptedException - */ - @Test - public void testErrorThrownViaObserve() throws InterruptedException { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - CommandWithErrorThrown command = new CommandWithErrorThrown(circuitBreaker); - final AtomicReference t = new AtomicReference(); - final CountDownLatch latch = new CountDownLatch(1); - try { - command.observe().subscribe(new Observer() { - - @Override - public void onCompleted() { - latch.countDown(); - } - - @Override - public void onError(Throwable e) { - t.set(e); - latch.countDown(); - } - - @Override - public void onNext(Boolean args) { - - } - - }); - } catch (Exception e) { - e.printStackTrace(); - fail("we should not get anything thrown, it should be emitted via the Observer#onError method"); - } - - latch.await(1, TimeUnit.SECONDS); - assertNotNull(t.get()); - t.get().printStackTrace(); - - assertTrue(t.get() instanceof HystrixRuntimeException); - // the actual error is an extra cause level deep because Hystrix needs to wrap Throwable/Error as it's public - // methods only support Exception and it's not a strong enough reason to break backwards compatibility and jump to version 2.x - assertEquals("simulated java.lang.Error message", t.get().getCause().getCause().getMessage()); - assertEquals("simulated java.lang.Error message", command.getFailedExecutionException().getCause().getMessage()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isFailedExecution()); - - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on successful execution - */ - @Test - public void testExecutionHookSuccessfulCommand() { - //test with observe().toBlocking().single() - TestHystrixCommand command = new SuccessfulTestCommand(); - command.observe().toBlocking().single(); - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we expect a successful response from run() - assertNotNull(command.builder.executionHook.runSuccessResponse); - // we do not expect an exception - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should not be run as we were successful - assertEquals(0, command.builder.executionHook.startFallback.get()); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().single() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should have a response from observe().toBlocking().single() since run() succeeded - assertNotNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should not have an exception since run() succeeded - assertNull(command.builder.executionHook.endExecuteFailureException); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // test with observe().toBlocking().toFuture() - command = new SuccessfulTestCommand(); - try { - command.observe().toBlocking().toFuture().get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we expect a successful response from run() - assertNotNull(command.builder.executionHook.runSuccessResponse); - // we do not expect an exception - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should not be run as we were successful - assertEquals(0, command.builder.executionHook.startFallback.get()); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().toFuture() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should have a response from observe().toBlocking().toFuture() since run() succeeded - assertNotNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should not have an exception since run() succeeded - assertNull(command.builder.executionHook.endExecuteFailureException); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on successful execution with "fire and forget" approach - */ - @Test - public void testExecutionHookSuccessfulCommandViaFireAndForget() { - TestHystrixCommand command = new SuccessfulTestCommand(); - try { - // do not block on "get()" ... fire this asynchronously - command.observe().toBlocking().toFuture(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - // wait for command to execute without calling get on the future - while (!command.isExecutionComplete()) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - throw new RuntimeException("interrupted"); - } - } - - /* All the hooks should still work even though we didn't call get() on the future */ - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we expect a successful response from run() - assertNotNull(command.builder.executionHook.runSuccessResponse); - // we do not expect an exception - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should not be run as we were successful - assertEquals(0, command.builder.executionHook.startFallback.get()); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().toFuture() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should have a response from observe().toBlocking().toFuture() since run() succeeded - assertNotNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should not have an exception since run() succeeded - assertNull(command.builder.executionHook.endExecuteFailureException); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on successful execution with multiple get() calls to Future - */ - @Test - public void testExecutionHookSuccessfulCommandWithMultipleGetsOnFuture() { - TestHystrixCommand command = new SuccessfulTestCommand(); - try { - Future f = command.observe().toBlocking().toFuture(); - f.get(); - f.get(); - f.get(); - f.get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - /* Despite multiple calls to get() we should only have 1 call to the hooks. */ - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we expect a successful response from run() - assertNotNull(command.builder.executionHook.runSuccessResponse); - // we do not expect an exception - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should not be run as we were successful - assertEquals(0, command.builder.executionHook.startFallback.get()); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().toFuture() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should have a response from observe().toBlocking().toFuture() since run() succeeded - assertNotNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should not have an exception since run() succeeded - assertNull(command.builder.executionHook.endExecuteFailureException); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on failed execution without a fallback - */ - @Test - public void testExecutionHookRunFailureWithoutFallback() { - // test with observe().toBlocking().single() - TestHystrixCommand command = new UnknownFailureTestCommandWithoutFallback(); - try { - command.observe().toBlocking().single(); - fail("Expecting exception"); - } catch (Exception e) { - // ignore - } - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we should not have a response - assertNull(command.builder.executionHook.runSuccessResponse); - // we should have an exception - assertNotNull(command.builder.executionHook.runFailureException); - - // the fallback() method should be run since run() failed - assertEquals(1, command.builder.executionHook.startFallback.get()); - // no response since fallback is not implemented - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // not null since it's not implemented and throws an exception - assertNotNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().single() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should not have a response from observe().toBlocking().single() since we do not have a fallback and run() failed - assertNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should have an exception since run() failed - assertNotNull(command.builder.executionHook.endExecuteFailureException); - // run() failure - assertEquals(FailureType.COMMAND_EXCEPTION, command.builder.executionHook.endExecuteFailureType); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // test with observe().toBlocking().toFuture() - command = new UnknownFailureTestCommandWithoutFallback(); - try { - command.observe().toBlocking().toFuture().get(); - fail("Expecting exception"); - } catch (Exception e) { - // ignore - } - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we should not have a response - assertNull(command.builder.executionHook.runSuccessResponse); - // we should have an exception - assertNotNull(command.builder.executionHook.runFailureException); - - // the fallback() method should be run since run() failed - assertEquals(1, command.builder.executionHook.startFallback.get()); - // no response since fallback is not implemented - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // not null since it's not implemented and throws an exception - assertNotNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().toFuture() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should not have a response from observe().toBlocking().toFuture() since we do not have a fallback and run() failed - assertNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should have an exception since run() failed - assertNotNull(command.builder.executionHook.endExecuteFailureException); - // run() failure - assertEquals(FailureType.COMMAND_EXCEPTION, command.builder.executionHook.endExecuteFailureType); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - - } - - /** - * Execution hook on failed execution with a fallback - */ - @Test - public void testExecutionHookRunFailureWithFallback() { - // test with observe().toBlocking().single() - TestHystrixCommand command = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker()); - command.observe().toBlocking().single(); - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we should not have a response from run since run() failed - assertNull(command.builder.executionHook.runSuccessResponse); - // we should have an exception since run() failed - assertNotNull(command.builder.executionHook.runFailureException); - - // the fallback() method should be run since run() failed - assertEquals(1, command.builder.executionHook.startFallback.get()); - // a response since fallback is implemented - assertNotNull(command.builder.executionHook.fallbackSuccessResponse); - // null since it's implemented and succeeds - assertNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().single() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should have a response from observe().toBlocking().single() since we expect a fallback despite failure of run() - assertNotNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should not have an exception because we expect a fallback - assertNull(command.builder.executionHook.endExecuteFailureException); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // test with observe().toBlocking().toFuture() - command = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker()); - try { - command.observe().toBlocking().toFuture().get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we should not have a response from run since run() failed - assertNull(command.builder.executionHook.runSuccessResponse); - // we should have an exception since run() failed - assertNotNull(command.builder.executionHook.runFailureException); - - // the fallback() method should be run since run() failed - assertEquals(1, command.builder.executionHook.startFallback.get()); - // a response since fallback is implemented - assertNotNull(command.builder.executionHook.fallbackSuccessResponse); - // null since it's implemented and succeeds - assertNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().toFuture() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should have a response from observe().toBlocking().toFuture() since we expect a fallback despite failure of run() - assertNotNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should not have an exception because we expect a fallback - assertNull(command.builder.executionHook.endExecuteFailureException); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on failed execution with a fallback failure - */ - @Test - public void testExecutionHookRunFailureWithFallbackFailure() { - // test with observe().toBlocking().single() - TestHystrixCommand command = new KnownFailureTestCommandWithFallbackFailure(); - try { - command.observe().toBlocking().single(); - fail("Expecting exception"); - } catch (Exception e) { - // ignore - } - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we should not have a response because run() and fallback fail - assertNull(command.builder.executionHook.runSuccessResponse); - // we should have an exception because run() and fallback fail - assertNotNull(command.builder.executionHook.runFailureException); - - // the fallback() method should be run since run() failed - assertEquals(1, command.builder.executionHook.startFallback.get()); - // no response since fallback fails - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // not null since it's implemented but fails - assertNotNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().single() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should not have a response because run() and fallback fail - assertNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should have an exception because run() and fallback fail - assertNotNull(command.builder.executionHook.endExecuteFailureException); - // run() failure - assertEquals(FailureType.COMMAND_EXCEPTION, command.builder.executionHook.endExecuteFailureType); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // test with observe().toBlocking().toFuture() - command = new KnownFailureTestCommandWithFallbackFailure(); - try { - command.observe().toBlocking().toFuture().get(); - fail("Expecting exception"); - } catch (Exception e) { - // ignore - } - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we should not have a response because run() and fallback fail - assertNull(command.builder.executionHook.runSuccessResponse); - // we should have an exception because run() and fallback fail - assertNotNull(command.builder.executionHook.runFailureException); - - // the fallback() method should be run since run() failed - assertEquals(1, command.builder.executionHook.startFallback.get()); - // no response since fallback fails - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // not null since it's implemented but fails - assertNotNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().toFuture() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should not have a response because run() and fallback fail - assertNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should have an exception because run() and fallback fail - assertNotNull(command.builder.executionHook.endExecuteFailureException); - // run() failure - assertEquals(FailureType.COMMAND_EXCEPTION, command.builder.executionHook.endExecuteFailureType); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on timeout without a fallback - */ - @Test - public void testExecutionHookTimeoutWithoutFallback() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_NOT_IMPLEMENTED); - try { - System.out.println("start at : " + System.currentTimeMillis()); - command.observe().toBlocking().toFuture().get(); - fail("Expecting exception"); - } catch (Exception e) { - // ignore - } - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we should not have a response because of timeout and no fallback - assertNull(command.builder.executionHook.runSuccessResponse); - // we should not have an exception because run() didn't fail, it timed out - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should be run due to timeout - assertEquals(1, command.builder.executionHook.startFallback.get()); - // no response since no fallback - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // not null since no fallback implementation - assertNotNull(command.builder.executionHook.fallbackFailureException); - - // execution occurred - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should not have a response because of timeout and no fallback - assertNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should have an exception because of timeout and no fallback - assertNotNull(command.builder.executionHook.endExecuteFailureException); - // timeout failure - assertEquals(FailureType.TIMEOUT, command.builder.executionHook.endExecuteFailureType); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - - // we need to wait for the thread to complete before the onThreadComplete hook will be called - // try { - // Thread.sleep(400); - // } catch (InterruptedException e) { - // // ignore - // } - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on timeout with a fallback - */ - @Test - public void testExecutionHookTimeoutWithFallback() { - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS); - try { - command.observe().toBlocking().toFuture().get(); - } catch (Exception e) { - throw new RuntimeException("not expecting", e); - } - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we should not have a response because of timeout - assertNull(command.builder.executionHook.runSuccessResponse); - // we should not have an exception because run() didn't fail, it timed out - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should be run due to timeout - assertEquals(1, command.builder.executionHook.startFallback.get()); - // response since we have a fallback - assertNotNull(command.builder.executionHook.fallbackSuccessResponse); - // null since fallback succeeds - assertNull(command.builder.executionHook.fallbackFailureException); - - // execution occurred - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should have a response because of fallback - assertNotNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should not have an exception because of fallback - assertNull(command.builder.executionHook.endExecuteFailureException); - - // thread execution - // assertEquals(1, command.builder.executionHook.threadStart.get()); - - // we need to wait for the thread to complete before the onThreadComplete hook will be called - // try { - // Thread.sleep(400); - // } catch (InterruptedException e) { - // // ignore - // } - // assertEquals(1, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on rejected with a fallback - */ - /* - * @Test - * public void testExecutionHookRejectedWithFallback() { - * TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - * SingleThreadedPool pool = new SingleThreadedPool(1); - * - * try { - * // fill the queue - * new TestCommandRejection(circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_SUCCESS).observe().toBlocking().toFuture(); - * new TestCommandRejection(circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_SUCCESS).observe().toBlocking().toFuture(); - * } catch (Exception e) { - * // ignore - * } - * - * TestCommandRejection command = new TestCommandRejection(circuitBreaker, pool, 500, 600, TestCommandRejection.FALLBACK_SUCCESS); - * try { - * // now execute one that will be rejected - * command.observe().toBlocking().toFuture().get(); - * } catch (Exception e) { - * throw new RuntimeException("not expecting", e); - * } - * - * assertTrue(command.isResponseRejected()); - * - * // the run() method should not run as we're rejected - * assertEquals(0, command.builder.executionHook.startRun.get()); - * // we should not have a response because of rejection - * assertNull(command.builder.executionHook.runSuccessResponse); - * // we should not have an exception because we didn't run - * assertNull(command.builder.executionHook.runFailureException); - * - * // the fallback() method should be run due to rejection - * assertEquals(1, command.builder.executionHook.startFallback.get()); - * // response since we have a fallback - * assertNotNull(command.builder.executionHook.fallbackSuccessResponse); - * // null since fallback succeeds - * assertNull(command.builder.executionHook.fallbackFailureException); - * - * // execution occurred - * assertEquals(1, command.builder.executionHook.startExecute.get()); - * // we should have a response because of fallback - * assertNotNull(command.builder.executionHook.endExecuteSuccessResponse); - * // we should not have an exception because of fallback - * assertNull(command.builder.executionHook.endExecuteFailureException); - * - * // thread execution - * // assertEquals(0, command.builder.executionHook.threadStart.get()); - * // assertEquals(0, command.builder.executionHook.threadComplete.get()); - * } - */ - /** - * Execution hook on short-circuit with a fallback - */ - @Test - public void testExecutionHookShortCircuitedWithFallbackViaQueue() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker().setForceShortCircuit(true); - KnownFailureTestCommandWithoutFallback command = new KnownFailureTestCommandWithoutFallback(circuitBreaker); - try { - // now execute one that will be short-circuited - command.observe().toBlocking().toFuture().get(); - fail("we expect an error as there is no fallback"); - } catch (Exception e) { - // expecting - } - - assertTrue(command.isResponseShortCircuited()); - - // the run() method should not run as we're rejected - assertEquals(0, command.builder.executionHook.startRun.get()); - // we should not have a response because of rejection - assertNull(command.builder.executionHook.runSuccessResponse); - // we should not have an exception because we didn't run - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should be run due to rejection - assertEquals(1, command.builder.executionHook.startFallback.get()); - // no response since we don't have a fallback - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // not null since fallback fails and throws an exception - assertNotNull(command.builder.executionHook.fallbackFailureException); - - // execution occurred - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should not have a response because fallback fails - assertNull(command.builder.executionHook.endExecuteSuccessResponse); - // we won't have an exception because short-circuit doesn't have one - assertNull(command.builder.executionHook.endExecuteFailureException); - // but we do expect to receive a onError call with FailureType.SHORTCIRCUIT - assertEquals(FailureType.SHORTCIRCUIT, command.builder.executionHook.endExecuteFailureType); - - // thread execution - // assertEquals(0, command.builder.executionHook.threadStart.get()); - // assertEquals(0, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on short-circuit with a fallback - */ - @Test - public void testExecutionHookShortCircuitedWithFallbackViaExecute() { - TestCircuitBreaker circuitBreaker = new TestCircuitBreaker().setForceShortCircuit(true); - KnownFailureTestCommandWithoutFallback command = new KnownFailureTestCommandWithoutFallback(circuitBreaker); - try { - // now execute one that will be short-circuited - command.observe().toBlocking().single(); - fail("we expect an error as there is no fallback"); - } catch (Exception e) { - // expecting - } - - assertTrue(command.isResponseShortCircuited()); - - // the run() method should not run as we're rejected - assertEquals(0, command.builder.executionHook.startRun.get()); - // we should not have a response because of rejection - assertNull(command.builder.executionHook.runSuccessResponse); - // we should not have an exception because we didn't run - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should be run due to rejection - assertEquals(1, command.builder.executionHook.startFallback.get()); - // no response since we don't have a fallback - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // not null since fallback fails and throws an exception - assertNotNull(command.builder.executionHook.fallbackFailureException); - - // execution occurred - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should not have a response because fallback fails - assertNull(command.builder.executionHook.endExecuteSuccessResponse); - // we won't have an exception because short-circuit doesn't have one - assertNull(command.builder.executionHook.endExecuteFailureException); - // but we do expect to receive a onError call with FailureType.SHORTCIRCUIT - assertEquals(FailureType.SHORTCIRCUIT, command.builder.executionHook.endExecuteFailureType); - - // thread execution - // assertEquals(0, command.builder.executionHook.threadStart.get()); - // assertEquals(0, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on successful execution with semaphore isolation - */ - @Test - public void testExecutionHookSuccessfulCommandWithSemaphoreIsolation() { - // test with observe().toBlocking().single() - TestSemaphoreCommand command = new TestSemaphoreCommand(new TestCircuitBreaker(), 1, 10); - command.observe().toBlocking().single(); - - assertFalse(command.isExecutedInThread()); - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we expect a successful response from run() - assertNotNull(command.builder.executionHook.runSuccessResponse); - // we do not expect an exception - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should not be run as we were successful - assertEquals(0, command.builder.executionHook.startFallback.get()); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().single() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should have a response from observe().toBlocking().single() since run() succeeded - assertNotNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should not have an exception since run() succeeded - assertNull(command.builder.executionHook.endExecuteFailureException); - - // thread execution - assertEquals(0, command.builder.executionHook.threadStart.get()); - assertEquals(0, command.builder.executionHook.threadComplete.get()); - - // test with observe().toBlocking().toFuture() - command = new TestSemaphoreCommand(new TestCircuitBreaker(), 1, 10); - try { - command.observe().toBlocking().toFuture().get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - assertFalse(command.isExecutedInThread()); - - // the run() method should run as we're not short-circuited or rejected - assertEquals(1, command.builder.executionHook.startRun.get()); - // we expect a successful response from run() - assertNotNull(command.builder.executionHook.runSuccessResponse); - // we do not expect an exception - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should not be run as we were successful - assertEquals(0, command.builder.executionHook.startFallback.get()); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // null since it didn't run - assertNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().toFuture() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should have a response from observe().toBlocking().toFuture() since run() succeeded - assertNotNull(command.builder.executionHook.endExecuteSuccessResponse); - // we should not have an exception since run() succeeded - assertNull(command.builder.executionHook.endExecuteFailureException); - - // thread execution - assertEquals(0, command.builder.executionHook.threadStart.get()); - assertEquals(0, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Execution hook on successful execution with semaphore isolation - */ - @Test - public void testExecutionHookFailureWithSemaphoreIsolation() { - // test with observe().toBlocking().single() - final TryableSemaphoreActual semaphore = - new TryableSemaphoreActual(HystrixProperty.Factory.asProperty(0)); - - TestSemaphoreCommand command = new TestSemaphoreCommand(new TestCircuitBreaker(), semaphore, 200); - try { - command.observe().toBlocking().single(); - fail("we expect a failure"); - } catch (Exception e) { - // expected - } - - assertFalse(command.isExecutedInThread()); - assertTrue(command.isResponseRejected()); - - // the run() method should not run as we are rejected - assertEquals(0, command.builder.executionHook.startRun.get()); - // null as run() does not get invoked - assertNull(command.builder.executionHook.runSuccessResponse); - // null as run() does not get invoked - assertNull(command.builder.executionHook.runFailureException); - - // the fallback() method should run because of rejection - assertEquals(1, command.builder.executionHook.startFallback.get()); - // null since there is no fallback - assertNull(command.builder.executionHook.fallbackSuccessResponse); - // not null since the fallback is not implemented - assertNotNull(command.builder.executionHook.fallbackFailureException); - - // the observe().toBlocking().single() method was used - assertEquals(1, command.builder.executionHook.startExecute.get()); - // we should not have a response since fallback has nothing - assertNull(command.builder.executionHook.endExecuteSuccessResponse); - // we won't have an exception because rejection doesn't have one - assertNull(command.builder.executionHook.endExecuteFailureException); - // but we do expect to receive a onError call with FailureType.SHORTCIRCUIT - assertEquals(FailureType.REJECTED_SEMAPHORE_EXECUTION, command.builder.executionHook.endExecuteFailureType); - - // thread execution - assertEquals(0, command.builder.executionHook.threadStart.get()); - assertEquals(0, command.builder.executionHook.threadComplete.get()); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * Test a command execution that fails but has a fallback. - */ - @Test - public void testExecutionFailureWithFallbackImplementedButDisabled() { - TestHystrixCommand commandEnabled = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker(), true); - try { - assertEquals(false, commandEnabled.observe().toBlocking().single()); - } catch (Exception e) { - e.printStackTrace(); - fail("We should have received a response from the fallback."); - } - - TestHystrixCommand commandDisabled = new KnownFailureTestCommandWithFallback(new TestCircuitBreaker(), false); - try { - assertEquals(false, commandDisabled.observe().toBlocking().single()); - fail("expect exception thrown"); - } catch (Exception e) { - // expected - } - - assertEquals("we failed with a simulated issue", commandDisabled.getFailedExecutionException().getMessage()); - - assertTrue(commandDisabled.isFailedExecution()); - - assertEquals(0, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.EXCEPTION_THROWN)); - assertEquals(1, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE)); - assertEquals(0, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_REJECTION)); - assertEquals(0, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_FAILURE)); - assertEquals(0, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(0, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(0, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, commandDisabled.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, commandDisabled.builder.metrics.getHealthCounts().getErrorPercentage()); - - // assertEquals(2, HystrixRequestLog.getCurrentRequest().getExecutedCommands().size()); - } - - /** - * Test that we can still use thread isolation if desired. - */ - @Test(timeout = 500) - public void testSynchronousExecutionTimeoutValueViaExecute() { - HystrixAsyncCommand.Setter properties = HystrixAsyncCommand.Setter - .withGroupKey(HystrixCommandGroupKey.Factory.asKey("TestKey")) - .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() - .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD) - .withExecutionIsolationThreadTimeoutInMilliseconds(50)); - - System.out.println(">>>>> Begin: " + System.currentTimeMillis()); - - HystrixAsyncCommand command = new HystrixAsyncCommand(properties) { - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - p.onSuccess("hello"); - } - - }, Schedulers.immediate()); - } - - @Override - protected HystrixFuture getFallback() { - if (isResponseTimedOut()) { - return HystrixFutureUtil.just("timed-out"); - } else { - return HystrixFutureUtil.just("abc"); - } - } - }; - - System.out.println(">>>>> Start: " + System.currentTimeMillis()); - String value = command.observe().toBlocking().single(); - System.out.println(">>>>> End: " + System.currentTimeMillis()); - assertTrue(command.isResponseTimedOut()); - assertEquals("expected fallback value", "timed-out", value); - - // Thread isolated - assertTrue(command.isExecutedInThread()); - } - - @Test(timeout = 500) - public void testSynchronousExecutionUsingThreadIsolationTimeoutValueViaObserve() { - HystrixAsyncCommand.Setter properties = HystrixAsyncCommand.Setter - .withGroupKey(HystrixCommandGroupKey.Factory.asKey("TestKey")) - .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() - .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD) - .withExecutionIsolationThreadTimeoutInMilliseconds(50)); - - HystrixAsyncCommand command = new HystrixAsyncCommand(properties) { - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - p.onSuccess("hello"); - } - - }, Schedulers.immediate()); - } - - @Override - protected HystrixFuture getFallback() { - if (isResponseTimedOut()) { - return HystrixFutureUtil.just("timed-out"); - } else { - return HystrixFutureUtil.just("abc"); - } - } - }; - - String value = command.observe().toBlocking().last(); - assertTrue(command.isResponseTimedOut()); - assertEquals("expected fallback value", "timed-out", value); - - // Thread isolated - assertTrue(command.isExecutedInThread()); - } - - @Test(timeout = 500) - public void testAsyncExecutionTimeoutValueViaObserve() { - HystrixAsyncCommand.Setter properties = HystrixAsyncCommand.Setter - .withGroupKey(HystrixCommandGroupKey.Factory.asKey("TestKey")) - .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() - .withExecutionIsolationThreadTimeoutInMilliseconds(50)); - - HystrixAsyncCommand command = new HystrixAsyncCommand(properties) { - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - System.out.println("********** interrupted on timeout"); - e.printStackTrace(); - } - // should never reach here - p.onSuccess("hello"); - } - - }, Schedulers.newThread()); - } - - @Override - protected HystrixFuture getFallback() { - if (isResponseTimedOut()) { - return HystrixFutureUtil.just("timed-out"); - } else { - return HystrixFutureUtil.just("abc"); - } - } - }; - - String value = command.observe().toBlocking().last(); - assertTrue(command.isResponseTimedOut()); - assertEquals("expected fallback value", "timed-out", value); - - // semaphore isolated - assertFalse(command.isExecutedInThread()); - } - - /** - * See https://github.com/Netflix/Hystrix/issues/212 - */ - @Test - public void testObservableTimeoutNoFallbackThreadContext() { - TestSubscriber ts = new TestSubscriber(); - - final AtomicReference onErrorThread = new AtomicReference(); - final AtomicBoolean isRequestContextInitialized = new AtomicBoolean(); - - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_NOT_IMPLEMENTED); - command.toObservable().doOnError(new Action1() { - - @Override - public void call(Throwable t1) { - System.out.println("onError: " + t1); - System.out.println("onError Thread: " + Thread.currentThread()); - System.out.println("ThreadContext in onError: " + HystrixRequestContext.isCurrentThreadInitialized()); - onErrorThread.set(Thread.currentThread()); - isRequestContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized()); - } - - }).subscribe(ts); - - ts.awaitTerminalEvent(); - - assertTrue(isRequestContextInitialized.get()); - assertTrue(onErrorThread.get().getName().startsWith("HystrixTimer")); - - List errors = ts.getOnErrorEvents(); - assertEquals(1, errors.size()); - Throwable e = errors.get(0); - if (errors.get(0) 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 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()); - } - - /** - * See https://github.com/Netflix/Hystrix/issues/212 - */ - @Test - public void testObservableTimeoutFallbackThreadContext() { - TestSubscriber ts = new TestSubscriber(); - - final AtomicReference onErrorThread = new AtomicReference(); - final AtomicBoolean isRequestContextInitialized = new AtomicBoolean(); - - TestHystrixCommand command = new TestCommandWithTimeout(50, TestCommandWithTimeout.FALLBACK_SUCCESS); - command.toObservable().doOnNext(new Action1() { - - @Override - public void call(Boolean t1) { - System.out.println("onNext: " + t1); - System.out.println("onNext Thread: " + Thread.currentThread()); - System.out.println("ThreadContext in onNext: " + HystrixRequestContext.isCurrentThreadInitialized()); - onErrorThread.set(Thread.currentThread()); - isRequestContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized()); - } - - }).subscribe(ts); - - ts.awaitTerminalEvent(); - - System.out.println("events: " + ts.getOnNextEvents()); - - assertTrue(isRequestContextInitialized.get()); - assertTrue(onErrorThread.get().getName().startsWith("HystrixTimer")); - - List onNexts = ts.getOnNextEvents(); - assertEquals(1, onNexts.size()); - assertFalse(onNexts.get(0)); - - 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 - public void testRejectedViaSemaphoreIsolation() { - final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - final ArrayBlockingQueue results = new ArrayBlockingQueue(2); - final List executionThreads = Collections.synchronizedList(new ArrayList(2)); - final List responseThreads = Collections.synchronizedList(new ArrayList(2)); - - final AtomicBoolean exceptionReceived = new AtomicBoolean(); - - Runnable r = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() { - - @Override - public void run() { - try { - executionThreads.add(Thread.currentThread()); - results.add(new TestSemaphoreCommand(circuitBreaker, 1, 200).toObservable().map(new Func1() { - - @Override - public Boolean call(Boolean b) { - responseThreads.add(Thread.currentThread()); - return b; - } - - }).toBlocking().single()); - } 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"); - } - - // one thread should have returned values - assertEquals(1, results.size()); - assertTrue(results.contains(Boolean.TRUE)); - // the other thread should have thrown an Exception - assertTrue(exceptionReceived.get()); - - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, 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(0, 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()); - } - - @Test - public void testRejectedViaThreadIsolation() throws InterruptedException { - final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker(); - final ArrayBlockingQueue results = new ArrayBlockingQueue(10); - final List executionThreads = Collections.synchronizedList(new ArrayList(20)); - final List responseThreads = Collections.synchronizedList(new ArrayList(10)); - - final AtomicBoolean exceptionReceived = new AtomicBoolean(); - final CountDownLatch scheduleLatch = new CountDownLatch(2); - final CountDownLatch successLatch = new CountDownLatch(1); - final AtomicInteger count = new AtomicInteger(); - - Runnable r = new HystrixContextRunnable(HystrixPlugins.getInstance().getConcurrencyStrategy(), new Runnable() { - - @Override - public void run() { - final boolean shouldExecute = count.incrementAndGet() < 3; - try { - executionThreads.add(Thread.currentThread()); - results.add(new TestThreadIsolationWithSemaphoreSetSmallCommand(circuitBreaker, 2, new Action0() { - - @Override - public void call() { - // make sure it's deterministic and we put 2 threads into the pool before the 3rd is submitted - if (shouldExecute) { - try { - scheduleLatch.countDown(); - successLatch.await(); - } catch (InterruptedException e) { - } - } - } - - }).toObservable().map(new Func1() { - - @Override - public Boolean call(Boolean b) { - responseThreads.add(Thread.currentThread()); - return b; - } - - }).finallyDo(new Action0() { - - @Override - public void call() { - if (!shouldExecute) { - // the final thread that shouldn't execute releases the latch once it has run - // so it is deterministic that the other two fill the thread pool until this one rejects - successLatch.countDown(); - } - } - - }).toBlocking().single()); - } 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); - Thread t3 = new Thread(r); - - t1.start(); - t2.start(); - // wait for the previous 2 thread to be running before starting otherwise it can race - scheduleLatch.await(500, TimeUnit.MILLISECONDS); - t3.start(); - try { - t1.join(); - t2.join(); - t3.join(); - } catch (Exception e) { - e.printStackTrace(); - fail("failed waiting on threads"); - } - - // we should have 2 of the 3 return results - assertEquals(2, results.size()); - // the other thread should have thrown an Exception - assertTrue(exceptionReceived.get()); - - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(2, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS)); - assertEquals(1, 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(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.FALLBACK_SUCCESS)); - assertEquals(1, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - // the rest should not be involved in this test - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT)); - assertEquals(0, circuitBreaker.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(3, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - } - - /* ******************************************************************************************************** */ - /* *************************************** Request Context Testing Below ********************************** */ - /* ******************************************************************************************************** */ - - private RequestContextTestResults testRequestContextOnSuccess(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) { - final RequestContextTestResults results = new RequestContextTestResults(); - TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder() - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation))) { - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.originThread.set(Thread.currentThread()); - p.onSuccess(true); - } - - }, userScheduler); - } - - }; - - results.command = command; - - command.toObservable().doOnEach(new Action1>() { - - @Override - public void call(Notification n) { - results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.observeOnThread.set(Thread.currentThread()); - } - - }).subscribe(results.ts); - results.ts.awaitTerminalEvent(); - - System.out.println("Run => Initialized: " + results.isContextInitialized.get() + " Thread: " + results.originThread.get()); - System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + " Thread: " + results.observeOnThread.get()); - - assertEquals(1, results.ts.getOnNextEvents().size()); - assertTrue(results.ts.getOnNextEvents().get(0)); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertTrue(command.isSuccessfulExecution()); - - 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.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.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(0, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - return results; - } - - private RequestContextTestResults testRequestContextOnGracefulFailure(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) { - final RequestContextTestResults results = new RequestContextTestResults(); - TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder() - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation))) { - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.originThread.set(Thread.currentThread()); - p.onError(new RuntimeException("graceful onError")); - } - - }, userScheduler); - } - - }; - - results.command = command; - - command.toObservable().doOnEach(new Action1>() { - - @Override - public void call(Notification n) { - results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.observeOnThread.set(Thread.currentThread()); - } - - }).subscribe(results.ts); - results.ts.awaitTerminalEvent(); - - System.out.println("Run => Initialized: " + results.isContextInitialized.get() + " Thread: " + results.originThread.get()); - System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + " Thread: " + results.observeOnThread.get()); - - assertEquals(1, results.ts.getOnErrorEvents().size()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertFalse(command.isSuccessfulExecution()); - assertTrue(command.isFailedExecution()); - - 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(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, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - return results; - } - - private RequestContextTestResults testRequestContextOnBadFailure(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) { - final RequestContextTestResults results = new RequestContextTestResults(); - TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder() - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation))) { - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.originThread.set(Thread.currentThread()); - throw new RuntimeException("bad onError"); - } - - }, userScheduler); - } - - }; - - results.command = command; - - command.toObservable().doOnEach(new Action1>() { - - @Override - public void call(Notification n) { - results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.observeOnThread.set(Thread.currentThread()); - } - - }).subscribe(results.ts); - results.ts.awaitTerminalEvent(); - - System.out.println("Run => Initialized: " + results.isContextInitialized.get() + " Thread: " + results.originThread.get()); - System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + " Thread: " + results.observeOnThread.get()); - - assertEquals(1, results.ts.getOnErrorEvents().size()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertFalse(command.isSuccessfulExecution()); - assertTrue(command.isFailedExecution()); - - 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(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, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - return results; - } - - private RequestContextTestResults testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) { - final RequestContextTestResults results = new RequestContextTestResults(); - TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder() - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation))) { - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise s) { - s.onError(new RuntimeException("onError")); - } - - }, userScheduler); - } - - @Override - protected HystrixFuture getFallback() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise s) { - results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.originThread.set(Thread.currentThread()); - s.onSuccess(false); - } - - }, userScheduler); - } - - }; - - results.command = command; - - command.toObservable().doOnEach(new Action1>() { - - @Override - public void call(Notification n) { - results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.observeOnThread.set(Thread.currentThread()); - } - - }).subscribe(results.ts); - results.ts.awaitTerminalEvent(); - - System.out.println("Run => Initialized: " + results.isContextInitialized.get() + " Thread: " + results.originThread.get()); - System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + " Thread: " + results.observeOnThread.get()); - - assertEquals(0, results.ts.getOnErrorEvents().size()); - assertEquals(1, results.ts.getOnNextEvents().size()); - assertEquals(false, results.ts.getOnNextEvents().get(0)); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertFalse(command.isSuccessfulExecution()); - assertTrue(command.isFailedExecution()); - - 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.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(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - return results; - } - - private RequestContextTestResults testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) { - final RequestContextTestResults results = new RequestContextTestResults(); - TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder() - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter() - .withExecutionIsolationStrategy(isolation) - .withExecutionIsolationSemaphoreMaxConcurrentRequests(0)) - .setThreadPool(new HystrixThreadPool() { - - @Override - public ThreadPoolExecutor getExecutor() { - return null; - } - - @Override - public void markThreadExecution() { - - } - - @Override - public void markThreadCompletion() { - - } - - @Override - public boolean isQueueSpaceAvailable() { - // always return false so we reject everything - return false; - } - - @Override - public Scheduler getScheduler() { - return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this); - } - - })) { - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise s) { - s.onError(new RuntimeException("onError")); - } - - }, userScheduler); - } - - @Override - protected HystrixFuture getFallback() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise s) { - results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.originThread.set(Thread.currentThread()); - s.onSuccess(false); - } - - }, userScheduler); - } - - }; - - results.command = command; - - command.toObservable().doOnEach(new Action1>() { - - @Override - public void call(Notification n) { - results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.observeOnThread.set(Thread.currentThread()); - } - - }).subscribe(results.ts); - results.ts.awaitTerminalEvent(); - - System.out.println("Run => Initialized: " + results.isContextInitialized.get() + " Thread: " + results.originThread.get()); - System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + " Thread: " + results.observeOnThread.get()); - - assertEquals(0, results.ts.getOnErrorEvents().size()); - assertEquals(1, results.ts.getOnNextEvents().size()); - assertEquals(false, results.ts.getOnNextEvents().get(0)); - - assertTrue(command.getExecutionTimeInMilliseconds() == -1); - assertFalse(command.isSuccessfulExecution()); - assertTrue(command.isResponseRejected()); - - 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)); - if (isolation == ExecutionIsolationStrategy.SEMAPHORE) { - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.SEMAPHORE_REJECTED)); - } else { - assertEquals(1, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.THREAD_POOL_REJECTED)); - 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.TIMEOUT)); - assertEquals(0, command.builder.metrics.getRollingCount(HystrixRollingNumberEvent.RESPONSE_FROM_CACHE)); - - assertEquals(100, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - return results; - } - - private RequestContextTestResults testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) { - final RequestContextTestResults results = new RequestContextTestResults(); - TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder() - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter() - .withExecutionIsolationStrategy(isolation)) - .setCircuitBreaker(new TestCircuitBreaker().setForceShortCircuit(true))) { - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise s) { - s.onError(new RuntimeException("onError")); - } - - }, userScheduler); - } - - @Override - protected HystrixFuture getFallback() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise s) { - results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.originThread.set(Thread.currentThread()); - s.onSuccess(false); - } - - }, userScheduler); - } - - }; - - results.command = command; - - command.toObservable().doOnEach(new Action1>() { - - @Override - public void call(Notification n) { - results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.observeOnThread.set(Thread.currentThread()); - } - - }).subscribe(results.ts); - results.ts.awaitTerminalEvent(); - - System.out.println("Run => Initialized: " + results.isContextInitialized.get() + " Thread: " + results.originThread.get()); - System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + " Thread: " + results.observeOnThread.get()); - - assertEquals(0, results.ts.getOnErrorEvents().size()); - assertEquals(1, results.ts.getOnNextEvents().size()); - assertEquals(false, results.ts.getOnNextEvents().get(0)); - - assertTrue(command.getExecutionTimeInMilliseconds() == -1); - assertFalse(command.isSuccessfulExecution()); - assertTrue(command.isResponseShortCircuited()); - - 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(1, 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, command.builder.metrics.getHealthCounts().getErrorPercentage()); - - assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - - return results; - } - - private RequestContextTestResults testRequestContextOnTimeout(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) { - final RequestContextTestResults results = new RequestContextTestResults(); - TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder() - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation).withExecutionIsolationThreadTimeoutInMilliseconds(50))) { - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise s) { - results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.originThread.set(Thread.currentThread()); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - // ignore the interrupted exception - } - } - - }, userScheduler); - } - - }; - - results.command = command; - - command.toObservable().doOnEach(new Action1>() { - - @Override - public void call(Notification n) { - results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.observeOnThread.set(Thread.currentThread()); - } - - }).subscribe(results.ts); - results.ts.awaitTerminalEvent(); - - System.out.println("Run => Initialized: " + results.isContextInitialized.get() + " Thread: " + results.originThread.get()); - System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + " Thread: " + results.observeOnThread.get()); - - assertEquals(1, results.ts.getOnErrorEvents().size()); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertFalse(command.isSuccessfulExecution()); - 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()); - - return results; - } - - private RequestContextTestResults testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) { - final RequestContextTestResults results = new RequestContextTestResults(); - TestHystrixCommand command = new TestHystrixCommand(TestHystrixCommand.testPropsBuilder() - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation).withExecutionIsolationThreadTimeoutInMilliseconds(50))) { - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise s) { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - // ignore the interrupted exception - } - } - - }, userScheduler); - } - - @Override - protected HystrixFuture getFallback() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise s) { - results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.originThread.set(Thread.currentThread()); - s.onSuccess(false); - } - - }, userScheduler); - } - - }; - - results.command = command; - - command.toObservable().doOnEach(new Action1>() { - - @Override - public void call(Notification n) { - System.out.println("timeoutWithFallback notification: " + n + " " + Thread.currentThread()); - results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized()); - results.observeOnThread.set(Thread.currentThread()); - } - - }).subscribe(results.ts); - results.ts.awaitTerminalEvent(); - - System.out.println("Fallback => Initialized: " + results.isContextInitialized.get() + " Thread: " + results.originThread.get()); - System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + " Thread: " + results.observeOnThread.get()); - - assertEquals(1, results.ts.getOnNextEvents().size()); - assertEquals(false, results.ts.getOnNextEvents().get(0)); - - assertTrue(command.getExecutionTimeInMilliseconds() > -1); - assertFalse(command.isSuccessfulExecution()); - 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()); - - return results; - } - - private final class RequestContextTestResults { - volatile TestHystrixCommand command; - final AtomicReference originThread = new AtomicReference(); - final AtomicBoolean isContextInitialized = new AtomicBoolean(); - TestSubscriber ts = new TestSubscriber(); - final AtomicBoolean isContextInitializedObserveOn = new AtomicBoolean(); - final AtomicReference observeOnThread = new AtomicReference(); - } - - /* *************************************** testSuccessfuleRequestContext *********************************** */ - - /** - * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this. - */ - @Test - public void testSuccessfulRequestContextWithSemaphoreIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testSuccessfulRequestContextWithSemaphoreIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testSuccessfulRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation] - */ - @Test - public void testSuccessfulRequestContextWithThreadIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.THREAD, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().getName().startsWith("hystrix-OWNER_ONE")); // thread isolated on a HystrixThreadPool - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().getName().startsWith("hystrix-OWNER_ONE")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testSuccessfulRequestContextWithThreadIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.THREAD, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testSuccessfulRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnSuccess(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /* *************************************** testGracefulFailureRequestContext *********************************** */ - - /** - * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this. - */ - @Test - public void testGracefulFailureRequestContextWithSemaphoreIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testGracefulFailureRequestContextWithSemaphoreIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testGracefulFailureRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation] - */ - @Test - public void testGracefulFailureRequestContextWithThreadIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.THREAD, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().getName().startsWith("hystrix-OWNER_ONE")); // thread isolated on a HystrixThreadPool - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().getName().startsWith("hystrix-OWNER_ONE")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testGracefulFailureRequestContextWithThreadIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.THREAD, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testGracefulFailureRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnGracefulFailure(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /* *************************************** testBadFailureRequestContext *********************************** */ - - /** - * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this. - */ - @Test - public void testBadFailureRequestContextWithSemaphoreIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testBadFailureRequestContextWithSemaphoreIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testBadFailureRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation] - */ - @Test - public void testBadFailureRequestContextWithThreadIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.THREAD, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().getName().startsWith("hystrix-OWNER_ONE")); // thread isolated on a HystrixThreadPool - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().getName().startsWith("hystrix-OWNER_ONE")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testBadFailureRequestContextWithThreadIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.THREAD, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testBadFailureRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnBadFailure(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /* *************************************** testFailureWithFallbackRequestContext *********************************** */ - - /** - * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this. - */ - @Test - public void testFailureWithFallbackRequestContextWithSemaphoreIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testFailureWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testFailureWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation] - */ - @Test - public void testFailureWithFallbackRequestContextWithThreadIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().getName().startsWith("hystrix-OWNER_ONE")); // thread isolated on a HystrixThreadPool - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().getName().startsWith("hystrix-OWNER_ONE")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testFailureWithFallbackRequestContextWithThreadIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testFailureWithFallbackRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnFailureWithFallback(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /* *************************************** testRejectionWithFallbackRequestContext *********************************** */ - - /** - * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this. - */ - @Test - public void testRejectionWithFallbackRequestContextWithSemaphoreIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testRejectionWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testRejectionWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation] - */ - @Test - public void testRejectionWithFallbackRequestContextWithThreadIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().equals(Thread.currentThread())); // fallback is performed by the calling thread - - assertTrue(results.isContextInitializedObserveOn.get()); - System.out.println("results.observeOnThread.get(): " + results.observeOnThread.get() + " " + Thread.currentThread()); - assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // rejected so we stay on calling thread - - // thread isolated so even though we're rejected we mark that it attempted execution in a thread - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testRejectionWithFallbackRequestContextWithThreadIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); - - // thread isolated so even though we're rejected we mark that it attempted execution in a thread - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testRejectionWithFallbackRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler for getFallback - - // thread isolated so even though we're rejected we mark that it attempted execution in a thread - assertTrue(results.command.isExecutedInThread()); - } - - /* *************************************** testShortCircuitedWithFallbackRequestContext *********************************** */ - - /** - * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this. - */ - @Test - public void testShortCircuitedWithFallbackRequestContextWithSemaphoreIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // all synchronous - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testShortCircuitedWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testShortCircuitedWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation] - */ - @Test - public void testShortCircuitedWithFallbackRequestContextWithThreadIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().equals(Thread.currentThread())); // fallback is performed by the calling thread - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().equals(Thread.currentThread())); // rejected so we stay on calling thread - - // thread isolated ... but rejected so not executed in a thread - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testShortCircuitedWithFallbackRequestContextWithThreadIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // we capture and set the context once the user provided Observable emits - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler from getFallback - - // thread isolated ... but rejected so not executed in a thread - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testShortCircuitedWithFallbackRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler from getFallback - - // thread isolated ... but rejected so not executed in a thread - assertFalse(results.command.isExecutedInThread()); - } - - /* *************************************** testTimeoutRequestContext *********************************** */ - - /** - * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this. - */ - @Test - public void testTimeoutRequestContextWithSemaphoreIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnTimeout(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().equals(Thread.currentThread())); // all synchronous - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().getName().startsWith("HystrixTimer")); // timeout schedules on HystrixTimer since the original thread was timed out - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testTimeoutRequestContextWithSemaphoreIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnTimeout(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the timeout captures the context so it exists - assertTrue(results.observeOnThread.get().getName().startsWith("HystrixTimer")); // timeout schedules on HystrixTimer since the original thread was timed out - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testTimeoutRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnTimeout(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("HystrixTimer")); // timeout schedules on HystrixTimer since the original thread was timed out - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation] - */ - @Test - public void testTimeoutRequestContextWithThreadIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnTimeout(ExecutionIsolationStrategy.THREAD, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().getName().startsWith("hystrix-OWNER_ONE")); // thread isolated on a HystrixThreadPool - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().getName().startsWith("HystrixTimer")); // timeout schedules on HystrixTimer since the original thread was timed out - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testTimeoutRequestContextWithThreadIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnTimeout(ExecutionIsolationStrategy.THREAD, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the timeout captures the context so it exists - assertTrue(results.observeOnThread.get().getName().startsWith("HystrixTimer")); // timeout schedules on HystrixTimer since the original thread was timed out - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testTimeoutRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnTimeout(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("HystrixTimer")); // timeout schedules on HystrixTimer since the original thread was timed out - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /* *************************************** testTimeoutWithFallbackRequestContext *********************************** */ - - /** - * Synchronous Observable and semaphore isolation. Only [Main] thread is involved in this. - */ - @Test - public void testTimeoutWithFallbackRequestContextWithSemaphoreIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().getName().startsWith("HystrixTimer")); // timeout uses HystrixTimer thread to perform fallback - //(this use case is a little odd as it should generally not be the case that we are "timing out" a synchronous observable on semaphore isolation) - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().getName().startsWith("HystrixTimer")); // timeout uses HystrixTimer thread - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation. User provided thread [RxNewThread] does everything. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testTimeoutWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.SEMAPHORE, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the timeout captures the context so it exists - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testTimeoutWithFallbackRequestContextWithSemaphoreIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.SEMAPHORE, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // semaphore isolated - assertFalse(results.command.isExecutedInThread()); - } - - /** - * Synchronous Observable and thread isolation. Work done on [hystrix-OWNER_ONE] thread and then observed on [RxComputation] - */ - @Test - public void testTimeoutWithFallbackRequestContextWithThreadIsolatedSynchronousObservable() { - RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.immediate()); - - assertTrue(results.isContextInitialized.get()); - assertTrue(results.originThread.get().getName().startsWith("HystrixTimer")); // timeout uses HystrixTimer thread for fallback - - assertTrue(results.isContextInitializedObserveOn.get()); - assertTrue(results.observeOnThread.get().getName().startsWith("HystrixTimer")); // fallback uses the timeout thread - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and thread isolation. User provided thread [RxNetThread] executes Observable and then [RxComputation] observes the onNext calls. - * - * NOTE: RequestContext will NOT exist on that thread. - * - * An async Observable running on its own thread will not have access to the request context unless the user manages the context. - */ - @Test - public void testTimeoutWithFallbackRequestContextWithThreadIsolatedAsynchronousObservable() { - RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.THREAD, Schedulers.newThread()); - - assertFalse(results.isContextInitialized.get()); // it won't have request context as it's on a user provided thread/scheduler - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the timeout captures the context so it exists - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /** - * Async Observable and semaphore isolation WITH functioning RequestContext - * - * Use HystrixContextScheduler to make the user provided scheduler capture context. - */ - @Test - public void testTimeoutWithFallbackRequestContextWithThreadIsolatedAsynchronousObservableAndCapturedContextScheduler() { - RequestContextTestResults results = testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy.THREAD, new HystrixContextScheduler(Schedulers.newThread())); - - assertTrue(results.isContextInitialized.get()); // the user scheduler captures context - assertTrue(results.originThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - assertTrue(results.isContextInitializedObserveOn.get()); // the user scheduler captures context - assertTrue(results.observeOnThread.get().getName().startsWith("RxNewThread")); // the user provided thread/scheduler - - // thread isolated - assertTrue(results.command.isExecutedInThread()); - } - - /* ******************************************************************************** */ - /* ******************************************************************************** */ - /* private HystrixCommand class implementations for unit testing */ - /* ******************************************************************************** */ - /* ******************************************************************************** */ - - /** - * Used by UnitTest command implementations to provide base defaults for constructor and a builder pattern for the arguments being passed in. - */ - /* package */static abstract class TestHystrixCommand extends HystrixAsyncCommand { - - final TestCommandBuilder builder; - - TestHystrixCommand(TestCommandBuilder builder) { - super(builder.owner, builder.dependencyKey, builder.threadPoolKey, builder.circuitBreaker, builder.threadPool, - builder.commandPropertiesDefaults, builder.threadPoolPropertiesDefaults, builder.metrics, - builder.fallbackSemaphore, builder.executionSemaphore, TEST_PROPERTIES_FACTORY, builder.executionHook); - this.builder = builder; - } - - static TestCommandBuilder testPropsBuilder() { - return new TestCommandBuilder(); - } - - static class TestCommandBuilder { - TestCircuitBreaker _cb = new TestCircuitBreaker(); - HystrixCommandGroupKey owner = CommandGroupForUnitTest.OWNER_ONE; - HystrixCommandKey dependencyKey = null; - HystrixThreadPoolKey threadPoolKey = null; - HystrixCircuitBreaker circuitBreaker = _cb; - HystrixThreadPool threadPool = null; - HystrixCommandProperties.Setter commandPropertiesDefaults = HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE); - HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults = HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder(); - HystrixCommandMetrics metrics = _cb.metrics; - TryableSemaphoreActual fallbackSemaphore = null; - TryableSemaphoreActual executionSemaphore = null; - TestExecutionHook executionHook = new TestExecutionHook(); - - TestCommandBuilder setOwner(HystrixCommandGroupKey owner) { - this.owner = owner; - return this; - } - - TestCommandBuilder setCommandKey(HystrixCommandKey dependencyKey) { - this.dependencyKey = dependencyKey; - return this; - } - - TestCommandBuilder setThreadPoolKey(HystrixThreadPoolKey threadPoolKey) { - this.threadPoolKey = threadPoolKey; - return this; - } - - TestCommandBuilder setCircuitBreaker(HystrixCircuitBreaker circuitBreaker) { - this.circuitBreaker = circuitBreaker; - return this; - } - - TestCommandBuilder setThreadPool(HystrixThreadPool threadPool) { - this.threadPool = threadPool; - return this; - } - - TestCommandBuilder setCommandPropertiesDefaults(HystrixCommandProperties.Setter commandPropertiesDefaults) { - this.commandPropertiesDefaults = commandPropertiesDefaults; - return this; - } - - TestCommandBuilder setThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults) { - this.threadPoolPropertiesDefaults = threadPoolPropertiesDefaults; - return this; - } - - TestCommandBuilder setMetrics(HystrixCommandMetrics metrics) { - this.metrics = metrics; - return this; - } - - TestCommandBuilder setFallbackSemaphore(TryableSemaphoreActual fallbackSemaphore) { - this.fallbackSemaphore = fallbackSemaphore; - return this; - } - - TestCommandBuilder setExecutionSemaphore(TryableSemaphoreActual executionSemaphore) { - this.executionSemaphore = executionSemaphore; - return this; - } - - } - - } - - /** - * Successful execution - no fallback implementation. - */ - private static class SuccessfulTestCommand extends TestHystrixCommand { - - public SuccessfulTestCommand() { - this(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)); - } - - public SuccessfulTestCommand(HystrixCommandProperties.Setter properties) { - super(testPropsBuilder().setCommandPropertiesDefaults(properties)); - } - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.just(true, Schedulers.computation()); - } - - } - - /** - * Successful execution - no fallback implementation. - */ - private static class DynamicOwnerTestCommand extends TestHystrixCommand { - - public DynamicOwnerTestCommand(HystrixCommandGroupKey owner) { - super(testPropsBuilder().setOwner(owner)); - } - - @Override - protected HystrixFuture run() { - System.out.println("successfully executed"); - return HystrixFutureUtil.just(true, Schedulers.computation()); - } - - } - - /** - * Successful execution - no fallback implementation. - */ - private static class DynamicOwnerAndKeyTestCommand extends TestHystrixCommand { - - public DynamicOwnerAndKeyTestCommand(HystrixCommandGroupKey owner, HystrixCommandKey key) { - super(testPropsBuilder().setOwner(owner).setCommandKey(key).setCircuitBreaker(null).setMetrics(null)); - // we specifically are NOT passing in a circuit breaker here so we test that it creates a new one correctly based on the dynamic key - } - - @Override - protected HystrixFuture run() { - System.out.println("successfully executed"); - return HystrixFutureUtil.just(true, Schedulers.computation()); - } - - } - - /** - * Failed execution with unknown exception (not HystrixException) - no fallback implementation. - */ - private static class UnknownFailureTestCommandWithoutFallback extends TestHystrixCommand { - - private UnknownFailureTestCommandWithoutFallback() { - super(testPropsBuilder()); - } - - @Override - protected HystrixFuture run() { - // TODO duplicate with error inside async Observable - System.out.println("*** simulated failed execution ***"); - throw new RuntimeException("we failed with an unknown issue"); - } - - } - - /** - * Failed execution with known exception (HystrixException) - no fallback implementation. - */ - private static class KnownFailureTestCommandWithoutFallback extends TestHystrixCommand { - - private KnownFailureTestCommandWithoutFallback(TestCircuitBreaker circuitBreaker) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)); - } - - @Override - protected HystrixFuture run() { - // TODO duplicate with error inside async Observable - System.out.println("*** simulated failed execution ***"); - throw new RuntimeException("we failed with a simulated issue"); - } - - } - - /** - * Failed execution - fallback implementation successfully returns value. - */ - private static class KnownFailureTestCommandWithFallback extends TestHystrixCommand { - - public KnownFailureTestCommandWithFallback(TestCircuitBreaker circuitBreaker) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)); - } - - public KnownFailureTestCommandWithFallback(TestCircuitBreaker circuitBreaker, boolean fallbackEnabled) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withFallbackEnabled(fallbackEnabled).withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE))); - } - - @Override - protected HystrixFuture run() { - // TODO duplicate with error inside async Observable - System.out.println("*** simulated failed execution ***"); - throw new RuntimeException("we failed with a simulated issue"); - } - - @Override - protected HystrixFuture getFallback() { - return HystrixFutureUtil.just(false, Schedulers.computation()); - } - } - - /** - * Failed execution - fallback implementation throws exception. - */ - private static class KnownFailureTestCommandWithFallbackFailure extends TestHystrixCommand { - - private KnownFailureTestCommandWithFallbackFailure() { - super(testPropsBuilder()); - } - - @Override - protected HystrixFuture run() { - System.out.println("*** simulated failed execution ***"); - throw new RuntimeException("we failed with a simulated issue"); - } - - @Override - protected HystrixFuture getFallback() { - // TODO duplicate with error inside async Observable - throw new RuntimeException("failed while getting fallback"); - } - } - - /** - * A Command implementation that supports caching. - */ - private static class SuccessfulCacheableCommand extends TestHystrixCommand { - - private final boolean cacheEnabled; - private volatile boolean executed = false; - private final String value; - - public SuccessfulCacheableCommand(TestCircuitBreaker circuitBreaker, boolean cacheEnabled, String value) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD))); - this.value = value; - this.cacheEnabled = cacheEnabled; - } - - @Override - protected HystrixFuture run() { - executed = true; - System.out.println("successfully executed"); - return HystrixFutureUtil.just(value, Schedulers.computation()); - } - - public boolean isCommandRunningInThread() { - return super.getProperties().executionIsolationStrategy().get().equals(ExecutionIsolationStrategy.THREAD); - } - - @Override - public String getCacheKey() { - if (cacheEnabled) - return value; - else - return null; - } - } - - /** - * A Command implementation that supports caching. - */ - private static class SuccessfulCacheableCommandViaSemaphore extends TestHystrixCommand { - - private final boolean cacheEnabled; - private volatile boolean executed = false; - private final String value; - - public SuccessfulCacheableCommandViaSemaphore(TestCircuitBreaker circuitBreaker, boolean cacheEnabled, String value) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE))); - this.value = value; - this.cacheEnabled = cacheEnabled; - } - - @Override - protected HystrixFuture run() { - executed = true; - System.out.println("successfully executed"); - return HystrixFutureUtil.just(value, Schedulers.computation()); - } - - public boolean isCommandRunningInThread() { - return super.getProperties().executionIsolationStrategy().get().equals(ExecutionIsolationStrategy.THREAD); - } - - @Override - public String getCacheKey() { - if (cacheEnabled) - return value; - else - return null; - } - } - - /** - * A Command implementation that supports caching and execution takes a while. - *

- * Used to test scenario where Futures are returned with a backing call still executing. - */ - private static class SlowCacheableCommand extends TestHystrixCommand { - - private final String value; - private final int duration; - private volatile boolean executed = false; - - public SlowCacheableCommand(TestCircuitBreaker circuitBreaker, String value, int duration) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)); - this.value = value; - this.duration = duration; - } - - @Override - protected HystrixFuture run() { - executed = true; - final Promise p = Promise.create(); - Observable.just(value).delay(duration, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.computation()) - .doOnNext(new Action1() { - - @Override - public void call(String t1) { - System.out.println("successfully executed"); - p.onSuccess(t1); - } - - }).subscribe(); - - return p.createFuture(); - } - - @Override - public String getCacheKey() { - return value; - } - } - - /** - * Successful execution - no fallback implementation, circuit-breaker disabled. - */ - private static class TestCommandWithoutCircuitBreaker extends TestHystrixCommand { - - private TestCommandWithoutCircuitBreaker() { - super(testPropsBuilder().setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withCircuitBreakerEnabled(false))); - } - - @Override - protected HystrixFuture run() { - System.out.println("successfully executed"); - return HystrixFutureUtil.just(true, Schedulers.computation()); - } - - } - - /** - * This should timeout. - */ - private static class TestCommandWithTimeout extends TestHystrixCommand { - - private final long timeout; - - private final static int FALLBACK_NOT_IMPLEMENTED = 1; - private final static int FALLBACK_SUCCESS = 2; - private final static int FALLBACK_FAILURE = 3; - - private final int fallbackBehavior; - - private TestCommandWithTimeout(long timeout, int fallbackBehavior) { - this(timeout, fallbackBehavior, ExecutionIsolationStrategy.SEMAPHORE); - } - - private TestCommandWithTimeout(long timeout, int fallbackBehavior, ExecutionIsolationStrategy isolationStrategy) { - super(testPropsBuilder().setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolationStrategy).withExecutionIsolationThreadTimeoutInMilliseconds((int) timeout))); - this.timeout = timeout; - this.fallbackBehavior = fallbackBehavior; - } - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - System.out.println("***** running"); - try { - Thread.sleep(timeout * 10); - } catch (InterruptedException e) { - e.printStackTrace(); - // ignore and sleep some more to simulate a dependency that doesn't obey interrupts - try { - Thread.sleep(timeout * 2); - } catch (Exception e2) { - // ignore - } - System.out.println("after interruption with extra sleep"); - } - p.onSuccess(true); - } - - }, Schedulers.computation()); - } - - @Override - protected HystrixFuture getFallback() { - if (fallbackBehavior == FALLBACK_SUCCESS) { - return HystrixFutureUtil.just(false); - } else if (fallbackBehavior == FALLBACK_FAILURE) { - // TODO duplicate with error inside async Observable - throw new RuntimeException("failed on fallback"); - } else { - // FALLBACK_NOT_IMPLEMENTED - return super.getFallback(); - } - } - } - - private static class NoRequestCacheTimeoutWithoutFallback extends TestHystrixCommand { - public NoRequestCacheTimeoutWithoutFallback(TestCircuitBreaker circuitBreaker) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withExecutionIsolationThreadTimeoutInMilliseconds(200))); - - // we want it to timeout - } - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - System.out.println(">>>> Sleep Interrupted: " + e.getMessage()); - // e.printStackTrace(); - } - p.onSuccess(true); - } - - }, Schedulers.computation()); - } - - @Override - public String getCacheKey() { - return null; - } - } - - /** - * The run() will take time. No fallback implementation. - */ - private static class TestSemaphoreCommand extends TestHystrixCommand { - - private final long executionSleep; - - private TestSemaphoreCommand(TestCircuitBreaker circuitBreaker, int executionSemaphoreCount, long executionSleep) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter() - .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE) - .withExecutionIsolationSemaphoreMaxConcurrentRequests(executionSemaphoreCount))); - this.executionSleep = executionSleep; - } - - private TestSemaphoreCommand(TestCircuitBreaker circuitBreaker, TryableSemaphoreActual semaphore, long executionSleep) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter() - .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)) - .setExecutionSemaphore(semaphore)); - this.executionSleep = executionSleep; - } - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - try { - Thread.sleep(executionSleep); - } catch (InterruptedException e) { - e.printStackTrace(); - } - p.onSuccess(true); - } - - }, Schedulers.computation()); - } - } - - /** - * The run() will take time. No fallback implementation. - * - * Used for making sure Thread and Semaphore isolation are separated from each other. - */ - private static class TestThreadIsolationWithSemaphoreSetSmallCommand extends TestHystrixCommand { - - private final Action0 action; - - private TestThreadIsolationWithSemaphoreSetSmallCommand(TestCircuitBreaker circuitBreaker, int poolSize, Action0 action) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(TestThreadIsolationWithSemaphoreSetSmallCommand.class.getSimpleName())) - .setThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder() - .withCoreSize(poolSize).withMaxQueueSize(0)) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter() - .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD) - .withExecutionIsolationSemaphoreMaxConcurrentRequests(1))); - this.action = action; - } - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - action.call(); - p.onSuccess(true); - } - - }, Schedulers.computation()); - } - } - - /** - * Semaphore based command that allows caller to use latches to know when it has started and signal when it - * would like the command to finish - */ - private static class LatchedSemaphoreCommand extends TestHystrixCommand { - - private final CountDownLatch startLatch, waitLatch; - - /** - * - * @param circuitBreaker - * @param semaphore - * @param startLatch - * this command calls {@link java.util.concurrent.CountDownLatch#countDown()} immediately - * upon running - * @param waitLatch - * this command calls {@link java.util.concurrent.CountDownLatch#await()} once it starts - * to run. The caller can use the latch to signal the command to finish - */ - private LatchedSemaphoreCommand(TestCircuitBreaker circuitBreaker, TryableSemaphoreActual semaphore, - CountDownLatch startLatch, CountDownLatch waitLatch) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)) - .setExecutionSemaphore(semaphore)); - this.startLatch = startLatch; - this.waitLatch = waitLatch; - } - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - // signals caller that run has started - startLatch.countDown(); - - try { - // waits for caller to countDown latch - waitLatch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - p.onSuccess(false); - return; - } - - p.onSuccess(true); - } - - }, Schedulers.computation()); - } - } - - /** - * The run() will take time. Contains fallback. - */ - private static class TestSemaphoreCommandWithFallback extends TestHystrixCommand { - - private final long executionSleep; - private final HystrixFuture fallback; - - private TestSemaphoreCommandWithFallback(TestCircuitBreaker circuitBreaker, int executionSemaphoreCount, long executionSleep, Boolean fallback) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withExecutionIsolationSemaphoreMaxConcurrentRequests(executionSemaphoreCount))); - this.executionSleep = executionSleep; - this.fallback = HystrixFutureUtil.just(fallback); - } - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - try { - Thread.sleep(executionSleep); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - p.onSuccess(true); - } - - }, Schedulers.computation()); - } - - @Override - protected HystrixFuture getFallback() { - return fallback; - } - - } - - private static class RequestCacheNullPointerExceptionCase extends TestHystrixCommand { - public RequestCacheNullPointerExceptionCase(TestCircuitBreaker circuitBreaker) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withExecutionIsolationThreadTimeoutInMilliseconds(200))); - // we want it to timeout - } - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - p.onSuccess(true); - } - - }, Schedulers.computation()); - } - - @Override - protected HystrixFuture getFallback() { - return HystrixFutureUtil.just(false, Schedulers.computation()); - } - - @Override - public String getCacheKey() { - return "A"; - } - } - - private static class RequestCacheTimeoutWithoutFallback extends TestHystrixCommand { - public RequestCacheTimeoutWithoutFallback(TestCircuitBreaker circuitBreaker) { - super(testPropsBuilder().setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withExecutionIsolationThreadTimeoutInMilliseconds(200))); - // we want it to timeout - } - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.from(new Action1>() { - - @Override - public void call(Promise p) { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - System.out.println(">>>> Sleep Interrupted: " + e.getMessage()); - // e.printStackTrace(); - } - p.onSuccess(true); - } - - }, Schedulers.computation()); - } - - @Override - public String getCacheKey() { - return "A"; - } - } - - private static class RequestCacheThreadRejectionWithoutFallback extends TestHystrixCommand { - - final CountDownLatch completionLatch; - - public RequestCacheThreadRejectionWithoutFallback(TestCircuitBreaker circuitBreaker, CountDownLatch completionLatch) { - super(testPropsBuilder() - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)) - .setCircuitBreaker(circuitBreaker) - .setMetrics(circuitBreaker.metrics) - .setThreadPool(new HystrixThreadPool() { - - @Override - public ThreadPoolExecutor getExecutor() { - return null; - } - - @Override - public void markThreadExecution() { - - } - - @Override - public void markThreadCompletion() { - - } - - @Override - public boolean isQueueSpaceAvailable() { - // always return false so we reject everything - return false; - } - - @Override - public Scheduler getScheduler() { - return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this); - } - - })); - this.completionLatch = completionLatch; - } - - @Override - protected HystrixFuture run() { - try { - if (completionLatch.await(1000, TimeUnit.MILLISECONDS)) { - throw new RuntimeException("timed out waiting on completionLatch"); - } - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - return HystrixFutureUtil.just(true); - } - - @Override - public String getCacheKey() { - return "A"; - } - } - - private static class BadRequestCommand extends TestHystrixCommand { - - public BadRequestCommand(TestCircuitBreaker circuitBreaker, ExecutionIsolationStrategy isolationType) { - super(testPropsBuilder() - .setCircuitBreaker(circuitBreaker) - .setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE).withExecutionIsolationStrategy(isolationType))); - } - - @Override - protected HystrixFuture run() { - throw new HystrixBadRequestException("Message to developer that they passed in bad data or something like that."); - } - - @Override - protected HystrixFuture getFallback() { - return HystrixFutureUtil.just(false, Schedulers.computation()); - } - - @Override - protected String getCacheKey() { - return "one"; - } - - } - - private static class CommandWithErrorThrown extends TestHystrixCommand { - - public CommandWithErrorThrown(TestCircuitBreaker circuitBreaker) { - super(testPropsBuilder() - .setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)); - } - - @Override - protected HystrixFuture run() { - // TODO duplicate with error inside async Observable - throw new Error("simulated java.lang.Error message"); - } - - } - - private static class CommandWithCheckedException extends TestHystrixCommand { - - public CommandWithCheckedException(TestCircuitBreaker circuitBreaker) { - super(testPropsBuilder() - .setCircuitBreaker(circuitBreaker).setMetrics(circuitBreaker.metrics)); - } - - @Override - protected HystrixFuture run() { - return HystrixFutureUtil.error(new IOException("simulated checked exception message")); - } - - } - - enum CommandKeyForUnitTest implements HystrixCommandKey { - KEY_ONE, KEY_TWO; - } - - enum CommandGroupForUnitTest implements HystrixCommandGroupKey { - OWNER_ONE, OWNER_TWO; - } - - enum ThreadPoolKeyForUnitTest implements HystrixThreadPoolKey { - THREAD_POOL_ONE, THREAD_POOL_TWO; - } - - private static HystrixPropertiesStrategy TEST_PROPERTIES_FACTORY = new TestPropertiesFactory(); - - private static class TestPropertiesFactory extends HystrixPropertiesStrategy { - - @Override - public HystrixCommandProperties getCommandProperties(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) { - if (builder == null) { - builder = HystrixCommandPropertiesTest.getUnitTestPropertiesSetter(); - } - return HystrixCommandPropertiesTest.asMock(builder); - } - - @Override - public HystrixThreadPoolProperties getThreadPoolProperties(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter builder) { - if (builder == null) { - builder = HystrixThreadPoolProperties.Setter.getUnitTestPropertiesBuilder(); - } - return HystrixThreadPoolProperties.Setter.asMock(builder); - } - - @Override - public HystrixCollapserProperties getCollapserProperties(HystrixCollapserKey collapserKey, HystrixCollapserProperties.Setter builder) { - throw new IllegalStateException("not expecting collapser properties"); - } - - @Override - public String getCommandPropertiesCacheKey(HystrixCommandKey commandKey, HystrixCommandProperties.Setter builder) { - return null; - } - - @Override - public String getThreadPoolPropertiesCacheKey(HystrixThreadPoolKey threadPoolKey, com.netflix.hystrix.HystrixThreadPoolProperties.Setter builder) { - return null; - } - - @Override - public String getCollapserPropertiesCacheKey(HystrixCollapserKey collapserKey, com.netflix.hystrix.HystrixCollapserProperties.Setter builder) { - return null; - } - - } - - private static class TestExecutionHook extends HystrixCommandExecutionHook { - - AtomicInteger startExecute = new AtomicInteger(); - - @Override - public void onStart(HystrixInvokable commandInstance) { - super.onStart(commandInstance); - startExecute.incrementAndGet(); - } - - Object endExecuteSuccessResponse = null; - - @Override - public T onComplete(HystrixInvokable commandInstance, T response) { - endExecuteSuccessResponse = response; - return super.onComplete(commandInstance, response); - } - - Exception endExecuteFailureException = null; - FailureType endExecuteFailureType = null; - - @Override - public Exception onError(HystrixInvokable commandInstance, FailureType failureType, Exception e) { - endExecuteFailureException = e; - endExecuteFailureType = failureType; - return super.onError(commandInstance, failureType, e); - } - - AtomicInteger startRun = new AtomicInteger(); - - @Override - public void onRunStart(HystrixInvokable commandInstance) { - super.onRunStart(commandInstance); - startRun.incrementAndGet(); - } - - Object runSuccessResponse = null; - - @Override - public T onRunSuccess(HystrixInvokable commandInstance, T response) { - runSuccessResponse = response; - return super.onRunSuccess(commandInstance, response); - } - - Exception runFailureException = null; - - @Override - public Exception onRunError(HystrixInvokable commandInstance, Exception e) { - runFailureException = e; - return super.onRunError(commandInstance, e); - } - - AtomicInteger startFallback = new AtomicInteger(); - - @Override - public void onFallbackStart(HystrixInvokable commandInstance) { - super.onFallbackStart(commandInstance); - startFallback.incrementAndGet(); - } - - Object fallbackSuccessResponse = null; - - @Override - public T onFallbackSuccess(HystrixInvokable commandInstance, T response) { - fallbackSuccessResponse = response; - return super.onFallbackSuccess(commandInstance, response); - } - - Exception fallbackFailureException = null; - - @Override - public Exception onFallbackError(HystrixInvokable commandInstance, Exception e) { - fallbackFailureException = e; - return super.onFallbackError(commandInstance, e); - } - - AtomicInteger threadStart = new AtomicInteger(); - - @Override - public void onThreadStart(HystrixInvokable commandInstance) { - super.onThreadStart(commandInstance); - threadStart.incrementAndGet(); - } - - AtomicInteger threadComplete = new AtomicInteger(); - - @Override - public void onThreadComplete(HystrixInvokable commandInstance) { - super.onThreadComplete(commandInstance); - threadComplete.incrementAndGet(); - } - - } - -} diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCircuitBreakerTest.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCircuitBreakerTest.java index 3ee9783e1..64ff4610d 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCircuitBreakerTest.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCircuitBreakerTest.java @@ -585,8 +585,8 @@ public T onComplete(final HystrixInvokable command, final T response) { private void logHC(HystrixInvokable command, T response) { - if(command instanceof HystrixExecutableInfo) { - HystrixExecutableInfo commandInfo = (HystrixExecutableInfo)command; + if(command instanceof HystrixInvokableInfo) { + HystrixInvokableInfo commandInfo = (HystrixInvokableInfo)command; HystrixCommandMetrics metrics = commandInfo.getMetrics(); System.out.println("cb/error-count/%/total: " + commandInfo.isCircuitBreakerOpen() + " " diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCollapserTest.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCollapserTest.java index a00e4e671..b0d9e5f51 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCollapserTest.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCollapserTest.java @@ -448,7 +448,7 @@ public void testRequestCache1() { assertEquals(1, counter.get()); assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - HystrixExecutableInfo command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixExecutableInfo[1])[0]; + HystrixInvokableInfo command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo[1])[0]; System.out.println("command.getExecutionEvents(): " + command.getExecutionEvents()); assertEquals(2, command.getExecutionEvents().size()); assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS)); @@ -500,7 +500,7 @@ public void testRequestCache2() { assertEquals(1, counter.get()); assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - HystrixExecutableInfo command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixExecutableInfo[1])[0]; + HystrixInvokableInfo command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo[1])[0]; assertEquals(2, command.getExecutionEvents().size()); assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS)); assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED)); @@ -556,7 +556,7 @@ public void testRequestCache3() { assertEquals(1, counter.get()); assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - HystrixExecutableInfo command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixExecutableInfo[1])[0]; + HystrixInvokableInfo command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo[1])[0]; assertEquals(2, command.getExecutionEvents().size()); assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS)); assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED)); @@ -613,13 +613,13 @@ public void testNoRequestCache3() { assertEquals(2, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); // we expect to see it with SUCCESS and COLLAPSED and both - HystrixExecutableInfo commandA = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixExecutableInfo[2])[0]; + HystrixInvokableInfo commandA = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo[2])[0]; assertEquals(2, commandA.getExecutionEvents().size()); assertTrue(commandA.getExecutionEvents().contains(HystrixEventType.SUCCESS)); assertTrue(commandA.getExecutionEvents().contains(HystrixEventType.COLLAPSED)); // we expect to see it with SUCCESS and COLLAPSED and both - HystrixExecutableInfo commandB = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixExecutableInfo[2])[1]; + HystrixInvokableInfo commandB = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo[2])[1]; assertEquals(2, commandB.getExecutionEvents().size()); assertTrue(commandB.getExecutionEvents().contains(HystrixEventType.SUCCESS)); assertTrue(commandB.getExecutionEvents().contains(HystrixEventType.COLLAPSED)); @@ -682,7 +682,7 @@ public void testRequestCacheWithException() { assertEquals(1, commands.size()); assertEquals(1, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - HystrixExecutableInfo command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixExecutableInfo[1])[0]; + HystrixInvokableInfo command = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo[1])[0]; assertEquals(2, command.getExecutionEvents().size()); assertTrue(command.getExecutionEvents().contains(HystrixEventType.FAILURE)); assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED)); 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 2dbf0a28a..3d67997e9 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTest.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTest.java @@ -2838,7 +2838,7 @@ public void testRequestCacheOnTimeoutCausesNullPointerException() throws Excepti assertEquals(5, HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size()); - HystrixExecutableInfo[] executeCommands = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixExecutableInfo[] {}); + HystrixInvokableInfo[] executeCommands = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().toArray(new HystrixInvokableInfo[] {}); System.out.println(":executeCommands[0].getExecutionEvents()" + executeCommands[0].getExecutionEvents()); assertEquals(2, executeCommands[0].getExecutionEvents().size()); diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTimeoutConcurrencyTesting.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTimeoutConcurrencyTesting.java index cb3ba7401..e3d7730d4 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTimeoutConcurrencyTesting.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCommandTimeoutConcurrencyTesting.java @@ -19,7 +19,7 @@ public void testTimeoutRace() { throw new RuntimeException("Received NULL"); } - for (HystrixExecutableInfo hi : HystrixRequestLog.getCurrentRequest().getAllExecutedCommands()) { + for (HystrixInvokableInfo hi : HystrixRequestLog.getCurrentRequest().getAllExecutedCommands()) { if (hi.isResponseTimedOut() && hi.getExecutionEvents().size() == 1) { System.err.println("Missing fallback status!"); throw new RuntimeException("Missing fallback status on timeout."); diff --git a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixFutureUtil.java b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixFutureUtil.java deleted file mode 100644 index 281b6a6ff..000000000 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixFutureUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.netflix.hystrix; - -import rx.Scheduler; -import rx.Scheduler.Worker; -import rx.functions.Action0; -import rx.functions.Action1; - -import com.netflix.hystrix.HystrixAsyncCommand.HystrixFuture; -import com.netflix.hystrix.HystrixAsyncCommand.Promise; - -public class HystrixFutureUtil { - - public static HystrixFuture just(T t) { - Promise p = Promise.create(); - p.onSuccess(t); - return HystrixFuture.create(p); - } - - public static HystrixFuture error(Throwable t) { - Promise p = Promise.create(); - p.onError(t); - return HystrixFuture.create(p); - } - - public static HystrixFuture just(final T t, Scheduler s) { - return from(new Action1>() { - - @Override - public void call(Promise p) { - p.onSuccess(t); - } - }, s); - } - - public static HystrixFuture from(final Action1> action, Scheduler s) { - final Promise p = Promise.create(); - final Worker worker = s.createWorker(); - worker.schedule(new Action0() { - - @Override - public void call() { - try { - action.call(p); - } catch (Exception e) { - p.onError(e); - } finally { - worker.unsubscribe(); - } - } - - }); - return HystrixFuture.create(p, new Action0() { - - @Override - public void call() { - worker.unsubscribe(); - } - - }); - } -} 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 0551bc69d..e4a4be2ae 100644 --- a/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java +++ b/hystrix-core/src/test/java/com/netflix/hystrix/HystrixObservableCommandTest.java @@ -4186,7 +4186,7 @@ public void call(Subscriber t1) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { if (isResponseTimedOut()) { return Observable.just("timed-out"); } else { @@ -4233,7 +4233,7 @@ public void call(Subscriber t1) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { if (isResponseTimedOut()) { return Observable.just("timed-out"); } else { @@ -4278,7 +4278,7 @@ public void call(Subscriber t1) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { if (isResponseTimedOut()) { return Observable.just("timed-out"); } else { @@ -4800,7 +4800,7 @@ public void call(Subscriber s) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { return Observable.create(new OnSubscribe() { @Override @@ -4908,7 +4908,7 @@ public void call(Subscriber s) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { return Observable.create(new OnSubscribe() { @Override @@ -4993,7 +4993,7 @@ public void call(Subscriber s) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { return Observable.create(new OnSubscribe() { @Override @@ -5140,7 +5140,7 @@ public void call(Subscriber s) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { return Observable.create(new OnSubscribe() { @Override @@ -6491,7 +6491,7 @@ protected Observable construct() { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { return Observable.just(1, 2, 3, 4); } @@ -6525,7 +6525,7 @@ public void call(Integer t1) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { if (lastSeen < 4) { return Observable.range(lastSeen + 1, 4 - lastSeen); } else { @@ -6628,7 +6628,7 @@ protected Observable construct() { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { return Observable.just(false).subscribeOn(Schedulers.computation()); } } @@ -6649,7 +6649,7 @@ protected Observable construct() { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { // TODO duplicate with error inside async Observable throw new RuntimeException("failed while getting fallback"); } @@ -6831,7 +6831,7 @@ public void call(Subscriber sub) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { if (fallbackBehavior == FALLBACK_SUCCESS) { return Observable.just(false); } else if (fallbackBehavior == FALLBACK_FAILURE) { @@ -6839,7 +6839,7 @@ protected Observable onFailureResumeWithFallback() { throw new RuntimeException("failed on fallback"); } else { // FALLBACK_NOT_IMPLEMENTED - return super.onFailureResumeWithFallback(); + return super.resumeWithFallback(); } } } @@ -7044,7 +7044,7 @@ public void call(Subscriber s) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { return fallback; } @@ -7077,7 +7077,7 @@ public void call(Subscriber s) { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { return Observable.just(false).subscribeOn(Schedulers.computation()); } @@ -7193,7 +7193,7 @@ protected Observable construct() { } @Override - protected Observable onFailureResumeWithFallback() { + protected Observable resumeWithFallback() { return Observable.just(false).subscribeOn(Schedulers.computation()); }