use of com.nike.riposte.server.handler.base.BaseInboundHandlerWithTracingAndMdcSupport.HandlerMethodToExecute in project riposte by Nike-Inc.
the class BaseInboundHandlerWithTracingAndMdcSupportTest method verifyMethodBehaviorDetails.
private void verifyMethodBehaviorDetails(String methodName, Object[] methodArgs, PipelineContinuationBehavior doMethodReturnValue, boolean shouldPerformDebugLogging, boolean forceEnableDTraceOnAllMethods, boolean isDefaultMethodImpl, boolean argsEligibleForLinkUnlink, boolean shouldExplodeInDoMethod) throws InvocationTargetException, IllegalAccessException {
// Setup all the things!
BaseInboundHandlerWithTracingAndMdcSupport handlerSpy = spy(handler);
Method mainMethod = findMethodWithName(BaseInboundHandlerWithTracingAndMdcSupport.class, methodName);
String methodNameWithFirstCharCapitalized = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
String doMethodName = "do" + methodNameWithFirstCharCapitalized;
Method doMethod = findMethodWithName(BaseInboundHandlerWithTracingAndMdcSupport.class, doMethodName);
String fireEventMethodName = "fire" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
Method fireEventMethod = ("handlerAdded".equals(methodName) || "handlerRemoved".equals(methodName)) ? null : findMethodWithName(ChannelHandlerContext.class, fireEventMethodName);
Whitebox.setInternalState(handlerSpy, "debugHandlerMethodCalls", shouldPerformDebugLogging);
Whitebox.setInternalState(handlerSpy, "forceEnableDTraceOnAllMethods", forceEnableDTraceOnAllMethods);
Whitebox.setInternalState(handlerSpy, "isDefaultDo" + methodNameWithFirstCharCapitalized + "Impl", isDefaultMethodImpl);
HandlerMethodToExecute expectedHandlerMethodToExecute = constructHandlerMethodToExecuteFromMethodName(methodName);
doReturn(argsEligibleForLinkUnlink).when(handlerSpy).argsAreEligibleForLinkingAndUnlinkingDistributedTracingInfo(eq(expectedHandlerMethodToExecute), eq(ctxMock), anyObject(), any(Throwable.class));
TestLogger handlerLogger = TestLoggerFactory.getTestLogger(((Logger) Whitebox.getInternalState(handlerSpy, "logger")).getName());
handlerLogger.clear();
ObjectHolder<Boolean> calledLinkMethod = new ObjectHolder<>(false);
ObjectHolder<Boolean> calledDoMethod = new ObjectHolder<>(false);
ObjectHolder<Boolean> calledUnlinkMethod = new ObjectHolder<>(false);
ObjectHolder<Boolean> calledSuperMethod = new ObjectHolder<>(false);
@SuppressWarnings("unchecked") Pair<Deque<Span>, Map<String, String>> linkTracingAndMdcReturnVal = mock(Pair.class);
boolean shouldCallLinkAndUnlinkMethods = (!isDefaultMethodImpl && argsEligibleForLinkUnlink) || forceEnableDTraceOnAllMethods || shouldPerformDebugLogging;
// Configure the linkTracingAndMdcToCurrentThread method to:
// 1. Indicate that the link method was called (for future assertions).
// 2. Assert that the do* method has not yet been called.
// 3. Assert that the unlink method has not yet been called.
// 4. Assert that the super method has not yet been called.
// 5. Return linkTracingAndMdcReturnVal (for future assertions).
doAnswer(invocation -> {
calledLinkMethod.heldObject = true;
assertThat(calledDoMethod.heldObject, is(false));
assertThat(calledUnlinkMethod.heldObject, is(false));
assertThat(calledSuperMethod.heldObject, is(false));
return linkTracingAndMdcReturnVal;
}).when(handlerSpy).linkTracingAndMdcToCurrentThread(ctxMock);
// Configure the do* method depending on whether it's supposed to explode with a IntentionalDoMethodException or not.
if (shouldExplodeInDoMethod) {
// The do* method is supposed to explode. Make it so.
when(doMethod.invoke(handlerSpy, methodArgs)).thenThrow(new IntentionalDoMethodException("intentional exception"));
} else {
// The do* method is not supposed to explode. Configure it to:
// 1. Indicate that the do* method was called (for future assertions).
// 2. Assert that the link method was called previously if and only if shouldCallLinkAndUnlinkMethods is true.
// 3. Assert that the unlink method has not yet been called.
// 4. Assert that the super method has not yet been called.
// 5. Return doMethodReturnValue (for future assertions).
when(doMethod.invoke(handlerSpy, methodArgs)).thenAnswer(invocation -> {
calledDoMethod.heldObject = true;
assertThat(calledLinkMethod.heldObject, is(shouldCallLinkAndUnlinkMethods));
assertThat(calledUnlinkMethod.heldObject, is(false));
assertThat(calledSuperMethod.heldObject, is(false));
return doMethodReturnValue;
});
}
// Configure the unlinkTracingAndMdcFromCurrentThread method to:
// 1. Indicate that the unlink method was called (for future assertions).
// 2. Assert that the link method was called previously if and only if shouldCallLinkAndUnlinkMethods is true.
// 3. Assert that the do* method was called (if it was setup to *not* explode).
// 4. Assert that the super method has not yet been called.
// 5. Assert that the tracing info arg passed in was the same data that was returned by the link method.
doAnswer(invocation -> {
calledUnlinkMethod.heldObject = true;
assertThat(calledLinkMethod.heldObject, is(shouldCallLinkAndUnlinkMethods));
if (shouldExplodeInDoMethod)
assertThat(calledDoMethod.heldObject, is(false));
else
assertThat(calledDoMethod.heldObject, is(true));
assertThat(calledSuperMethod.heldObject, is(false));
assertThat(invocation.getArguments()[1], is(linkTracingAndMdcReturnVal));
return null;
}).when(handlerSpy).unlinkTracingAndMdcFromCurrentThread(ctxMock, linkTracingAndMdcReturnVal);
// we can use that as a proxy to verify that the super method was called.
if (fireEventMethod != null) {
Object[] fireEventArgs = new Object[fireEventMethod.getParameterCount()];
// Configure the ctxMock's fire* method to:
// 1. Indicate that the super method was called (for future assertions).
// 2. Assert that the link method was called previously if and only if shouldCallLinkAndUnlinkMethods is true.
// 3. Assert that the do* method was called previously.
// 4. Assert that the unlink method was called previously if and only if shouldCallLinkAndUnlinkMethods is true.
when(fireEventMethod.invoke(ctxMock, fireEventArgs)).thenAnswer(invocation -> {
calledSuperMethod.heldObject = true;
assertThat(calledLinkMethod.heldObject, is(shouldCallLinkAndUnlinkMethods));
assertThat(calledDoMethod.heldObject, is(true));
assertThat(calledUnlinkMethod.heldObject, is(shouldCallLinkAndUnlinkMethods));
return ctxMock;
});
}
try {
// Execute the method in question.
mainMethod.invoke(handlerSpy, methodArgs);
} catch (InvocationTargetException ex) {
// An exception occurred during method execution.
if (ex.getCause() instanceof AssertionError) {
// on how to interpret what went wrong.
throw new RuntimeException("An AssertionError was experienced while running the method-to-be-tested. This either means a bug in " + "BaseInboundHandlerWithTracingAndMdcSupport for the method in question, or this unit test is " + "out-of-date and needs to be fixed. See the AssertionError cause for the true cause of the error.", ex.getCause());
}
// Not an AssertionError, so this should be the expected IntentionalDoMethodException.
assertThat(ex.getCause(), instanceOf(IntentionalDoMethodException.class));
// Make sure we were supposed to throw a IntentionalDoMethodException.
assertThat(shouldExplodeInDoMethod, is(true));
// The do* method was called, so mark it that way (for future assertions).
calledDoMethod.heldObject = true;
}
assertThat(calledLinkMethod.heldObject, is(shouldCallLinkAndUnlinkMethods));
// The do* method should always be called no matter what.
assertThat(calledDoMethod.heldObject, is(true));
assertThat(calledUnlinkMethod.heldObject, is(shouldCallLinkAndUnlinkMethods));
if (fireEventMethod != null) {
boolean shouldHaveCalledSuperMethod = !shouldExplodeInDoMethod && (doMethodReturnValue == null || PipelineContinuationBehavior.CONTINUE.equals(doMethodReturnValue));
assertThat(calledSuperMethod.heldObject, is(shouldHaveCalledSuperMethod));
}
if (shouldPerformDebugLogging) {
List<LoggingEvent> loggingEvents = handlerLogger.getLoggingEvents();
assertThat(loggingEvents.size(), is(1));
assertThat(loggingEvents.get(0).getMessage(), containsString(" " + methodName + " for "));
}
boolean argsEligibleMethodShouldHaveBeenCalled = !isDefaultMethodImpl;
int numExpectedArgsEligibleMethodCalls = (argsEligibleMethodShouldHaveBeenCalled) ? 1 : 0;
verify(handlerSpy, times(numExpectedArgsEligibleMethodCalls)).argsAreEligibleForLinkingAndUnlinkingDistributedTracingInfo(eq(expectedHandlerMethodToExecute), eq(ctxMock), anyObject(), any(Throwable.class));
}
Aggregations