package com.navercorp.pinpoint.plugin.hystrix;
import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations;
import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace;
import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier;
import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder;
import com.navercorp.pinpoint.plugin.hystrix.commands.SayHelloCommand;
import com.navercorp.pinpoint.plugin.hystrix.commands.ThrowExceptionCommand;
import com.navercorp.pinpoint.plugin.hystrix.commands.ThrowExceptionCommandWithFallback;
import com.navercorp.pinpoint.test.plugin.Dependency;
import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite;
import com.netflix.hystrix.HystrixCommand;
import org.junit.Test;
import org.junit.runner.RunWith;
import rx.Subscriber;
import java.lang.reflect.Method;
import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.annotation;
/**
* Integration test for hystrix-core 1.4.3 - 1.5.2 traces the following :
* <p>
* <tt>HystrixCommand.queue()</tt><br/>
* <tt>HystrixCommand$1.call(Subscriber<? super R>)</tt> - Anonymous inner class that invokes run()<br/>
* <tt>HystrixCommand$2.call(Subscriber<? super R>)</tt> - Anonymous inner class that invokes getFallback()<br/>
* <p>
* The cause of fallback is not traced as AbstractCommand.getExecutionException() method is missing.
* <p>
* Created by jack on 4/22/16.
*
* @author Jiaqi Feng
* @author HyunGil Jeong
*/
@RunWith(PinpointPluginTestSuite.class)
@Dependency({"com.netflix.hystrix:hystrix-core:[1.4.3,1.5.2]","com.netflix.hystrix:hystrix-metrics-event-stream:1.1.2"})
public class HystrixCommand_1_4_3_to_1_5_2_IT extends HystrixCommandITBase {
private static final String EXECUTION_OBSERVABLE_INNER_CLASS = "com.netflix.hystrix.HystrixCommand$1";
private static final String FALLBACK_OBSERVABLE_INNER_CLASS = "com.netflix.hystrix.HystrixCommand$2";
@Test
public void testSyncCall() throws Exception {
String name = "Pinpoint";
executeSayHelloCommand(name);
PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
verifier.printCache();
Method queue = HystrixCommand.class.getMethod("queue");
Class<?> executionObservableClazz = Class.forName(EXECUTION_OBSERVABLE_INNER_CLASS);
Method executioObservableCallCmd = executionObservableClazz.getDeclaredMethod("call", Subscriber.class);
verifier.verifyTrace(Expectations.async(
Expectations.event("HYSTRIX_COMMAND", queue, annotation("hystrix.command", SayHelloCommand.class.getSimpleName())),
Expectations.event("ASYNC", "Asynchronous Invocation"),
Expectations.event("HYSTRIX_COMMAND_INTERNAL", executioObservableCallCmd,
annotation("hystrix.command.execution", "run"))
));
// no more traces
verifier.verifyTraceCount(0);
}
@Test
public void testAsyncCall() throws Exception {
String name = "Pinpoint";
queueAndGetSayHelloCommand(name);
PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
verifier.printCache();
Method queue = HystrixCommand.class.getMethod("queue");
Class<?> executionObservableClazz = Class.forName(EXECUTION_OBSERVABLE_INNER_CLASS);
Method executionObservableCallCmd = executionObservableClazz.getDeclaredMethod("call", Subscriber.class);
verifier.verifyTrace(Expectations.async(
Expectations.event("HYSTRIX_COMMAND", queue, annotation("hystrix.command", SayHelloCommand.class.getSimpleName())),
Expectations.event("ASYNC", "Asynchronous Invocation"),
Expectations.event("HYSTRIX_COMMAND_INTERNAL", executionObservableCallCmd,
annotation("hystrix.command.execution", "run"))
));
// no more traces
verifier.verifyTraceCount(0);
}
@Test
public void testExecutionException() throws Exception {
Exception expectedException = new RuntimeException("expected");
executeThrowExceptionCommand(expectedException);
PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
verifier.printCache();
Method queue = HystrixCommand.class.getMethod("queue");
Class<?> executionObservableClazz = Class.forName(EXECUTION_OBSERVABLE_INNER_CLASS);
Method executionObservableCallCmd = executionObservableClazz.getDeclaredMethod("call", Subscriber.class);
Class<?> fallbackObservableClazz = Class.forName(FALLBACK_OBSERVABLE_INNER_CLASS);
Method fallbackObservableCallCmd = fallbackObservableClazz.getDeclaredMethod("call", Subscriber.class);
ExpectedTrace expectedFallbackTrace;
try {
// We record the cause of the fallback by invoking AbstractCommand.getExecutionException() added in 1.4.22
HystrixCommand.class.getMethod("getExecutionException");
expectedFallbackTrace = Expectations.event("HYSTRIX_COMMAND_INTERNAL", fallbackObservableCallCmd,
annotation("hystrix.command.execution", "fallback"),
annotation("hystrix.command.fallback.cause", expectedException.toString()));
} catch (NoSuchMethodException e) {
// pre 1.4.22
expectedFallbackTrace = Expectations.event("HYSTRIX_COMMAND_INTERNAL", fallbackObservableCallCmd,
annotation("hystrix.command.execution", "fallback"));
}
verifier.verifyTrace(Expectations.async(
Expectations.event("HYSTRIX_COMMAND", queue, annotation("hystrix.command", ThrowExceptionCommand.class.getSimpleName())),
Expectations.event("ASYNC", "Asynchronous Invocation"),
Expectations.event("HYSTRIX_COMMAND_INTERNAL", executionObservableCallCmd,
annotation("hystrix.command.execution", "run")),
expectedFallbackTrace
));
// no more traces
verifier.verifyTraceCount(0);
}
@Test
public void testExecutionExceptionWithFallback() throws Exception {
Exception expectedException = new RuntimeException("expected");
String fallbackMessage = "Fallback";
executeThrowExceptionWithFallbackCommand(expectedException, fallbackMessage);
PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
verifier.printCache();
Method queue = HystrixCommand.class.getMethod("queue");
Class<?> executionObservableClazz = Class.forName(EXECUTION_OBSERVABLE_INNER_CLASS);
Method executionObservableCallCmd = executionObservableClazz.getDeclaredMethod("call", Subscriber.class);
Class<?> fallbackObservableClazz = Class.forName(FALLBACK_OBSERVABLE_INNER_CLASS);
Method fallbackObservableCallCmd = fallbackObservableClazz.getDeclaredMethod("call", Subscriber.class);
ExpectedTrace expectedFallbackTrace;
try {
// We record the cause of the fallback by invoking AbstractCommand.getExecutionException() added in 1.4.22
HystrixCommand.class.getMethod("getExecutionException");
expectedFallbackTrace = Expectations.event("HYSTRIX_COMMAND_INTERNAL", fallbackObservableCallCmd,
annotation("hystrix.command.execution", "fallback"),
annotation("hystrix.command.fallback.cause", expectedException.toString()));
} catch (NoSuchMethodException e) {
// pre 1.4.22
expectedFallbackTrace = Expectations.event("HYSTRIX_COMMAND_INTERNAL", fallbackObservableCallCmd,
annotation("hystrix.command.execution", "fallback"));
}
verifier.verifyTrace(Expectations.async(
Expectations.event("HYSTRIX_COMMAND", queue, annotation("hystrix.command", ThrowExceptionCommandWithFallback.class.getSimpleName())),
Expectations.event("ASYNC", "Asynchronous Invocation"),
Expectations.event("HYSTRIX_COMMAND_INTERNAL", executionObservableCallCmd,
annotation("hystrix.command.execution", "run")),
expectedFallbackTrace
));
// no more traces
verifier.verifyTraceCount(0);
}
@Test
public void testTraceContinuation() throws Exception {
String name = "Pinpoint";
executeInvokeSayHelloCommand(name);
PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
verifier.printCache();
// If the trace is propagated properly to a HystrixCommand's run() method, there should be 6 total traces.
// 3 for InvokeSayHelloCommand, 3 for SayHelloCommand.
verifier.verifyTraceCount(6);
}
}