/** * Removes duplicate {@link InstrumentationDefinition}s which are out-dated or would have been * overwritten by a newer {@link InstrumentationDefinition}. * * @param instrumentationDefinitions * the {@link InstrumentationDefinition}s of union * @return {@link Collection} of union {@link InstrumentationDefinition}s */ private Collection<InstrumentationDefinition> removeOutdatedInstrumentationDefinitions(List<InstrumentationDefinition> instrumentationDefinitions) { Map<String, InstrumentationDefinition> definitionMap = new HashMap<String, InstrumentationDefinition>(); for (InstrumentationDefinition iDefinition : instrumentationDefinitions) { definitionMap.put(iDefinition.getClassName(), iDefinition); } return definitionMap.values(); }
/** * Updates the timestamp of all method idents matching the {@link InstrumentationDefinition}s in * the given message. * * @param platformId * the platform id * @param messages * all agent messages */ private void updateMethodIdentTimestamps(long platformId, List<IAgentMessage<?>> messages) { for (IAgentMessage<?> agentMessage : messages) { if (agentMessage instanceof UpdatedInstrumentationMessage) { UpdatedInstrumentationMessage message = (UpdatedInstrumentationMessage) agentMessage; for (InstrumentationDefinition definition : message.getMessageContent()) { String fqn = definition.getClassName(); int index = fqn.lastIndexOf('.'); String packageName = fqn.substring(0, index); String className = fqn.substring(index + 1, fqn.length()); registrationService.updateMethodIdentTimestamp(platformId, packageName, className); } } } }
@Test public void retransformationDisabled() throws UnmodifiableClassException { InstrumentationDefinition objectDefinition = mock(InstrumentationDefinition.class); when(objectDefinition.getClassName()).thenReturn("java.lang.Object"); IAgentMessage<?> message = new UpdatedInstrumentationMessage(); ((UpdatedInstrumentationMessage) message).getMessageContent().add(objectDefinition); AgentMessagesReceivedEvent event = new AgentMessagesReceivedEvent(eventSource, Arrays.<IAgentMessage<?>> asList(message)); when(agent.isUsingRetransformation()).thenReturn(false); retransformManager.onApplicationEvent(event); verifyZeroInteractions(instrumentation, classHashHelper, threadTransformHelper); } }
@Test @SuppressWarnings("unchecked") public void changeEventNoAgentStatusData() throws Exception { when(definitionOne.getClassName()).thenReturn("class.one"); ClassInstrumentationChangedEvent eventOne = new ClassInstrumentationChangedEvent(this, 10L, Arrays.asList(definitionOne)); when(agentStatusDataProvider.getAgentStatusDataMap()).thenReturn(Collections.EMPTY_MAP); messageGate.onApplicationEvent(eventOne); verify(agentStatusDataProvider).getAgentStatusDataMap(); verifyNoMoreInteractions(agentStatusDataProvider); verifyZeroInteractions(statusData, messageProvider); }
@Test public void unknownPlatformId() throws Exception { when(definition.getClassName()).thenReturn("class.one"); ClassInstrumentationChangedEvent event = new ClassInstrumentationChangedEvent(this, 10L, Arrays.asList(definition)); messageGate.onApplicationEvent(event); messageGate.clear(20L); verifyZeroInteractions(messageProvider); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(1)); } }
@Test @SuppressWarnings("unchecked") public void unknownPlatformId() throws Exception { when(definition.getClassName()).thenReturn("class.one"); ClassInstrumentationChangedEvent event = new ClassInstrumentationChangedEvent(this, 10L, Arrays.asList(definition)); messageGate.onApplicationEvent(event); when(agentStatusDataProvider.getAgentStatusDataMap()).thenReturn(Collections.EMPTY_MAP); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(1)); messageGate.flush(20L); verifyZeroInteractions(messageProvider); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(1)); } }
@Test public void successful() throws Exception { when(definition.getClassName()).thenReturn("class.one"); ClassInstrumentationChangedEvent event = new ClassInstrumentationChangedEvent(this, 10L, Arrays.asList(definition)); messageGate.onApplicationEvent(event); messageGate.clear(10L); verifyZeroInteractions(messageProvider); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(0)); }
@Test public void agentRegisteredEvent() throws Exception { when(definitionOne.getClassName()).thenReturn("class.one"); ClassInstrumentationChangedEvent event = new ClassInstrumentationChangedEvent(this, 10L, Collections.singletonList(definitionOne)); messageGate.onApplicationEvent(event); AgentRegisteredEvent registeredEvent = new AgentRegisteredEvent(this, 10L); messageGate.onApplicationEvent(registeredEvent); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(0)); }
@Test public void instrumented() { Collection<MethodInstrumentationConfig> configs = mock(Collection.class); when(classType.isInitialized()).thenReturn(true); when(classType.getFQN()).thenReturn(FQN); when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.getInstrumentationPoints()).thenReturn(configs); when(instrumentationApplier.addInstrumentationPoints(agentConfiguration, classType)).thenReturn(true); InstrumentationDefinition result = instrumentation.addAndGetInstrumentationResult(classType, agentConfiguration, Collections.singleton(instrumentationApplier)); assertThat(result, is(notNullValue())); assertThat(result.getClassName(), is(FQN)); assertThat(result.getMethodInstrumentationConfigs(), is(configs)); }
@Test public void initialInstrumentationPoints() throws Exception { String fqn = "fqn"; String hash = "hash"; InstrumentationDefinition instrumentationResult = mock(InstrumentationDefinition.class); Map<Collection<String>, InstrumentationDefinition> initInstrumentations = Collections.<Collection<String>, InstrumentationDefinition> singletonMap(Collections.singleton(hash), instrumentationResult); when(instrumentationResult.getClassName()).thenReturn(fqn); when(configurationStorage.getInitialInstrumentationResults()).thenReturn(initInstrumentations); helper.afterPropertiesSet(); assertThat(helper.isEmpty(), is(false)); assertThat(helper.isSent(fqn, hash), is(true)); assertThat(helper.getInstrumentationDefinition(fqn), is(instrumentationResult)); }
@Test public void agentDeletedEvent() throws Exception { when(definitionOne.getClassName()).thenReturn("class.one"); ClassInstrumentationChangedEvent event = new ClassInstrumentationChangedEvent(this, 10L, Collections.singletonList(definitionOne)); messageGate.onApplicationEvent(event); AgentDeletedEvent deletedEvent = new AgentDeletedEvent(this, 10L); messageGate.onApplicationEvent(deletedEvent); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(0)); }
@Test @SuppressWarnings("unchecked") public void changeEventReplaceInstrumentationDefinition() throws Exception { when(definitionOne.getClassName()).thenReturn("class.one"); when(definitionTwo.getClassName()).thenReturn("class.two"); when(definitionThree.getClassName()).thenReturn("class.one"); ClassInstrumentationChangedEvent eventOne = new ClassInstrumentationChangedEvent(this, 10L, Arrays.asList(definitionOne, definitionTwo)); ClassInstrumentationChangedEvent eventTwo = new ClassInstrumentationChangedEvent(this, 10L, Arrays.asList(definitionThree)); when(agentStatusDataProvider.getAgentStatusDataMap()).thenReturn(Collections.EMPTY_MAP); when(statusData.getInstrumentationStatus()).thenReturn(InstrumentationStatus.UP_TO_DATE, InstrumentationStatus.PENDING); messageGate.onApplicationEvent(eventOne); messageGate.onApplicationEvent(eventTwo); assertThat(getDefinitionBuffer().entrySet(), hasSize(1)); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(2)); assertThat(getDefinitionBuffer().get(10L), hasEntry("class.one", definitionThree)); assertThat(getDefinitionBuffer().get(10L), hasEntry("class.two", definitionTwo)); }
@Test public void unmodifiableClass() throws UnmodifiableClassException { InstrumentationDefinition iDefinition = mock(InstrumentationDefinition.class); when(iDefinition.getClassName()).thenReturn("java.lang.Object"); IAgentMessage<?> message = new UpdatedInstrumentationMessage(); ((UpdatedInstrumentationMessage) message).getMessageContent().add(iDefinition); AgentMessagesReceivedEvent event = new AgentMessagesReceivedEvent(eventSource, Arrays.<IAgentMessage<?>> asList(message)); when(instrumentation.getAllLoadedClasses()).thenReturn(new Class[] { Object.class, String.class }); when(instrumentation.isModifiableClass(eq(Object.class))).thenReturn(false); when(agent.isUsingRetransformation()).thenReturn(true); retransformManager.onApplicationEvent(event); verify(classHashHelper).registerInstrumentationDefinition(eq("java.lang.Object"), eq(iDefinition)); verify(instrumentation).getAllLoadedClasses(); verify(instrumentation, times(2)).isModifiableClass(any(Class.class)); verifyNoMoreInteractions(instrumentation, classHashHelper); verifyZeroInteractions(threadTransformHelper); }
@Test public void unknownInstrumentationClass() throws UnmodifiableClassException { InstrumentationDefinition iDefinition = mock(InstrumentationDefinition.class); when(iDefinition.getClassName()).thenReturn("unknown.Class"); IAgentMessage<?> message = new UpdatedInstrumentationMessage(); ((UpdatedInstrumentationMessage) message).getMessageContent().add(iDefinition); AgentMessagesReceivedEvent event = new AgentMessagesReceivedEvent(eventSource, Arrays.<IAgentMessage<?>> asList(message)); when(instrumentation.getAllLoadedClasses()).thenReturn(new Class[] { Object.class, String.class }); when(agent.isUsingRetransformation()).thenReturn(true); retransformManager.onApplicationEvent(event); verify(classHashHelper).registerInstrumentationDefinition(eq("unknown.Class"), eq(iDefinition)); verify(instrumentation).getAllLoadedClasses(); verify(instrumentation, times(2)).isModifiableClass(any(Class.class)); verifyNoMoreInteractions(instrumentation, classHashHelper); verifyZeroInteractions(threadTransformHelper); }
@Test @SuppressWarnings("rawtypes") public void successful() throws Exception { when(definition.getClassName()).thenReturn("class.one"); ClassInstrumentationChangedEvent event = new ClassInstrumentationChangedEvent(this, 10L, Arrays.asList(definition)); messageGate.onApplicationEvent(event); when(agentStatusDataProvider.getAgentStatusDataMap()).thenReturn(ImmutableMap.of(10L, statusData)); when(statusData.getInstrumentationStatus()).thenReturn(InstrumentationStatus.PENDING); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(1)); messageGate.flush(10L); ArgumentCaptor<IAgentMessage> messageCaptor = ArgumentCaptor.forClass(IAgentMessage.class); verify(messageProvider).provideMessage(eq(10L), messageCaptor.capture()); verify(statusData).setInstrumentationStatus(InstrumentationStatus.UP_TO_DATE); verifyNoMoreInteractions(statusData, messageProvider); assertThat(((UpdatedInstrumentationMessage) messageCaptor.getValue()).getMessageContent(), contains(definition)); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(0)); }
@Test public void collect() throws Exception { Collection<MethodInstrumentationConfig> configs = mock(Collection.class); when(classType.isClass()).thenReturn(true); when(classType.castToClass()).thenReturn(classType); when(classType.isInitialized()).thenReturn(true); when(classType.getFQN()).thenReturn(FQN); when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.getInstrumentationPoints()).thenReturn(configs); doReturn(Collections.singleton(classType)).when(lookup).findAll(); Collection<InstrumentationDefinition> result = instrumentation.getInstrumentationResults(); // assert result assertThat(result, hasSize(1)); InstrumentationDefinition instrumentationResult = result.iterator().next(); assertThat(instrumentationResult.getClassName(), is(FQN)); assertThat(instrumentationResult.getMethodInstrumentationConfigs(), is(configs)); // read lock is enough verify(classCache, times(1)).executeWithReadLock(Matchers.<Callable<?>> any()); }
@Test public void collect() throws Exception { Collection<MethodInstrumentationConfig> configs = mock(Collection.class); Set<String> hashes = mock(Set.class); when(classType.isClass()).thenReturn(true); when(classType.castToClass()).thenReturn(classType); when(classType.isInitialized()).thenReturn(true); when(classType.getFQN()).thenReturn(FQN); when(classType.hasInstrumentationPoints()).thenReturn(true); when(classType.getInstrumentationPoints()).thenReturn(configs); when(classType.getHashes()).thenReturn(hashes); doReturn(Collections.singleton(classType)).when(lookup).findAll(); Map<Collection<String>, InstrumentationDefinition> result = instrumentation.getInstrumentationResultsWithHashes(); // assert result assertThat(result.size(), is(1)); Entry<Collection<String>, InstrumentationDefinition> entry = result.entrySet().iterator().next(); assertThat((Set<String>) entry.getKey(), is(hashes)); assertThat(entry.getValue().getClassName(), is(FQN)); assertThat(entry.getValue().getMethodInstrumentationConfigs(), is(configs)); // read lock is enough verify(classCache, times(1)).executeWithReadLock(Matchers.<Callable<?>> any()); }
@Test @SuppressWarnings("unchecked") public void changeEventAddInstrumentationDefinitionForDiffrentAgents() throws Exception { when(definitionOne.getClassName()).thenReturn("class.one"); when(definitionTwo.getClassName()).thenReturn("class.two"); when(definitionThree.getClassName()).thenReturn("class.one"); ClassInstrumentationChangedEvent eventOne = new ClassInstrumentationChangedEvent(this, 10L, Arrays.asList(definitionOne, definitionTwo)); ClassInstrumentationChangedEvent eventTwo = new ClassInstrumentationChangedEvent(this, 20L, Arrays.asList(definitionThree)); when(agentStatusDataProvider.getAgentStatusDataMap()).thenReturn(Collections.EMPTY_MAP); when(statusData.getInstrumentationStatus()).thenReturn(InstrumentationStatus.UP_TO_DATE, InstrumentationStatus.PENDING); messageGate.onApplicationEvent(eventOne); messageGate.onApplicationEvent(eventTwo); assertThat(getDefinitionBuffer().entrySet(), hasSize(2)); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(2)); assertThat(getDefinitionBuffer().get(10L), hasEntry("class.one", definitionOne)); assertThat(getDefinitionBuffer().get(10L), hasEntry("class.two", definitionTwo)); assertThat(getDefinitionBuffer().get(20L).entrySet(), hasSize(1)); assertThat(getDefinitionBuffer().get(20L), hasEntry("class.one", definitionThree)); }
@Test public void retransformationThrowsException() throws UnmodifiableClassException { InstrumentationDefinition iDefinition = mock(InstrumentationDefinition.class); when(iDefinition.getClassName()).thenReturn("java.lang.Object"); IAgentMessage<?> message = new UpdatedInstrumentationMessage(); ((UpdatedInstrumentationMessage) message).getMessageContent().add(iDefinition); AgentMessagesReceivedEvent event = new AgentMessagesReceivedEvent(eventSource, Arrays.<IAgentMessage<?>> asList(message)); when(instrumentation.getAllLoadedClasses()).thenReturn(new Class[] { Object.class, String.class }); doThrow(Exception.class).when(instrumentation).retransformClasses(any(Class.class)); when(instrumentation.isModifiableClass(Matchers.<Class<?>> any())).thenReturn(true); when(agent.isUsingRetransformation()).thenReturn(true); retransformManager.onApplicationEvent(event); verify(classHashHelper).registerInstrumentationDefinition(eq("java.lang.Object"), eq(iDefinition)); verify(instrumentation).getAllLoadedClasses(); verify(instrumentation).retransformClasses(any(Class.class)); verify(instrumentation, times(2)).isModifiableClass(any(Class.class)); InOrder inOrder = inOrder(threadTransformHelper); inOrder.verify(threadTransformHelper).setThreadTransformDisabled(false); inOrder.verify(threadTransformHelper).setThreadTransformDisabled(true); verifyNoMoreInteractions(instrumentation, classHashHelper); verifyZeroInteractions(threadTransformHelper); }
@Test @SuppressWarnings("unchecked") public void instrumentationThrowsOneException() throws UnmodifiableClassException { InstrumentationDefinition iDefinition = mock(InstrumentationDefinition.class); when(iDefinition.getClassName()).thenReturn("java.lang.Object"); IAgentMessage<?> message = new UpdatedInstrumentationMessage(); ((UpdatedInstrumentationMessage) message).getMessageContent().add(iDefinition); AgentMessagesReceivedEvent event = new AgentMessagesReceivedEvent(eventSource, Arrays.<IAgentMessage<?>> asList(message)); when(instrumentation.getAllLoadedClasses()).thenReturn(new Class[] { Object.class, String.class }); when(instrumentation.isModifiableClass(any(Class.class))).thenReturn(true).thenThrow(RuntimeException.class); when(agent.isUsingRetransformation()).thenReturn(true); retransformManager.onApplicationEvent(event); verify(classHashHelper).registerInstrumentationDefinition(eq("java.lang.Object"), eq(iDefinition)); verify(instrumentation).getAllLoadedClasses(); verify(instrumentation).retransformClasses(eq(Object.class)); verify(instrumentation, times(2)).isModifiableClass(any(Class.class)); InOrder inOrder = inOrder(threadTransformHelper); inOrder.verify(threadTransformHelper).setThreadTransformDisabled(false); inOrder.verify(threadTransformHelper).setThreadTransformDisabled(true); verifyNoMoreInteractions(instrumentation, classHashHelper, threadTransformHelper); }