/*
* Copyright 2016 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.web.mapper.stat;
import com.navercorp.pinpoint.common.buffer.Buffer;
import com.navercorp.pinpoint.common.hbase.HBaseTables;
import com.navercorp.pinpoint.common.hbase.distributor.RangeOneByteSimpleHash;
import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatCodec;
import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatDecoder;
import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatEncoder;
import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatDecodingContext;
import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory;
import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatRowKeyDecoder;
import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatRowKeyEncoder;
import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatSerializer;
import com.navercorp.pinpoint.common.server.bo.stat.AgentStatDataPoint;
import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType;
import com.navercorp.pinpoint.web.mapper.TimestampFilter;
import com.sematext.hbase.wd.AbstractRowKeyDistributor;
import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
/**
* @author HyunGil Jeong
*/
public class AgentStatMapperV2Test {
private static final String AGENT_ID = "testAgent";
private static final AgentStatType AGENT_STAT_TYPE = AgentStatType.UNKNOWN;
private static final long COLLECT_INVERVAL = 5000L;
private static final Random RANDOM = new Random();
private static final TimestampFilter TEST_FILTER = new TimestampFilter() {
@Override
public boolean filter(long timestamp) {
return false;
}
};
private final AgentStatRowKeyEncoder rowKeyEncoder = new AgentStatRowKeyEncoder();
private final AgentStatRowKeyDecoder rowKeyDecoder = new AgentStatRowKeyDecoder();
private final AbstractRowKeyDistributor rowKeyDistributor = new RowKeyDistributorByHashPrefix(
new RangeOneByteSimpleHash(0, 33, 64));
private final AgentStatHbaseOperationFactory hbaseOperationFactory = new AgentStatHbaseOperationFactory(
this.rowKeyEncoder, this.rowKeyDecoder, this.rowKeyDistributor);
private final AgentStatCodec<TestAgentStat> codec = new TestAgentStatCodec();
private final AgentStatEncoder<TestAgentStat> encoder = new TestAgentStatEncoder(this.codec);
private final AgentStatDecoder<TestAgentStat> decoder = new TestAgentStatDecoder(this.codec);
private final AgentStatSerializer<TestAgentStat> serializer = new TestAgentStatSerializer(this.encoder);
@Test
public void mapperTest() throws Exception {
// Given
List<TestAgentStat> givenAgentStats = new ArrayList<>();
List<Put> puts = new ArrayList<>();
long initialTimestamp = System.currentTimeMillis();
int numBatch = RANDOM.nextInt(10) + 1;
for (int i = 0; i < numBatch; ++i) {
int batchSize = RANDOM.nextInt(10) + 1;
List<TestAgentStat> agentStatBatch = createAgentStats(initialTimestamp, COLLECT_INVERVAL, batchSize);
givenAgentStats.addAll(agentStatBatch);
puts.addAll(this.hbaseOperationFactory.createPuts(AGENT_ID, AGENT_STAT_TYPE, agentStatBatch, this.serializer));
initialTimestamp += batchSize * COLLECT_INVERVAL;
}
List<Cell> cellsToPut = new ArrayList<>();
for (Put put : puts) {
List<Cell> cells = put.getFamilyCellMap().get(HBaseTables.AGENT_STAT_CF_STATISTICS);
cellsToPut.addAll(cells);
}
Result result = Result.create(cellsToPut);
// When
AgentStatMapperV2<TestAgentStat> mapper = new AgentStatMapperV2<>(this.hbaseOperationFactory, this.decoder, TEST_FILTER);
List<TestAgentStat> mappedAgentStats = mapper.mapRow(result, 0);
// Then
Collections.sort(givenAgentStats, AgentStatMapperV2.REVERSE_TIMESTAMP_COMPARATOR);
Assert.assertEquals(givenAgentStats, mappedAgentStats);
}
private List<TestAgentStat> createAgentStats(long initialTimestamp, long interval, int batchSize) {
List<TestAgentStat> agentStats = new ArrayList<>(batchSize);
for (int i = 0; i < batchSize; ++i) {
long timestamp = initialTimestamp + (interval * i);
TestAgentStat agentStat = new TestAgentStat();
agentStat.setAgentId(AGENT_ID);
agentStat.setTimestamp(timestamp);
agentStat.setValue(RANDOM.nextLong());
agentStats.add(agentStat);
}
return agentStats;
}
private static class TestAgentStatCodec implements AgentStatCodec<TestAgentStat> {
@Override
public byte getVersion() {
return 0;
}
@Override
public void encodeValues(Buffer valueBuffer, List<TestAgentStat> agentStats) {
valueBuffer.putInt(agentStats.size());
for (TestAgentStat agentStat : agentStats) {
valueBuffer.putLong(agentStat.getTimestamp());
valueBuffer.putLong(agentStat.getValue());
}
}
@Override
public List<TestAgentStat> decodeValues(Buffer valueBuffer, AgentStatDecodingContext decodingContext) {
int size = valueBuffer.readInt();
List<TestAgentStat> agentStats = new ArrayList<>(size);
for (int i = 0; i < size; ++i) {
TestAgentStat agentStat = new TestAgentStat();
agentStat.setAgentId(decodingContext.getAgentId());
agentStat.setTimestamp(valueBuffer.readLong());
agentStat.setValue(valueBuffer.readLong());
agentStats.add(agentStat);
}
return agentStats;
}
}
private static class TestAgentStatEncoder extends AgentStatEncoder<TestAgentStat> {
protected TestAgentStatEncoder(AgentStatCodec<TestAgentStat> codec) {
super(codec);
}
}
private static class TestAgentStatDecoder extends AgentStatDecoder<TestAgentStat> {
protected TestAgentStatDecoder(AgentStatCodec<TestAgentStat> codec) {
super(Arrays.asList(codec));
}
}
private static class TestAgentStatSerializer extends AgentStatSerializer<TestAgentStat> {
protected TestAgentStatSerializer(AgentStatEncoder<TestAgentStat> encoder) {
super(encoder);
}
}
private static class TestAgentStat implements AgentStatDataPoint {
private String agentId;
private long startTimestamp;
private long timestamp;
private long value;
@Override
public String getAgentId() {
return this.agentId;
}
@Override
public void setAgentId(String agentId) {
this.agentId = agentId;
}
@Override
public long getStartTimestamp() {
return startTimestamp;
}
@Override
public void setStartTimestamp(long startTimestamp) {
this.startTimestamp = startTimestamp;
}
@Override
public long getTimestamp() {
return this.timestamp;
}
@Override
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public long getValue() {
return this.value;
}
public void setValue(long value) {
this.value = value;
}
@Override
public AgentStatType getAgentStatType() {
return AGENT_STAT_TYPE;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestAgentStat that = (TestAgentStat) o;
if (startTimestamp != that.startTimestamp) return false;
if (timestamp != that.timestamp) return false;
if (value != that.value) return false;
return agentId != null ? agentId.equals(that.agentId) : that.agentId == null;
}
@Override
public int hashCode() {
int result = agentId != null ? agentId.hashCode() : 0;
result = 31 * result + (int) (startTimestamp ^ (startTimestamp >>> 32));
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
result = 31 * result + (int) (value ^ (value >>> 32));
return result;
}
@Override
public String toString() {
return "TestAgentStat{" +
"agentId='" + agentId + '\'' +
", startTimestamp=" + startTimestamp +
", timestamp=" + timestamp +
", value=" + value +
'}';
}
}
}