/*
* Copyright 2015 NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.navercorp.pinpoint.collector.rpc.handler;
import com.navercorp.pinpoint.collector.dao.AgentLifeCycleDao;
import com.navercorp.pinpoint.collector.util.ManagedAgentLifeCycle;
import com.navercorp.pinpoint.common.server.bo.AgentLifeCycleBo;
import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState;
import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType;
import com.navercorp.pinpoint.rpc.server.PinpointServer;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
* @author HyunGil Jeong
*/
@RunWith(MockitoJUnitRunner.class)
public class AgentLifeCycleHandlerTest {
// FIX guava 19.0.0 update error. MoreExecutors.sameThreadExecutor(); change final class
@Spy
private Executor executor = new DirectExecutor();
@Mock
private PinpointServer pinpointServer;
@Mock
private AgentLifeCycleDao agentLifeCycleDao;
@InjectMocks
private AgentLifeCycleHandler agentLifeCycleHandler = new AgentLifeCycleHandler();
private static final String TEST_AGENT_ID = "TEST_AGENT";
private static final long TEST_START_TIMESTAMP = System.currentTimeMillis();
private static final long TEST_EVENT_TIMESTAMP = TEST_START_TIMESTAMP + 10;
private static final int TEST_SOCKET_ID = 999;
private static final Map<Object, Object> TEST_CHANNEL_PROPERTIES = createTestChannelProperties();
@Before
public void setUp() throws Exception {
when(this.pinpointServer.getChannelProperties()).thenReturn(TEST_CHANNEL_PROPERTIES);
}
@Test
public void runningStateShouldBeInserted() {
runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.RUNNING);
}
@Test
public void closedByClientStateShouldBeInserted() {
runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.CLOSED_BY_CLIENT);
}
@Test
public void unexpectedCloseByClientStateShouldBeInserted() {
runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.UNEXPECTED_CLOSE_BY_CLIENT);
}
@Test
public void closedByServerStateShouldBeInserted() {
runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.CLOSED_BY_SERVER);
}
@Test
public void unexpectedCloseByServerStateShouldBeInserted() {
runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.UNEXPECTED_CLOSE_BY_SERVER);
}
@Test
public void testValidTimestampCreation() {
// socketId = 1, eventCounter = 1 -> timestamp = 0x100000001
int givenSocketId = 1;
int givenEventCounter = 1;
long expectedTimestamp = new BigInteger("100000001", 16).longValue();
long timestamp = this.agentLifeCycleHandler.createEventIdentifier(givenSocketId, givenEventCounter);
assertEquals(expectedTimestamp, timestamp);
// socketId = 0, eventCounter = 0 -> timestamp = 0x0
givenSocketId = 0;
givenEventCounter = 0;
expectedTimestamp = new BigInteger("0000000000000000", 16).longValue();
timestamp = this.agentLifeCycleHandler.createEventIdentifier(givenSocketId, givenEventCounter);
assertEquals(expectedTimestamp, timestamp);
// socketId = Integer.MAX_VALUE, eventCounter = 0 -> timestamp = 0x7fffffff00000000
givenSocketId = Integer.MAX_VALUE;
givenEventCounter = 0;
expectedTimestamp = new BigInteger("7fffffff00000000", 16).longValue();
timestamp = this.agentLifeCycleHandler.createEventIdentifier(givenSocketId, givenEventCounter);
assertEquals(expectedTimestamp, timestamp);
// socketId = Integer.MAX_VALUE, eventCounter = Integer.MAX_VALUE -> timestamp = 0x7fffffff7fffffff
givenSocketId = Integer.MAX_VALUE;
givenEventCounter = Integer.MAX_VALUE;
expectedTimestamp = new BigInteger("7fffffff7fffffff", 16).longValue();
timestamp = this.agentLifeCycleHandler.createEventIdentifier(givenSocketId, givenEventCounter);
assertEquals(expectedTimestamp, timestamp);
}
@Test
public void testTimestampOrdering() {
// 0x7fffffff < 0x100000000
long smallerTimestamp = this.agentLifeCycleHandler.createEventIdentifier(0, Integer.MAX_VALUE);
long largerTimestamp = this.agentLifeCycleHandler.createEventIdentifier(1, 0);
assertTrue(smallerTimestamp < largerTimestamp);
}
@Test
public void testInvalidTimestampCreation() {
final int negativeSocketId = new BigInteger("ffffffff", 16).intValue();
final int eventCounter = 0;
try {
this.agentLifeCycleHandler.createEventIdentifier(negativeSocketId, eventCounter);
fail();
} catch (IllegalArgumentException expected) {
// expected
}
final int socketId = 0;
final int negativeEventCounter = new BigInteger("ffffffff", 16).intValue();
try {
this.agentLifeCycleHandler.createEventIdentifier(socketId, negativeEventCounter);
fail();
} catch (IllegalArgumentException expected) {
// expected
}
}
private static Map<Object, Object> createTestChannelProperties() {
return createChannelProperties(TEST_AGENT_ID, TEST_START_TIMESTAMP, TEST_SOCKET_ID);
}
private static Map<Object, Object> createChannelProperties(String agentId, long startTimestamp, int socketId) {
Map<Object, Object> map = new HashMap<>();
map.put(HandshakePropertyType.AGENT_ID.getName(), agentId);
map.put(HandshakePropertyType.START_TIMESTAMP.getName(), startTimestamp);
map.put(AgentLifeCycleHandler.SOCKET_ID_KEY, socketId);
return map;
}
private void runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle managedAgentLifeCycle) {
// given
final AgentLifeCycleState expectedLifeCycleState = managedAgentLifeCycle.getMappedState();
final int expectedEventCounter = managedAgentLifeCycle.getEventCounter();
final long expectedEventIdentifier = this.agentLifeCycleHandler.createEventIdentifier(TEST_SOCKET_ID, expectedEventCounter);
ArgumentCaptor<AgentLifeCycleBo> argCaptor = ArgumentCaptor.forClass(AgentLifeCycleBo.class);
// when
this.agentLifeCycleHandler.handleLifeCycleEvent(this.pinpointServer, TEST_EVENT_TIMESTAMP, expectedLifeCycleState, expectedEventCounter);
verify(this.agentLifeCycleDao, times(1)).insert(argCaptor.capture());
// then
AgentLifeCycleBo actualAgentLifeCycleBo = argCaptor.getValue();
assertEquals(AgentLifeCycleBo.CURRENT_VERSION, actualAgentLifeCycleBo.getVersion());
assertEquals(TEST_AGENT_ID, actualAgentLifeCycleBo.getAgentId());
assertEquals(TEST_START_TIMESTAMP, actualAgentLifeCycleBo.getStartTimestamp());
assertEquals(TEST_EVENT_TIMESTAMP, actualAgentLifeCycleBo.getEventTimestamp());
assertEquals(expectedLifeCycleState, actualAgentLifeCycleBo.getAgentLifeCycleState());
assertEquals(expectedEventIdentifier, actualAgentLifeCycleBo.getEventIdentifier());
}
}