/** * Copyright 2012 Comcast Corporation * * 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.comcast.cmb.test.common.util.unit; import static org.junit.Assert.*; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.comcast.cmb.common.controller.CMBControllerServlet; import com.comcast.cmb.common.util.ExpiringCache; import com.comcast.cmb.common.util.Util; import com.comcast.cmb.common.util.ExpiringCache.CacheFullException; public class ExpiringCacheTest { private static Logger log = Logger.getLogger(ExpiringCacheTest.class); @Before public void setup() throws Exception { Util.initLog4jTest(); CMBControllerServlet.valueAccumulator.initializeAllCounters(); } static class TestCallable implements Callable<Integer> { volatile int numTimesCalled = 0; @Override public Integer call() throws Exception { log.debug("getting called"); numTimesCalled++; return 1; } } @Test public void testSetGetCache() throws Exception { ExpiringCache<String, Integer> cache = new ExpiringCache<String, Integer>(1000); TestCallable c = new TestCallable(); Integer i = cache.getAndSetIfNotPresent("test", c, 1000); if (i != 1) { fail("Expected 1 got:" + i); } if (c.numTimesCalled != 1) { fail("Expected to have called the callable once. got num=" + c.numTimesCalled); } i = cache.getAndSetIfNotPresent("test", c, 1000); if (c.numTimesCalled != 1) { fail("Expected to have called the callable once. got num=" + c.numTimesCalled); } //check expiration Thread.sleep(1001); i = cache.getAndSetIfNotPresent("test", c, 1000); if (c.numTimesCalled != 2) { fail("Expected to have called the callable 2. got num=" + c.numTimesCalled); } } class TestRunnable implements Runnable { final ExpiringCache<Integer, Integer> cache; final TestCallable c; final boolean sleep; public volatile boolean done = false; public volatile int count = 0; public TestRunnable(ExpiringCache<Integer, Integer> cache, TestCallable c, boolean sleep) { this.cache = cache; this.c = c; this.sleep = sleep; } @Override public void run() { log.info("checking thread-state"); while(!Thread.interrupted() && !done) { try { cache.getAndSetIfNotPresent(1, c, 1000); count++; } catch (CacheFullException e1) { log.error("Cache too small"); } if (sleep) { try { Thread.sleep(100); } catch (InterruptedException e) { log.error("Could not sleep thread"); } } } } } @Test public void testConcurrentCacheGetsSets() throws Exception { ExecutorService e = Executors.newFixedThreadPool(10); final TestCallable c = new TestCallable(); final ExpiringCache<Integer, Integer> cache = new ExpiringCache<Integer, Integer>(1000); TestRunnable arr[] = new TestRunnable[10]; for (int i = 0; i < 10; i++) { arr[i] = new TestRunnable(cache, c, true); e.execute(arr[i]); } Thread.sleep(10000); for (TestRunnable r : arr) { r.done = true; } e.shutdown(); e.awaitTermination(2, TimeUnit.SECONDS); //check that there were only 10 calls to TestCallable in 10 seconds. if (c.numTimesCalled > 12) { fail("Expected to only have 10 calls in 10 seconds. Got:" + c.numTimesCalled); } } @Test public void testContains() throws Exception { final ExpiringCache<Integer, Integer> cache = new ExpiringCache<Integer, Integer>(1000); final TestCallable c = new TestCallable(); cache.getAndSetIfNotPresent(1, c, 100); if (!cache.containsKey(1)) { fail("Expected to find key 1 in cache. DIdn't get it"); } Thread.sleep(101); if (cache.containsKey(1)) { fail("Expected to Not find key 1 in cache after 100 ms. DId get it"); } } @Test public void test() throws Exception { ConcurrentHashMap<String, String> c = new ConcurrentHashMap<String, String>(); c.put("a", "a"); c.replace("a", "a", "b"); } @Test public void testThroughput() throws Exception { ExecutorService e = Executors.newFixedThreadPool(10); final TestCallable c = new TestCallable(); final ExpiringCache<Integer, Integer> cache = new ExpiringCache<Integer, Integer>(1000); long ts1 = System.currentTimeMillis(); TestRunnable arr[] = new TestRunnable[10]; for (int i = 0; i < 10; i++) { arr[i] = new TestRunnable(cache, c, false); e.execute(arr[i]); } Thread.sleep(10000); for (TestRunnable r : arr) { r.done = true; } e.shutdown(); e.awaitTermination(2, TimeUnit.SECONDS); long ts2 = System.currentTimeMillis(); long numCalled = 0; for (int i = 0; i < 10; i++) { numCalled += arr[i].count; } System.out.println("throughput=" + ((numCalled / (ts2-ts1))*1000) + "gets/sec" ) ; } @After public void tearDown() { CMBControllerServlet.valueAccumulator.deleteAllCounters(); } }