/*
* Copyright 2015-2016 the original author or authors.
*
* 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 org.glowroot.common.model;
import org.junit.Test;
import org.glowroot.common.model.LazyHistogram.ScratchBuffer;
import org.glowroot.wire.api.model.AggregateOuterClass.Aggregate;
import static org.assertj.core.api.Assertions.assertThat;
public class LazyHistogramTest {
@Test
public void shouldTestPercentiles() {
// test smaller numbers in more detail since that is where laziness occurs
for (int i = 0; i < 2000000; i += 10000) {
shouldTestPercentiles(i);
}
shouldTestPercentiles(10000000);
shouldTestPercentiles(100000000);
}
@Test
public void shouldTestEncodeDecode() throws Exception {
// test smaller numbers in more detail since that is where laziness occurs
for (int i = 0; i < 2000000; i += 10000) {
shouldTestEncodeDecode(i);
}
shouldTestEncodeDecode(10000000);
shouldTestEncodeDecode(100000000);
}
@Test
public void shouldTestEncodeDecodeAndAddMore() throws Exception {
// test smaller numbers in more detail since that is where laziness occurs
for (int i = 0; i < 2000000; i += 10000) {
shouldTestEncodeDecodeAndAddMore(i);
}
shouldTestEncodeDecodeAndAddMore(10000000);
shouldTestEncodeDecodeAndAddMore(100000000);
}
@Test
public void shouldTestDecodeOnTopOfExisting() throws Exception {
// test smaller numbers in more detail since that is where laziness occurs
for (int i = 0; i < 2000000; i += 10000) {
shouldDecodeOnTopOfExisting(i, i);
}
shouldDecodeOnTopOfExisting(10000000, 10000000);
shouldDecodeOnTopOfExisting(100000000, 100000000);
// test smaller numbers in more detail since that is where laziness occurs
for (int i = 0; i < 2000000; i += 10000) {
shouldDecodeOnTopOfExisting(2 * i, i);
}
shouldDecodeOnTopOfExisting(20000000, 10000000);
shouldDecodeOnTopOfExisting(200000000, 100000000);
// test smaller numbers in more detail since that is where laziness occurs
for (int i = 0; i < 2000000; i += 10000) {
shouldDecodeOnTopOfExisting(i, 2 * i);
}
shouldDecodeOnTopOfExisting(10000000, 20000000);
shouldDecodeOnTopOfExisting(100000000, 200000000);
}
private void shouldTestPercentiles(int num) {
// given
LazyHistogram lazyHistogram = new LazyHistogram();
// when
for (int i = num; i > 0; i -= 1000) {
lazyHistogram.add(i);
}
// then
assertPercentile(lazyHistogram, num, 50);
assertPercentile(lazyHistogram, num, 95);
assertPercentile(lazyHistogram, num, 99);
assertPercentile(lazyHistogram, num, 99.9);
assertPercentile(lazyHistogram, num, 99.99);
}
private void shouldTestEncodeDecode(int num) throws Exception {
// given
LazyHistogram lazyHistogram = new LazyHistogram();
for (int i = num; i > 0; i -= 1000) {
lazyHistogram.add(i);
}
Aggregate.Histogram histogram = lazyHistogram.toProto(new ScratchBuffer());
lazyHistogram = new LazyHistogram();
// when
lazyHistogram.merge(histogram);
// then
assertPercentile(lazyHistogram, num, 50);
assertPercentile(lazyHistogram, num, 95);
assertPercentile(lazyHistogram, num, 99);
assertPercentile(lazyHistogram, num, 99.9);
assertPercentile(lazyHistogram, num, 99.99);
}
private void shouldTestEncodeDecodeAndAddMore(int num) throws Exception {
// given
LazyHistogram lazyHistogram = new LazyHistogram();
for (int i = num; i > 0; i -= 1000) {
lazyHistogram.add(i);
}
Aggregate.Histogram histogram = lazyHistogram.toProto(new ScratchBuffer());
lazyHistogram = new LazyHistogram();
// when
lazyHistogram.merge(histogram);
for (int i = 2 * num; i > num; i -= 1000) {
lazyHistogram.add(i);
}
// then
assertPercentile(lazyHistogram, num * 2, 50);
assertPercentile(lazyHistogram, num * 2, 95);
assertPercentile(lazyHistogram, num * 2, 99);
assertPercentile(lazyHistogram, num * 2, 99.9);
assertPercentile(lazyHistogram, num * 2, 99.99);
}
private void shouldDecodeOnTopOfExisting(int encodedSize, int nonEncodedSize) throws Exception {
// given
LazyHistogram lazyHistogram = new LazyHistogram();
for (int i = encodedSize; i > 0; i -= 1000) {
lazyHistogram.add(i);
}
Aggregate.Histogram histogram = lazyHistogram.toProto(new ScratchBuffer());
lazyHistogram = new LazyHistogram();
// when
for (int i = nonEncodedSize + encodedSize; i > encodedSize; i -= 1000) {
lazyHistogram.add(i);
}
lazyHistogram.merge(histogram);
// then
assertPercentile(lazyHistogram, encodedSize + nonEncodedSize, 50);
assertPercentile(lazyHistogram, encodedSize + nonEncodedSize, 95);
assertPercentile(lazyHistogram, encodedSize + nonEncodedSize, 99);
assertPercentile(lazyHistogram, encodedSize + nonEncodedSize, 99.9);
assertPercentile(lazyHistogram, encodedSize + nonEncodedSize, 99.99);
}
private void assertPercentile(LazyHistogram lazyHistogram, int num, double percentile) {
long low = (long) Math.floor(num * percentile * 0.99 / (100 * 1000)) * 1000;
long high = (long) Math.ceil(num * percentile * 1.01 / (100 * 1000)) * 1000;
assertThat(lazyHistogram.getValueAtPercentile(percentile)).isBetween(low, high);
}
}