use of com.linkedin.test.util.ClockedExecutor in project rest.li by linkedin.
the class TestRampUpRateLimiter method testRampDownImmediately.
@Test(timeOut = TEST_TIMEOUT)
public void testRampDownImmediately() {
ClockedExecutor clockedExecutor = new ClockedExecutor();
RampUpRateLimiter rateLimiter = new RampUpRateLimiterImpl(new SmoothRateLimiter(clockedExecutor, clockedExecutor, clockedExecutor, _queue, Integer.MAX_VALUE, SmoothRateLimiter.BufferOverflowMode.DROP, RATE_LIMITER_NAME_TEST), clockedExecutor);
rateLimiter.setRate(1000d, ONE_SECOND_PERIOD, MINIMUM_BURST);
List<FutureCallback<None>> callbacks = new ArrayList<>();
IntStream.range(0, 1002).forEach(i -> {
FutureCallback<None> callback = new FutureCallback<>();
rateLimiter.submit(callback);
callbacks.add(callback);
});
// -1 because if it passes a full second, the new batch of permits will be issued
clockedExecutor.runFor(ONE_SECOND_PERIOD - 1);
IntStream.range(0, 1000).forEach(i -> assertTrue(callbacks.get(i).isDone()));
IntStream.range(1000, 1002).forEach(i -> assertFalse(callbacks.get(i).isDone(), i + " should not have been executed"));
rateLimiter.setRate(1, ONE_SECOND_PERIOD, 1, Integer.MAX_VALUE);
clockedExecutor.runFor(ONE_SECOND_PERIOD);
IntStream.range(1000, 1001).forEach(i -> assertTrue(callbacks.get(i).isDone()));
IntStream.range(1001, 1002).forEach(i -> assertFalse(callbacks.get(i).isDone(), i + " should not have been executed"));
clockedExecutor.runFor(ONE_SECOND_PERIOD);
IntStream.range(1001, 1002).forEach(i -> assertTrue(callbacks.get(i).isDone()));
}
use of com.linkedin.test.util.ClockedExecutor in project rest.li by linkedin.
the class TestConstantQpsRateLimiter method ensureRandomButConstantRate.
@Test
public void ensureRandomButConstantRate() {
ClockedExecutor executor = new ClockedExecutor();
ClockedExecutor circularBufferExecutor = new ClockedExecutor();
ConstantQpsRateLimiter rateLimiter = new ConstantQpsRateLimiter(executor, executor, executor, TestEvictingCircularBuffer.getBuffer(circularBufferExecutor));
rateLimiter.setRate(200d, ONE_SECOND, 1);
rateLimiter.setBufferCapacity(1);
TattlingCallback<None> tattler = new TattlingCallback<>(executor);
rateLimiter.submit(tattler);
executor.runFor(ONE_SECOND * TEST_NUM_CYCLES);
long prevTime = 0;
List<Long> timeDeltas = new ArrayList<>();
for (Long stamp : tattler.getOccurrences()) {
timeDeltas.add(stamp - prevTime);
prevTime = stamp;
}
// Ensure variance up to 10 possible time deltas given a rate of 200 requests per second
Set<Long> uniqueTimeDeltas = new HashSet<>(timeDeltas);
assert (uniqueTimeDeltas.size() > 8 && uniqueTimeDeltas.size() < 11);
}
use of com.linkedin.test.util.ClockedExecutor in project rest.li by linkedin.
the class TestConstantQpsRateLimiter method lowNonWholeRate.
@Test(timeOut = TEST_TIMEOUT)
public void lowNonWholeRate() {
for (int i = 0; i < TEST_NUM_CYCLES; i++) {
ClockedExecutor executor = new ClockedExecutor();
ClockedExecutor circularBufferExecutor = new ClockedExecutor();
ConstantQpsRateLimiter rateLimiter = new ConstantQpsRateLimiter(executor, executor, executor, TestEvictingCircularBuffer.getBuffer(circularBufferExecutor));
rateLimiter.setRate(TEST_LOW_FRACTIONAL_QPS, ONE_SECOND, UNLIMITED_BURST);
rateLimiter.setBufferCapacity(1);
TattlingCallback<None> tattler = new TattlingCallback<>(executor);
rateLimiter.submit(tattler);
// run for enough time such that 3 queries are sent
executor.runFor((int) (((ONE_SECOND / TEST_LOW_FRACTIONAL_QPS) * 3) - 1));
Assert.assertTrue(tattler.getInteractCount() == 3);
}
}
use of com.linkedin.test.util.ClockedExecutor in project rest.li by linkedin.
the class SimpleLoadBalancerStateTest method reset.
public void reset(boolean useSSL, boolean enableRelativeLoadBalancer) {
_executorService = new SynchronousExecutorService();
_uriRegistry = new MockStore<>();
_clusterRegistry = new MockStore<>();
_serviceRegistry = new MockStore<>();
_clientFactories = new HashMap<>();
_loadBalancerStrategyFactories = new HashMap<>();
if (enableRelativeLoadBalancer) {
_loadBalancerStrategyFactories.put(RelativeLoadBalancerStrategy.RELATIVE_LOAD_BALANCER_STRATEGY_NAME, new RelativeLoadBalancerStrategyFactory(new ClockedExecutor(), null, Collections.emptyList(), new NoopEventEmitter(), SystemClock.instance()));
}
_loadBalancerStrategyFactories.put("random", new RandomLoadBalancerStrategyFactory());
_loadBalancerStrategyFactories.put("degraderV3", new DegraderLoadBalancerStrategyFactoryV3());
_loadBalancerStrategyFactories.put(DegraderLoadBalancerStrategyV3.DEGRADER_STRATEGY_NAME, new DegraderLoadBalancerStrategyFactoryV3());
try {
_sslContext = SSLContext.getDefault();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
_sslParameters = new SSLParameters();
if (useSSL) {
_clientFactories.put("https", new SimpleLoadBalancerTest.DoNothingClientFactory());
_state = new SimpleLoadBalancerState(_executorService, new PropertyEventBusImpl<>(_executorService, _uriRegistry), new PropertyEventBusImpl<>(_executorService, _clusterRegistry), new PropertyEventBusImpl<>(_executorService, _serviceRegistry), _clientFactories, _loadBalancerStrategyFactories, _sslContext, _sslParameters, true, null, SSL_SESSION_VALIDATOR_FACTORY);
} else {
_clientFactories.put("http", new SimpleLoadBalancerTest.DoNothingClientFactory());
_state = new SimpleLoadBalancerState(_executorService, _uriRegistry, _clusterRegistry, _serviceRegistry, _clientFactories, _loadBalancerStrategyFactories);
}
FutureCallback<None> callback = new FutureCallback<>();
_state.start(callback);
try {
callback.get();
} catch (Exception e) {
Assert.fail("State start failed", e);
}
}
use of com.linkedin.test.util.ClockedExecutor in project rest.li by linkedin.
the class TestConstantQpsDarkClusterStrategy method testStrategy.
@Test(dataProvider = "qpsKeys")
public void testStrategy(int duration, float inboundQps, float outboundQps, int numSourceInstances, int numDarkInstances) {
IntStream.of(1, 1000, 1000000).forEach(capacity -> {
DarkClusterDispatcher darkClusterDispatcher = new DefaultDarkClusterDispatcher(new MockClient(false));
ClockedExecutor executor = new ClockedExecutor();
Supplier<ConstantQpsRateLimiter> uniqueRateLimiterSupplier = () -> {
EvictingCircularBuffer uniqueBuffer = TestConstantQpsDarkClusterStrategy.getBuffer(executor);
ConstantQpsRateLimiter limiter = new ConstantQpsRateLimiter(executor, executor, executor, uniqueBuffer);
limiter.setBufferCapacity(capacity);
limiter.setBufferTtl(Integer.MAX_VALUE, ChronoUnit.DAYS);
return limiter;
};
ConstantQpsRateLimiter sharedRateLimiter = uniqueRateLimiterSupplier.get();
Supplier<ConstantQpsRateLimiter> sharedRateLimiterSupplier = () -> sharedRateLimiter;
MockClusterInfoProvider mockClusterInfoProvider = new MockClusterInfoProvider();
mockClusterInfoProvider.putHttpsClusterCount(SOURCE_CLUSTER_NAME, numSourceInstances);
// dark cluster 1
BaseDarkClusterDispatcherImpl baseDispatcherOne = new BaseDarkClusterDispatcherImpl(DARK_CLUSTER_NAME_ONE, darkClusterDispatcher, new DoNothingNotifier(), new CountingVerifierManager());
mockClusterInfoProvider.putHttpsClusterCount(DARK_CLUSTER_NAME_ONE, numDarkInstances);
ConstantQpsRateLimiter rateLimiterOne = sharedRateLimiterSupplier.get();
// dark cluster 2
BaseDarkClusterDispatcherImpl baseDispatcherTwo = new BaseDarkClusterDispatcherImpl(DARK_CLUSTER_NAME_TWO, darkClusterDispatcher, new DoNothingNotifier(), new CountingVerifierManager());
mockClusterInfoProvider.putHttpsClusterCount(DARK_CLUSTER_NAME_TWO, numDarkInstances);
ConstantQpsRateLimiter rateLimiterTwo = sharedRateLimiterSupplier.get();
// dark cluster 3
BaseDarkClusterDispatcherImpl baseDispatcherThree = new BaseDarkClusterDispatcherImpl(DARK_CLUSTER_NAME_THREE, darkClusterDispatcher, new DoNothingNotifier(), new CountingVerifierManager());
mockClusterInfoProvider.putHttpsClusterCount(DARK_CLUSTER_NAME_THREE, numDarkInstances);
ConstantQpsRateLimiter rateLimiterThree = uniqueRateLimiterSupplier.get();
List<ConstantQpsDarkClusterStrategy> strategies = new ArrayList<>();
strategies.add(new ConstantQpsDarkClusterStrategy(SOURCE_CLUSTER_NAME, DARK_CLUSTER_NAME_ONE, outboundQps, baseDispatcherOne, new DoNothingNotifier(), mockClusterInfoProvider, rateLimiterOne));
strategies.add(new ConstantQpsDarkClusterStrategy(SOURCE_CLUSTER_NAME, DARK_CLUSTER_NAME_TWO, outboundQps, baseDispatcherTwo, new DoNothingNotifier(), mockClusterInfoProvider, rateLimiterTwo));
strategies.add(new ConstantQpsDarkClusterStrategy(SOURCE_CLUSTER_NAME, DARK_CLUSTER_NAME_THREE, outboundQps, baseDispatcherThree, new DoNothingNotifier(), mockClusterInfoProvider, rateLimiterThree));
// simulate receiving the configured qps while dispatching over the duration
int msBetweenEachInboundRequest = (int) (1000 / inboundQps);
for (int runTime = 0; runTime < duration; runTime = runTime + msBetweenEachInboundRequest) {
RestRequest dummyRestRequest = new RestRequestBuilder(URI.create("foo")).build();
for (ConstantQpsDarkClusterStrategy strategy : strategies) {
strategy.handleRequest(dummyRestRequest, dummyRestRequest, new RequestContext());
}
executor.runFor(msBetweenEachInboundRequest);
}
double validation = ((duration == 0 ? 0 : duration / 1000.0) * outboundQps * numDarkInstances) / (double) (numSourceInstances);
// Cluster One and Two share a rate limiter, so their combined QPS should match the expected value.
int actualCountClusterOne = baseDispatcherOne.getRequestCount();
int actualCountClusterTwo = baseDispatcherTwo.getRequestCount();
int expectedCountClusterOneAndTwo = (int) validation;
Assert.assertEquals(actualCountClusterOne + actualCountClusterTwo, expectedCountClusterOneAndTwo, expectedCountClusterOneAndTwo * ERR_PCT, "count not within expected range");
// Cluster Three uses its own so it matches the expected value on its own.
int expectedCountClusterThree = (int) validation;
int actualCountClusterThree = baseDispatcherThree.getRequestCount();
Assert.assertEquals(actualCountClusterThree, expectedCountClusterThree, expectedCountClusterThree * ERR_PCT, "count not within expected range");
});
}
Aggregations