package org.perfcake.common;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.LongAdder;
import java.util.stream.LongStream;
/**
* @author <a href="mailto:marvenec@gmail.com">Martin Večeřa</a>
*/
public class TimeSlidingWindowTest {
@Test
public void slidingWindowTest() throws InterruptedException {
final TimeSlidingWindow<Long> tsw = new TimeSlidingWindow<>(500);
for (int i = 0; i < 10; i++) {
tsw.add(10L);
}
final LongAdder la = new LongAdder();
tsw.forEach(la::add);
Assert.assertEquals(la.longValue(), 10 * 10); // all 10s should be there
Thread.sleep(600);
la.reset();
tsw.forEach(la::add);
Assert.assertEquals(la.longValue(), 0); // everything should be gone
// this takes 1 second
for (int i = 0; i < 10; i++) {
tsw.add(10L);
Thread.sleep(100);
}
la.reset();
tsw.forEach(la::add);
long sum = la.longValue();
Assert.assertTrue(sum > 0 && sum < 100); // there should be just some elements (not all, not empty), ideally 4 * 10
}
@Test
public void artificialSlidingWindowTest() {
final TimeSlidingWindow<Long> tsw = new TimeSlidingWindow<>(500);
for (int i = 1; i <= 10; i++) {
tsw.add((long) i, i * 100);
}
/* Assert.expectThrows(IllegalStateException.class, () -> {
tsw.add(10L, 100); // this should not work
});*/
final LongAdder la = new LongAdder();
tsw.forEach(500, la::add);
Assert.assertEquals(la.longValue(), 1 + 2 + 3 + 4 + 5);
la.reset();
tsw.forEach(601, la::add);
Assert.assertEquals(la.longValue(), 2 + 3 + 4 + 5 + 6);
la.reset();
tsw.forEach(500, la::add);
Assert.assertEquals(la.longValue(), 2 + 3 + 4 + 5); // number 1 was already gc'ed
la.reset();
tsw.forEach(1000, la::add);
Assert.assertEquals(la.longValue(), 5 + 6 + 7 + 8 + 9 + 10);
la.reset();
tsw.forEach(1500, la::add);
Assert.assertEquals(la.longValue(), 10);
la.reset();
tsw.forEach(1501, la::add);
Assert.assertEquals(la.longValue(), 0);
}
@Test
public void backwardsTest() {
final TimeSlidingWindow<Long> tsw = new TimeSlidingWindow<>(500);
for (int i = 10; i >= 1; i--) {
tsw.add((long) i, i * 100);
}
final LongAdder la = new LongAdder();
tsw.forEach(500, la::add);
Assert.assertEquals(la.longValue(), 1 + 2 + 3 + 4 + 5);
la.reset();
tsw.forEach(601, la::add);
Assert.assertEquals(la.longValue(), 2 + 3 + 4 + 5 + 6);
la.reset();
tsw.forEach(500, la::add);
Assert.assertEquals(la.longValue(), 2 + 3 + 4 + 5); // number 1 was already gc'ed
la.reset();
tsw.forEach(1000, la::add);
Assert.assertEquals(la.longValue(), 5 + 6 + 7 + 8 + 9 + 10);
la.reset();
tsw.forEach(1500, la::add);
Assert.assertEquals(la.longValue(), 10);
la.reset();
tsw.forEach(1501, la::add);
Assert.assertEquals(la.longValue(), 0);
}
@Test
public void randomAccessTest() {
final long count = 1000;
final List<Long> roller = new ArrayList<>((int) count);
LongStream.range(0, count).forEach(roller::add);
final Random r = new Random();
final TimeSlidingWindow<Long> tsw = new TimeSlidingWindow<>(count);
while (roller.size() > 0) {
final int index = r.nextInt(roller.size());
final Long l = roller.get(index);
roller.remove(index);
tsw.add(l, l);
}
final LongAdder la = new LongAdder();
tsw.forEach(count, la::add);
final long checksum = (count * (count - 1)) / 2;
Assert.assertEquals(la.longValue(), checksum);
}
}