@Test public void connectFirstTime() { long platformIdent = 10L; agentStatusDataProvider.registerConnected(platformIdent); assertThat(agentStatusDataProvider.getAgentStatusDataMap().entrySet(), hasSize(1)); AgentStatusData agentStatusData = agentStatusDataProvider.getAgentStatusDataMap().get(platformIdent); assertThat(agentStatusData, is(notNullValue())); assertThat(agentStatusData.getAgentConnection(), is(AgentConnection.CONNECTED)); assertThat(agentStatusData.getConnectionTimestamp(), is(greaterThan(0L))); assertThat(agentStatusData.getLastKeepAliveTimestamp(), is(greaterThan(0L))); assertThat(agentStatusData.getMillisSinceLastData(), is(nullValue())); assertThat(agentStatusData.getInstrumentationStatus(), is(InstrumentationStatus.UP_TO_DATE)); }
/** * Registers that the agent was connected. * * @param platformIdent * ID of the platform ident. */ public void registerConnected(long platformIdent) { AgentStatusData agentStatusData = agentStatusDataMap.get(platformIdent); if (null == agentStatusData) { agentStatusData = new AgentStatusData(AgentConnection.CONNECTED); AgentStatusData existing = agentStatusDataMap.putIfAbsent(platformIdent, agentStatusData); if (null != existing) { agentStatusData = existing; } } long currentTimeMillis = System.currentTimeMillis(); agentStatusData.setLastKeepAliveTimestamp(currentTimeMillis); agentStatusData.setConnectionTimestamp(currentTimeMillis); agentStatusData.setAgentConnection(AgentConnection.CONNECTED); agentStatusData.setPendingSinceTime(currentTimeMillis); // set instrumentation status up-to-date agentStatusData.setInstrumentationStatus(InstrumentationStatus.UP_TO_DATE); }
/** * Returns a descriptive text for the given agent. It contains a date which is formated using * the given {@link SimpleDateFormat}. * * @param entry * the agent * @param format * used {@link SimpleDateFormat} to format the date * @return descriptive {@link String} of the given agent */ private String getAgentText(Entry<PlatformIdent, AgentStatusData> entry, SimpleDateFormat format) { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(entry.getKey().getAgentName()); stringBuffer.append(" ["); stringBuffer.append(entry.getKey().getVersion()); stringBuffer.append("] - Pending since: "); stringBuffer.append(format.format(new Date(entry.getValue().getLastInstrumentationUpate()))); return stringBuffer.toString(); }
@Override public void run() { long currentTime = System.currentTimeMillis(); for (Entry<Long, AgentStatusData> entry : agentStatusDataMap.entrySet()) { if (entry.getValue().getAgentConnection() != AgentConnection.CONNECTED) { continue; } long timeToLastSignal = currentTime - entry.getValue().getLastKeepAliveTimestamp(); if (timeToLastSignal > IKeepAliveService.KA_TIMEOUT) { registerKeepAliveTimeout(entry.getKey()); if (log.isInfoEnabled()) { log.info("Platform " + entry.getKey() + " timed out."); } } } } };
/** * Registers the time when the last keep-alive was received for a given platform ident. * * @param platformIdent * ID of the platform ident. */ public void handleKeepAliveSignal(long platformIdent) { AgentStatusData agentStatusData = agentStatusDataMap.get(platformIdent); if (null != agentStatusData) { agentStatusData.setLastKeepAliveTimestamp(System.currentTimeMillis()); // Updates the agent status if no keep-alive messages were received before if (agentStatusData.getAgentConnection() == AgentConnection.NO_KEEP_ALIVE) { agentStatusData.setAgentConnection(AgentConnection.CONNECTED); if (log.isInfoEnabled()) { log.info("Platform " + platformIdent + " sending keep-alive signals again."); } } } else { registerConnected(platformIdent); agentStatusDataMap.get(platformIdent).setInstrumentationStatus(InstrumentationStatus.NO_CLASS_CACHE_AVAILABLE); if (log.isInfoEnabled()) { log.info("Platform " + platformIdent + " has been reconnected, but no class cache is available for this agent. Please reconnect the agent, to reload the class cache."); } } }
@Test public void neverConnected() { long platformIdent = 10L; long currentTimeMillis = System.currentTimeMillis(); agentStatusDataProvider.handleKeepAliveSignal(platformIdent); AgentStatusData agentStatusData = agentStatusDataProvider.getAgentStatusDataMap().get(platformIdent); assertThat(agentStatusData.getAgentConnection(), is(AgentConnection.CONNECTED)); assertThat(agentStatusData.getLastKeepAliveTimestamp(), is(greaterThanOrEqualTo(currentTimeMillis))); assertThat(agentStatusData.getInstrumentationStatus(), is(InstrumentationStatus.NO_CLASS_CACHE_AVAILABLE)); }
/** * Handles an event of type {@link ClassInstrumentationChangedEvent}. * * @param event * the event instance */ private void handleClassInstrumentationChangedEvent(ClassInstrumentationChangedEvent event) { if (log.isDebugEnabled()) { log.debug("Putting instrumentation definitions for agent {} into the definition buffer.", event.getAgentId()); } Map<String, InstrumentationDefinition> pendingDefinitions = definitionBuffer.get(event.getAgentId()); if (pendingDefinitions == null) { pendingDefinitions = new HashMap<>(); definitionBuffer.put(event.getAgentId(), pendingDefinitions); } for (InstrumentationDefinition definition : event.getInstrumentationDefinitions()) { pendingDefinitions.put(definition.getClassName(), definition); } AgentStatusData agentStatusData = agentStatusDataProvider.getAgentStatusDataMap().get(event.getAgentId()); if (agentStatusData != null) { if (agentStatusData.getInstrumentationStatus() != InstrumentationStatus.PENDING) { agentStatusData.setInstrumentationStatus(InstrumentationStatus.PENDING); agentStatusData.setPendingSinceTime(System.currentTimeMillis()); } } }
/** * {@inheritDoc} */ @Override public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { if (receiver instanceof AgentLeaf) { AgentLeaf agentLeaf = (AgentLeaf) receiver; if ("canDelete".equals(property)) { return (null == agentLeaf.getAgentStatusData()) || (agentLeaf.getAgentStatusData().getAgentConnection() != AgentConnection.CONNECTED); } } return false; }
for (Entry<PlatformIdent, AgentStatusData> entry : agentsOverview.entrySet()) { AgentStatusData agentStatus = entry.getValue(); if ((agentStatus.getAgentConnection() == AgentConnection.CONNECTED) && (agentStatus.getInstrumentationStatus() == InstrumentationStatus.PENDING)) { resultMap.put(entry.getKey(), entry.getValue());
@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)); }
switch (agentStatusData.getAgentConnection()) { case CONNECTED: if (null != agentStatusData.getMillisSinceLastData()) { long millis = agentStatusData.getMillisSinceLastData().longValue();
@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)); }
/** * {@inheritDoc} */ @Override @MethodLog public Map<PlatformIdent, AgentStatusData> getAgentsOverview() { List<PlatformIdent> agents = platformIdentDao.findAll(); Map<Long, AgentStatusData> agentStatusMap = agentStatusProvider.getAgentStatusDataMap(); Map<PlatformIdent, AgentStatusData> resultMap = new HashMap<>(); for (PlatformIdent platformIdent : agents) { AgentStatusData status = agentStatusMap.get(platformIdent.getId()); if (null == status) { status = new AgentStatusData(AgentConnection.NEVER_CONNECTED); } resultMap.put(platformIdent, status); } return resultMap; }
/** * Creates an {@link UpdatedInstrumentationMessage} which contains all stored * {@link InstrumentationDefinition}. The created message is put in the message provider for the * agent to fetch. * * @param platformId * the id of the platform which {@link InstrumentationDefinition}s should be provided * for fetching */ public synchronized void flush(long platformId) { if (log.isDebugEnabled()) { log.debug("Flushing new instrumentations for agent {}.", platformId); } Map<String, InstrumentationDefinition> pendingDefinitions = definitionBuffer.put(platformId, new HashMap<String, InstrumentationDefinition>()); if (MapUtils.isNotEmpty(pendingDefinitions)) { UpdatedInstrumentationMessage message = new UpdatedInstrumentationMessage(); message.getMessageContent().addAll(pendingDefinitions.values()); messageProvider.provideMessage(platformId, message); } AgentStatusData agentStatusData = agentStatusDataProvider.getAgentStatusDataMap().get(platformId); if (agentStatusData != null) { agentStatusData.setInstrumentationStatus(InstrumentationStatus.UP_TO_DATE); } }
@Test public void connected() { long platformIdent = 10L; agentStatusDataProvider.registerConnected(platformIdent); agentStatusDataProvider.registerDataSent(platformIdent); AgentStatusData agentStatusData = agentStatusDataProvider.getAgentStatusDataMap().get(platformIdent); assertThat(agentStatusData, is(notNullValue())); assertThat(agentStatusData.getMillisSinceLastData(), is(notNullValue())); } }
@Test public void connected() { long platformIdent = 10L; agentStatusDataProvider.registerConnected(platformIdent); long currentTimeMillis = System.currentTimeMillis(); agentStatusDataProvider.handleKeepAliveSignal(platformIdent); AgentStatusData agentStatusData = agentStatusDataProvider.getAgentStatusDataMap().get(platformIdent); assertThat(agentStatusData.getAgentConnection(), is(AgentConnection.CONNECTED)); assertThat(agentStatusData.getLastKeepAliveTimestamp(), is(greaterThanOrEqualTo(currentTimeMillis))); }
@Test public void changeEventAddInstrumentationDefinitions() throws Exception { when(definitionOne.getClassName()).thenReturn("class.one"); when(definitionTwo.getClassName()).thenReturn("class.two"); when(definitionThree.getClassName()).thenReturn("class.three"); ClassInstrumentationChangedEvent eventOne = new ClassInstrumentationChangedEvent(this, 10L, Arrays.asList(definitionOne, definitionTwo)); ClassInstrumentationChangedEvent eventTwo = new ClassInstrumentationChangedEvent(this, 10L, Arrays.asList(definitionThree)); when(agentStatusDataProvider.getAgentStatusDataMap()).thenReturn(ImmutableMap.of(10L, statusData)); when(statusData.getInstrumentationStatus()).thenReturn(InstrumentationStatus.UP_TO_DATE, InstrumentationStatus.PENDING); long currentTime = System.currentTimeMillis(); messageGate.onApplicationEvent(eventOne); messageGate.onApplicationEvent(eventTwo); verify(definitionOne).getClassName(); verify(definitionTwo).getClassName(); verify(definitionThree).getClassName(); verify(agentStatusDataProvider, times(2)).getAgentStatusDataMap(); verify(statusData, times(2)).getInstrumentationStatus(); verify(statusData).setInstrumentationStatus(InstrumentationStatus.PENDING); ArgumentCaptor<Long> timeCaptor = ArgumentCaptor.forClass(Long.class); verify(statusData).setPendingSinceTime(timeCaptor.capture()); verifyNoMoreInteractions(definitionOne, definitionTwo, definitionThree, agentStatusDataProvider, statusData); verifyZeroInteractions(messageProvider); assertThat(timeCaptor.getValue(), greaterThanOrEqualTo(currentTime)); assertThat(getDefinitionBuffer().entrySet(), hasSize(1)); assertThat(getDefinitionBuffer().get(10L).entrySet(), hasSize(3)); assertThat(getDefinitionBuffer().get(10L), hasEntry("class.one", definitionOne)); assertThat(getDefinitionBuffer().get(10L), hasEntry("class.two", definitionTwo)); assertThat(getDefinitionBuffer().get(10L), hasEntry("class.three", definitionThree)); }
@Test public void timeout() throws Exception { long platformIdent = 10L; agentStatusDataProvider.registerConnected(platformIdent); Thread.sleep(IKeepAliveService.KA_TIMEOUT + 1); agentStatusDataProvider.afterPropertiesSet(); AgentStatusData agentStatusData = agentStatusDataProvider.getAgentStatusDataMap().get(platformIdent); assertThat(agentStatusData, is(notNullValue())); assertThat(agentStatusData.getAgentConnection(), is(AgentConnection.NO_KEEP_ALIVE)); }
@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)); }
/** * No delete enabled when agent is connected. */ @Test(expectedExceptions = { BusinessException.class }) public void testConnectedAgentDelete() throws BusinessException { long platformId = 10L; PlatformIdent platformIdent = new PlatformIdent(); platformIdent.setId(platformId); when(platformIdentDao.load(Long.valueOf(platformId))).thenReturn(platformIdent); Map<Long, AgentStatusData> map = new HashMap<>(1); AgentStatusData agentStatusData = new AgentStatusData(AgentConnection.CONNECTED); map.put(platformId, agentStatusData); when(agentStatusProvider.getAgentStatusDataMap()).thenReturn(map); globalDataAccessService.deleteAgent(platformId); }