package rocks.inspectit.server.instrumentation.config.applier; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import org.mockito.ArgumentCaptor; import org.mockito.Matchers; import org.mockito.Mock; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import rocks.inspectit.server.instrumentation.config.filter.AssignmentFilterProvider; import rocks.inspectit.server.instrumentation.config.filter.ClassSensorAssignmentFilter; import rocks.inspectit.shared.all.instrumentation.classcache.ClassType; import rocks.inspectit.shared.all.instrumentation.classcache.MethodType; import rocks.inspectit.shared.all.instrumentation.classcache.MethodType.Character; import rocks.inspectit.shared.all.instrumentation.config.PriorityEnum; import rocks.inspectit.shared.all.instrumentation.config.impl.AgentConfig; import rocks.inspectit.shared.all.instrumentation.config.impl.ExceptionSensorTypeConfig; import rocks.inspectit.shared.all.instrumentation.config.impl.MethodInstrumentationConfig; import rocks.inspectit.shared.all.instrumentation.config.impl.SensorInstrumentationPoint; import rocks.inspectit.shared.all.testbase.TestBase; import rocks.inspectit.shared.cs.ci.Environment; import rocks.inspectit.shared.cs.ci.assignment.AbstractClassSensorAssignment; import rocks.inspectit.shared.cs.ci.assignment.impl.ExceptionSensorAssignment; import rocks.inspectit.shared.cs.cmr.service.IRegistrationService; /** * @author Ivan Senic * */ @SuppressWarnings("PMD") public class ExceptionSensorInstrumentationApplierTest extends TestBase { protected ExceptionSensorInstrumentationApplier applier; @Mock protected ExceptionSensorAssignment assignment; @Mock protected AssignmentFilterProvider filterProvider; @Mock protected Environment environment; @Mock protected IRegistrationService registrationService; @Mock protected ClassType classType; @Mock protected MethodType methodType; @Mock protected ClassSensorAssignmentFilter classFilter; @BeforeMethod public void setup() { applier = new ExceptionSensorInstrumentationApplier(assignment, environment, registrationService); applier.assignmentFilterProvider = filterProvider; // filters to true by default when(filterProvider.getClassSensorAssignmentFilter()).thenReturn(classFilter); when(classFilter.matches(Matchers.<AbstractClassSensorAssignment<?>> any(), Matchers.<ClassType> any())).thenReturn(true); // class to return one method when(classType.getMethods()).thenReturn(Collections.singleton(methodType)); } public class AddInstrumentationPoints extends ExceptionSensorInstrumentationApplierTest { @Test public void add() throws Exception { long agentId = 13L; long sensorId = 15L; long methodId = 17L; when(registrationService.registerMethodIdent(eq(agentId), anyString(), anyString(), anyString(), Matchers.<List<String>> any(), anyString(), anyInt())).thenReturn(methodId); ExceptionSensorTypeConfig exceptionSensorTypeConfig = mock(ExceptionSensorTypeConfig.class); when(exceptionSensorTypeConfig.getId()).thenReturn(sensorId); when(exceptionSensorTypeConfig.getPriority()).thenReturn(PriorityEnum.NORMAL); AgentConfig agentConfiguration = mock(AgentConfig.class); when(agentConfiguration.getPlatformId()).thenReturn(agentId); when(agentConfiguration.getExceptionSensorTypeConfig()).thenReturn(exceptionSensorTypeConfig); Map<String, Object> settings = Collections.<String, Object> singletonMap("key", "value"); when(assignment.getSettings()).thenReturn(settings); String packageName = "my.favorite.package"; String className = "ClassName"; String methodName = "<init>"; String returnType = "returnType"; List<String> parameters = Arrays.asList(new String[] {}); int mod = 10; when(classType.getFQN()).thenReturn(packageName + '.' + className); when(methodType.getClassOrInterfaceType()).thenReturn(classType); when(methodType.getName()).thenReturn(methodName); when(methodType.getParameters()).thenReturn(parameters); when(methodType.getReturnType()).thenReturn(returnType); when(methodType.getMethodCharacter()).thenReturn(Character.CONSTRUCTOR); when(methodType.getModifiers()).thenReturn(mod); when(classType.isException()).thenReturn(true); boolean changed = applier.addInstrumentationPoints(agentConfiguration, classType); // verify results assertThat(changed, is(true)); // verify registration service // for constructors the registered method name is class name verify(registrationService, times(1)).registerMethodIdent(agentId, packageName, className, methodName, parameters, returnType, mod); verifyNoMoreInteractions(registrationService); // check RSC and instrumentation config ArgumentCaptor<MethodInstrumentationConfig> captor = ArgumentCaptor.forClass(MethodInstrumentationConfig.class); verify(methodType, times(1)).setMethodInstrumentationConfig(captor.capture()); MethodInstrumentationConfig instrumentationConfig = captor.getValue(); SensorInstrumentationPoint rsc = instrumentationConfig.getSensorInstrumentationPoint(); assertThat(instrumentationConfig.getTargetClassFqn(), is(packageName + '.' + className)); assertThat(instrumentationConfig.getTargetMethodName(), is(methodName)); assertThat(instrumentationConfig.getReturnType(), is(returnType)); assertThat(instrumentationConfig.getParameterTypes(), is(parameters)); assertThat(instrumentationConfig.getAllInstrumentationPoints(), hasSize(1)); assertThat(rsc.getId(), is(methodId)); assertThat(rsc.getSensorIds().length, is(1)); assertThat(rsc.getSensorIds()[0], is(sensorId)); assertThat(rsc.getSettings(), is(settings)); assertThat(instrumentationConfig.getSpecialInstrumentationPoint(), is(nullValue())); } @Test public void doesNotMatchClassFilter() throws Exception { AgentConfig agentConfiguration = mock(AgentConfig.class); when(classType.isException()).thenReturn(true); when(classFilter.matches(assignment, classType)).thenReturn(false); boolean changed = applier.addInstrumentationPoints(agentConfiguration, classType); // verify results assertThat(changed, is(false)); verifyZeroInteractions(registrationService, methodType); } @Test public void doesNotMatchExceptionClass() throws Exception { AgentConfig agentConfiguration = mock(AgentConfig.class); when(classType.isException()).thenReturn(false); when(classFilter.matches(assignment, classType)).thenReturn(true); boolean changed = applier.addInstrumentationPoints(agentConfiguration, classType); // verify results assertThat(changed, is(false)); verifyZeroInteractions(registrationService, methodType); } @Test public void doesNotMatchMethod() throws Exception { AgentConfig agentConfiguration = mock(AgentConfig.class); when(classType.isException()).thenReturn(true); when(methodType.getMethodCharacter()).thenReturn(Character.METHOD); boolean changed = applier.addInstrumentationPoints(agentConfiguration, classType); // verify results assertThat(changed, is(false)); verify(methodType).getMethodCharacter(); verifyNoMoreInteractions(methodType); verifyZeroInteractions(registrationService); } @Test public void doesNotMatchStaticConstructor() throws Exception { AgentConfig agentConfiguration = mock(AgentConfig.class); when(classType.isException()).thenReturn(true); when(methodType.getMethodCharacter()).thenReturn(Character.STATIC_CONSTRUCTOR); boolean changed = applier.addInstrumentationPoints(agentConfiguration, classType); // verify results assertThat(changed, is(false)); verify(methodType).getMethodCharacter(); verifyNoMoreInteractions(methodType); verifyZeroInteractions(registrationService); } } public class RemoveInstrumentationPoints extends ExceptionSensorInstrumentationApplierTest { @Test public void remove() { when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.isException()).thenReturn(true); when(classType.getMethods()).thenReturn(Collections.singleton(methodType)); when(classFilter.matches(assignment, classType)).thenReturn(true); when(methodType.getMethodCharacter()).thenReturn(Character.CONSTRUCTOR); boolean removed = applier.removeInstrumentationPoints(classType); assertThat(removed, is(true)); verify(methodType, times(1)).setMethodInstrumentationConfig(Matchers.<MethodInstrumentationConfig> any()); } @Test public void doesNotMatchClassFilter() { when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.isException()).thenReturn(true); when(classType.getMethods()).thenReturn(Collections.singleton(methodType)); when(classFilter.matches(assignment, classType)).thenReturn(false); when(methodType.getName()).thenReturn("<init>"); boolean removed = applier.removeInstrumentationPoints(classType); assertThat(removed, is(false)); verify(methodType, times(0)).setMethodInstrumentationConfig(Matchers.<MethodInstrumentationConfig> any()); } @Test public void doesNotMatchConstructorMethod() { when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.isException()).thenReturn(true); when(classType.getMethods()).thenReturn(Collections.singleton(methodType)); when(classFilter.matches(assignment, classType)).thenReturn(true); when(methodType.getName()).thenReturn("whatever"); boolean removed = applier.removeInstrumentationPoints(classType); assertThat(removed, is(false)); verify(methodType, times(0)).setMethodInstrumentationConfig(Matchers.<MethodInstrumentationConfig> any()); } } }