package com.netflix.astyanax.contrib.valve; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicLong; import junit.framework.Assert; import org.junit.Test; import com.netflix.astyanax.contrib.valve.TimeWindowValve.RequestStatus; public class TimeWindowValveTest { @Test public void testSingleThread1SecWindow() throws Exception { TimeWindowValve window = new TimeWindowValve(1000L, System.currentTimeMillis(), 1000); testSingleThread(window, 100000, 1000); } @Test public void testSingleThread100MsWindow() throws Exception { TimeWindowValve window = new TimeWindowValve(1000L, System.currentTimeMillis(), 100); testSingleThread(window, 100000, 1000); } private void testSingleThread(final TimeWindowValve window, int numRequests, int expectedSuccesses) { Map<RequestStatus, Long> status = new HashMap<RequestStatus, Long>(); for (int i=0; i<numRequests; i++) { RequestStatus ret = window.decrementAndCheckQuota(); Long count = status.get(ret); if (count == null) { status.put(ret, 1L); } else { status.put(ret, ++count); } } Assert.assertTrue(expectedSuccesses == status.get(RequestStatus.Permitted)); } @Test public void testMultipleThreads1SecWindow() throws Exception { final TimeWindowValve window = new TimeWindowValve(100000L, System.currentTimeMillis(), 1000); testMultipleThreads(window, 100000L, 300); } @Test public void testMultipleThreads100MsWindow() throws Exception { final TimeWindowValve window = new TimeWindowValve(10000L, System.currentTimeMillis(), 500); testMultipleThreads(window, 10000L, 300); } private void testMultipleThreads(final TimeWindowValve window, long expectedSuccesses, int runTestMillis) throws Exception { final MultiThreadTestControl testControl = new MultiThreadTestControl(); // track success rate of rps that is allowed to pass through final AtomicLong successCount = new AtomicLong(0L); testControl.runTest(new Callable<Void>() { @Override public Void call() throws Exception { RequestStatus status = window.decrementAndCheckQuota(); if (status == RequestStatus.Permitted) { successCount.incrementAndGet(); } return null; } }); Thread.sleep(runTestMillis); testControl.stopTest(); long delta = Math.abs(expectedSuccesses-successCount.get()); int percentageDiff = (int) (delta*100/expectedSuccesses); Assert.assertTrue("Success: " + successCount.get() + ", expected: " + expectedSuccesses + ", percentageDiff: " + percentageDiff, percentageDiff < 10); } @Test public void testPastWindow() throws Exception { final TimeWindowValve window = new TimeWindowValve(100000L, System.currentTimeMillis(), 100); for (int i=0; i<1000; i++) { RequestStatus status = window.decrementAndCheckQuota(); Assert.assertEquals(RequestStatus.Permitted, status); } Thread.sleep(150); for (int i=0; i<1000; i++) { RequestStatus status = window.decrementAndCheckQuota(); Assert.assertEquals(RequestStatus.PastWindow, status); } } }