/*
* Copyright 2014 Google Inc. All rights reserved.
*
*
* 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.google.maps.internal;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.google.maps.MediumTests;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.AbstractMap;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@Category(MediumTests.class)
public class RateLimitExecutorServiceTest {
private static final Logger LOG = LoggerFactory.getLogger(RateLimitExecutorServiceTest.class.getName());
@Test
public void testRateLimitDoesNotExceedSuppliedQps() throws Exception {
int qps = 10;
RateLimitExecutorService service = new RateLimitExecutorService();
service.setQueriesPerSecond(qps, 50);
final ConcurrentHashMap<Integer, Integer> executedTimestamps = new ConcurrentHashMap<Integer, Integer>();
for (int i = 0; i < 100; i++) {
Runnable emptyTask = new Runnable() {
@Override
public void run() {
int nearestSecond = (int) (new Date().getTime() / 1000);
if (executedTimestamps.containsKey(nearestSecond)) {
executedTimestamps.put(nearestSecond, executedTimestamps.get(nearestSecond) + 1);
} else {
executedTimestamps.put(nearestSecond, 1);
}
}
};
service.execute(emptyTask);
}
// Sleep until finished, or 20s expires (to prevent waiting forever)
long sleepTime = 0;
while (sleepTime < 20000 && countTotalRequests(executedTimestamps) < 100) {
long sleepFor = TimeUnit.SECONDS.toMillis(1);
sleepTime += sleepFor;
Thread.sleep(sleepFor);
}
// Check that we executed at the correct rate
for (Integer timestamp : executedTimestamps.keySet()) {
Integer actualQps = executedTimestamps.get(timestamp);
// Logging QPS here to detect if a previous iteration had qps-1 and this is qps+1.
LOG.info(String.format("Timestamp(%d) logged %d queries (target of %d qps)",
timestamp, actualQps, qps));
assertTrue(String.format("Expected <= %d queries in a second, got %d.", qps, actualQps),
actualQps <= qps);
}
// Check that we executed every request
// TODO(brettmorgan): figure out where we are losing requests
//assertEquals(100, countTotalRequests(executedTimestamps));
service.shutdown();
}
private static int countTotalRequests(AbstractMap<?, Integer> hashMap) {
int counter = 0;
for (Integer value : hashMap.values()) {
counter += value;
}
return counter;
}
}