/**
* Copyright 2015 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.strategy.concurrency;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.lang.IllegalStateException;
import java.util.concurrent.atomic.AtomicBoolean;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import rx.functions.Action1;
import rx.functions.Func1;
import com.netflix.config.ConfigurationManager;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixRequestLog;
public class HystrixConcurrencyStrategyTest {
@Before
public void prepareForTest() {
/* we must call this to simulate a new request lifecycle running and clearing caches */
HystrixRequestContext.initializeContext();
}
@After
public void cleanup() {
shutdownContextIfExists();
// force properties to be clean as well
ConfigurationManager.getConfigInstance().clear();
}
/**
* If the RequestContext does not get transferred across threads correctly this blows up.
* No specific assertions are necessary.
*/
@Test
public void testRequestContextPropagatesAcrossObserveOnPool() {
new SimpleCommand().execute();
new SimpleCommand().observe().map(new Func1<String, String>() {
@Override
public String call(String s) {
System.out.println("Map => Commands: " + HystrixRequestLog.getCurrentRequest().getAllExecutedCommands());
return s;
}
}).toBlocking().forEach(new Action1<String>() {
@Override
public void call(String s) {
System.out.println("Result [" + s + "] => Commands: " + HystrixRequestLog.getCurrentRequest().getAllExecutedCommands());
}
});
}
private static class SimpleCommand extends HystrixCommand<String> {
public SimpleCommand() {
super(HystrixCommandGroupKey.Factory.asKey("SimpleCommand"));
}
@Override
protected String run() throws Exception {
if (HystrixRequestContext.isCurrentThreadInitialized()) {
System.out.println("Executing => Commands: " + HystrixRequestLog.getCurrentRequest().getAllExecutedCommands());
}
return "Hello";
}
}
@Test
public void testThreadContextOnTimeout() {
final AtomicBoolean isInitialized = new AtomicBoolean();
new TimeoutCommand().toObservable()
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
isInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());
}
})
.materialize()
.toBlocking().single();
System.out.println("initialized = " + HystrixRequestContext.isCurrentThreadInitialized());
System.out.println("initialized inside onError = " + isInitialized.get());
assertEquals(true, isInitialized.get());
}
@Test
public void testNoRequestContextOnSimpleConcurencyStrategyWithoutException() throws Exception {
shutdownContextIfExists();
ConfigurationManager.getConfigInstance().setProperty("hystrix.command.default.requestLog.enabled", "false");
new SimpleCommand().execute();
assertTrue("We are able to run the simple command without a context initialization error.", true);
}
private void shutdownContextIfExists() {
// 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();
}
}
private static class DummyHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {}
public static class TimeoutCommand extends HystrixCommand<Void> {
static final HystrixCommand.Setter properties = HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("TimeoutTest"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(50));
public TimeoutCommand() {
super(properties);
}
@Override
protected Void run() throws Exception {
Thread.sleep(500);
return null;
}
}
}