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 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.server.instrumentation.config.filter.MethodSensorAssignmentFilter; 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.MethodInstrumentationConfig; import rocks.inspectit.shared.all.instrumentation.config.impl.MethodSensorTypeConfig; import rocks.inspectit.shared.all.instrumentation.config.impl.SpecialInstrumentationPoint; import rocks.inspectit.shared.all.instrumentation.config.impl.SubstitutionDescriptor; 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.MethodSensorAssignment; import rocks.inspectit.shared.cs.ci.assignment.impl.SpecialMethodSensorAssignment; import rocks.inspectit.shared.cs.ci.sensor.method.special.AbstractSpecialMethodSensorConfig; import rocks.inspectit.shared.cs.cmr.service.IRegistrationService; /** * @author Ivan Senic * */ @SuppressWarnings("PMD") public class SpecialInstrumentationApplierTest extends TestBase { protected SpecialInstrumentationApplier applier; @Mock protected SpecialMethodSensorAssignment assignment; @Mock protected AssignmentFilterProvider filterProvider; @Mock protected Environment environment; @Mock protected IRegistrationService registrationService; @Mock protected ClassType classType; @Mock protected MethodType methodType; @Mock protected MethodSensorAssignmentFilter methodFilter; @Mock protected ClassSensorAssignmentFilter classFilter; @BeforeMethod public void setup() { applier = new SpecialInstrumentationApplier(assignment, environment, registrationService); applier.assignmentFilterProvider = filterProvider; // filters to true by default when(filterProvider.getClassSensorAssignmentFilter()).thenReturn(classFilter); when(filterProvider.getMethodSensorAssignmentFilter()).thenReturn(methodFilter); when(methodFilter.matches(Matchers.<MethodSensorAssignment> any(), Matchers.<MethodType> any())).thenReturn(true); when(classFilter.matches(Matchers.<AbstractClassSensorAssignment<?>> any(), Matchers.<ClassType> any(), Matchers.eq(false))).thenReturn(true); // class to return one method when(classType.getMethods()).thenReturn(Collections.singleton(methodType)); when(methodType.getMethodCharacter()).thenReturn(Character.METHOD); } public class AddInstrumentationPoints extends SpecialInstrumentationApplierTest { @Test public void add() throws Exception { long agentId = 13L; long sensorId = 15L; long methodId = 17L; String sensorClassName = "sensorClassName"; when(registrationService.registerMethodIdent(eq(agentId), anyString(), anyString(), anyString(), Matchers.<List<String>> any(), anyString(), anyInt())).thenReturn(methodId); MethodSensorTypeConfig methodSensorTypeConfig = mock(MethodSensorTypeConfig.class); when(methodSensorTypeConfig.getId()).thenReturn(sensorId); when(methodSensorTypeConfig.getPriority()).thenReturn(PriorityEnum.NORMAL); AgentConfig agentConfiguration = mock(AgentConfig.class); when(agentConfiguration.getPlatformId()).thenReturn(agentId); when(agentConfiguration.getSpecialMethodSensorTypeConfig(sensorClassName)).thenReturn(methodSensorTypeConfig); AbstractSpecialMethodSensorConfig methodSensorConfig = mock(AbstractSpecialMethodSensorConfig.class); when(methodSensorConfig.getClassName()).thenReturn(sensorClassName); when(assignment.getSpecialMethodSensorConfig()).thenReturn(methodSensorConfig); SubstitutionDescriptor substitutionDescriptor = mock(SubstitutionDescriptor.class); when(methodSensorConfig.getSubstitutionDescriptor()).thenReturn(substitutionDescriptor); String packageName = "my.favorite.package"; String className = "ClassName"; String methodName = "methodName"; String returnType = "returnType"; List<String> parameters = Arrays.asList(new String[] { "p1", "p2" }); 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.METHOD); when(methodType.getModifiers()).thenReturn(mod); boolean changed = applier.addInstrumentationPoints(agentConfiguration, classType); // verify results assertThat(changed, is(true)); // verify registration service verify(registrationService, times(1)).registerMethodIdent(agentId, packageName, className, methodName, parameters, returnType, mod); verifyNoMoreInteractions(registrationService); // check instrumentation config ArgumentCaptor<MethodInstrumentationConfig> captor = ArgumentCaptor.forClass(MethodInstrumentationConfig.class); verify(methodType, times(1)).setMethodInstrumentationConfig(captor.capture()); MethodInstrumentationConfig instrumentationConfig = captor.getValue(); 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)); SpecialInstrumentationPoint ssc = instrumentationConfig.getSpecialInstrumentationPoint(); assertThat(ssc.getId(), is(methodId)); assertThat(ssc.getSensorId(), is(sensorId)); assertThat(ssc.getSubstitutionDescriptor(), is(substitutionDescriptor)); assertThat(instrumentationConfig.getSensorInstrumentationPoint(), is(nullValue())); } @Test public void doesNotMatchClassFilter() throws Exception { AgentConfig agentConfiguration = mock(AgentConfig.class); when(classFilter.matches(assignment, classType, false)).thenReturn(false); boolean changed = applier.addInstrumentationPoints(agentConfiguration, classType); // verify results assertThat(changed, is(false)); verifyZeroInteractions(methodType); } @Test public void doesNotMatchMethodFilter() throws Exception { AgentConfig agentConfiguration = mock(AgentConfig.class); when(methodFilter.matches(assignment, methodType)).thenReturn(false); // test direct and via collection // we expect two calls to everything boolean changed = applier.addInstrumentationPoints(agentConfiguration, classType); // verify results assertThat(changed, is(false)); verify(methodType).getMethodCharacter(); verifyNoMoreInteractions(methodType); } @Test public void doesNotInstrumentConstructor() throws Exception { AgentConfig agentConfiguration = mock(AgentConfig.class); when(methodType.getMethodCharacter()).thenReturn(Character.CONSTRUCTOR); boolean changed = applier.addInstrumentationPoints(agentConfiguration, classType); // verify results assertThat(changed, is(false)); verify(methodType).getMethodCharacter(); verifyNoMoreInteractions(methodType); } @Test public void doesNotInstrumentStaticConstructor() throws Exception { AgentConfig agentConfiguration = mock(AgentConfig.class); when(methodType.getMethodCharacter()).thenReturn(Character.STATIC_CONSTRUCTOR); boolean changed = applier.addInstrumentationPoints(agentConfiguration, classType); // verify results assertThat(changed, is(false)); verify(methodType).getMethodCharacter(); verifyNoMoreInteractions(methodType); } } public class RemoveInstrumentationPoints extends SpecialInstrumentationApplierTest { @Test public void remove() { when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.getMethods()).thenReturn(Collections.singleton(methodType)); when(classFilter.matches(assignment, classType, false)).thenReturn(true); when(methodFilter.matches(assignment, methodType)).thenReturn(true); boolean removed = applier.removeInstrumentationPoints(classType); assertThat(removed, is(true)); verify(methodType, times(1)).setMethodInstrumentationConfig(null); } @Test public void doesNotMatchClassFilter() { when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.getMethods()).thenReturn(Collections.singleton(methodType)); when(classFilter.matches(assignment, classType, false)).thenReturn(false); when(methodFilter.matches(assignment, methodType)).thenReturn(true); boolean removed = applier.removeInstrumentationPoints(classType); assertThat(removed, is(false)); verifyZeroInteractions(methodType); } @Test public void doesNotMatchMethodFilter() { when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.getMethods()).thenReturn(Collections.singleton(methodType)); when(classFilter.matches(assignment, classType, false)).thenReturn(true); when(methodFilter.matches(assignment, methodType)).thenReturn(false); boolean removed = applier.removeInstrumentationPoints(classType); assertThat(removed, is(false)); verify(methodType).getMethodCharacter(); verifyNoMoreInteractions(methodType); } @Test public void doesNotMatchConstructor() { when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.getMethods()).thenReturn(Collections.singleton(methodType)); when(classFilter.matches(assignment, classType, false)).thenReturn(true); when(methodFilter.matches(assignment, methodType)).thenReturn(true); when(methodType.getMethodCharacter()).thenReturn(Character.CONSTRUCTOR); boolean removed = applier.removeInstrumentationPoints(classType); assertThat(removed, is(false)); verify(methodType).getMethodCharacter(); verifyNoMoreInteractions(methodType); } @Test public void doesNotMatchStaticConstructor() { when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.getMethods()).thenReturn(Collections.singleton(methodType)); when(classFilter.matches(assignment, classType, false)).thenReturn(true); when(methodFilter.matches(assignment, methodType)).thenReturn(true); when(methodType.getMethodCharacter()).thenReturn(Character.STATIC_CONSTRUCTOR); boolean removed = applier.removeInstrumentationPoints(classType); assertThat(removed, is(false)); verify(methodType).getMethodCharacter(); verifyNoMoreInteractions(methodType); } } }