001: /*
002: * Copyright (c) 2002-2003 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.oscache.base;
006:
007: import java.util.Properties;
008:
009: import com.opensymphony.oscache.general.GeneralCacheAdministrator;
010:
011: import junit.framework.Assert;
012: import junit.framework.Test;
013: import junit.framework.TestCase;
014: import junit.framework.TestSuite;
015:
016: /**
017: * Test the public methods of the Cache class
018: *
019: * $Id: TestCache.java 385 2006-10-07 06:57:10Z larst $
020: * @version $Revision: 385 $
021: * @author <a href="mailto:abergevin@pyxis-tech.com">Alain Bergevin</a>
022: */
023: public class TestCache extends TestCase {
024: // Static variables required thru all the tests
025: private static Cache map = null;
026: private final String CONTENT = "Content for the cache test";
027:
028: // Constants needed thru all the tests
029: private final String ENTRY_KEY = "Test cache key";
030: private final int NO_REFRESH_NEEDED = CacheEntry.INDEFINITE_EXPIRY;
031: private final int REFRESH_NEEDED = 0;
032:
033: /**
034: * Class constructor.
035: * <p>
036: * @param str The test name (required by JUnit)
037: */
038: public TestCache(String str) {
039: super (str);
040: }
041:
042: /**
043: * This method is invoked before each testXXXX methods of the
044: * class. It set ups the variables required for each tests.
045: */
046: public void setUp() {
047: // At first invocation, create a new Cache
048: if (map == null) {
049: GeneralCacheAdministrator admin = new GeneralCacheAdministrator();
050: map = admin.getCache();
051: assertNotNull(map);
052: }
053: }
054:
055: /**
056: * This methods returns the name of this test class to JUnit
057: * <p>
058: * @return The name of this class
059: */
060: public static Test suite() {
061: return new TestSuite(TestCache.class);
062: }
063:
064: /**
065: * Verify that items may still be flushed by key pattern
066: */
067: public void testFlushPattern() {
068: // Try to flush with a bad pattern and ensure that our data is still there
069: map.putInCache(ENTRY_KEY, CONTENT);
070: map.flushPattern(ENTRY_KEY + "do not flush");
071: getBackContent(map, CONTENT, NO_REFRESH_NEEDED, false);
072:
073: // Flush our map for real
074: map.flushPattern(ENTRY_KEY.substring(1, 2));
075: getBackContent(map, CONTENT, NO_REFRESH_NEEDED, true);
076:
077: // Check invalid values
078: map.flushPattern("");
079: map.flushPattern(null);
080: }
081:
082: /**
083: * Tests that with a very large amount of keys that added and trigger cache overflows, there is no memory leak
084: * @throws Exception
085: */
086: public void testBug174CacheOverflow() throws Exception {
087:
088: Properties p = new Properties();
089: p.setProperty(AbstractCacheAdministrator.CACHE_ALGORITHM_KEY,
090: "com.opensymphony.oscache.base.algorithm.LRUCache");
091: p.setProperty(AbstractCacheAdministrator.CACHE_CAPACITY_KEY,
092: "100");
093: GeneralCacheAdministrator admin = new GeneralCacheAdministrator(
094: p);
095:
096: int cacheCapacity = 100;
097: int maxAddedCacheEntries = cacheCapacity * 10;
098: String baseCacheKey = "baseKey";
099: String cacheValue = "same_value";
100:
101: admin.setCacheCapacity(cacheCapacity);
102:
103: Cache cache = admin.getCache();
104:
105: //Add lots of different keys to trigger cache overflow
106: for (int keyIndex = 0; keyIndex < maxAddedCacheEntries; keyIndex++) {
107: String key = baseCacheKey + keyIndex;
108: admin.putInCache(key, cacheValue);
109: }
110:
111: Assert.assertEquals(
112: "expected cache to be at its full capacity",
113: cacheCapacity, cache.getSize());
114: Assert.assertTrue(
115: "expected cache overflows to have cleaned UpdateState instances. got ["
116: + cache.getNbUpdateState()
117: + "] updates while max is [" + cacheCapacity
118: + "]",
119: cache.getNbUpdateState() <= cacheCapacity);
120: }
121:
122: /**
123: * Tests that with a very large amount of keys that added and trigger cache overflows, there is no memory leak
124: * @throws Exception
125: */
126: public void testBug174CacheOverflowAndUpdate() throws Exception {
127: Properties p = new Properties();
128: p.setProperty(AbstractCacheAdministrator.CACHE_ALGORITHM_KEY,
129: "com.opensymphony.oscache.base.algorithm.LRUCache");
130: p.setProperty(AbstractCacheAdministrator.CACHE_CAPACITY_KEY,
131: "100");
132: GeneralCacheAdministrator admin = new GeneralCacheAdministrator(
133: p);
134:
135: int cacheCapacity = 100;
136: int maxAddedCacheEntries = cacheCapacity * 10;
137: String baseCacheKey = "baseKey";
138: String cacheValue = "same_value";
139:
140: admin.setCacheCapacity(cacheCapacity);
141:
142: Cache cache = admin.getCache();
143:
144: //Add lots of different keys to trigger cache overflow, mixed with updates
145: //FIXME: we may need different threads to enter branches recovering from current update.
146: for (int keyIndex = 0; keyIndex < maxAddedCacheEntries; keyIndex++) {
147: String key = baseCacheKey + keyIndex;
148: admin.putInCache(key, cacheValue);
149:
150: try {
151: admin.getFromCache(key, 0);
152: fail("expected element [" + key + "] not to be present");
153: } catch (NeedsRefreshException e) {
154: admin.putInCache(key, cacheValue);
155: }
156: }
157:
158: Assert.assertEquals(
159: "expected cache to be at its full capacity",
160: cacheCapacity, cache.getSize());
161: Assert.assertTrue(
162: "expected cache overflows to have cleaned UpdateState instances. Nb states is:"
163: + cache.getNbUpdateState() + " expected max="
164: + cacheCapacity,
165: cache.getNbUpdateState() <= cacheCapacity);
166: }
167:
168: /**
169: * Tests that with a very large amount of keys accessed and cancelled, there is no memory leak
170: * @throws Exception
171: */
172: public void testBug174CacheMissesNonBlocking() throws Exception {
173: testBug174CacheMisses(false);
174: }
175:
176: /**
177: * Tests that with a very large amount of keys accessed and cancelled, there is no memory leak
178: * @throws Exception
179: */
180: public void testBug174CacheMissesBlocking() throws Exception {
181: testBug174CacheMisses(true);
182: }
183:
184: /**
185: * Tests that with a very large amount of keys accessed and cancelled, there is no memory leak
186: * @throws Exception
187: */
188: public void testBug174CacheMisses(boolean block) throws Exception {
189: Properties p = new Properties();
190: p.setProperty(AbstractCacheAdministrator.CACHE_ALGORITHM_KEY,
191: "com.opensymphony.oscache.base.algorithm.LRUCache");
192: p.setProperty(AbstractCacheAdministrator.CACHE_CAPACITY_KEY,
193: "100");
194: if (block) {
195: p.setProperty(
196: AbstractCacheAdministrator.CACHE_BLOCKING_KEY,
197: "true");
198: }
199: GeneralCacheAdministrator admin = new GeneralCacheAdministrator(
200: p);
201:
202: int cacheCapacity = 100;
203: int maxAddedCacheEntries = cacheCapacity * 10;
204: String baseCacheKey = "baseKey";
205: //String cacheValue ="same_value";
206:
207: admin.setCacheCapacity(cacheCapacity);
208:
209: Cache cache = admin.getCache();
210:
211: //Access lots of different keys to trigger cache overflow
212: for (int keyIndex = 0; keyIndex < maxAddedCacheEntries; keyIndex++) {
213: String key = baseCacheKey + keyIndex;
214: try {
215: admin.getFromCache(key);
216: fail("expected element [" + key + "] not to be present");
217: } catch (NeedsRefreshException e) {
218: admin.cancelUpdate(key);
219: }
220: }
221:
222: Assert.assertTrue(
223: "expected cache accesses to not leak past cache capacity. Nb states is:"
224: + cache.getNbUpdateState() + " expected max="
225: + cacheCapacity,
226: cache.getNbUpdateState() < cacheCapacity);
227: }
228:
229: /**
230: * Verify that we can put item in the cache and that they are correctly retrieved
231: */
232: public void testPutGetFromCache() {
233: // We put content in the cache and get it back with and without refresh
234: map.putInCache(ENTRY_KEY, CONTENT);
235: getBackContent(map, CONTENT, NO_REFRESH_NEEDED, false);
236: getBackContent(map, CONTENT, REFRESH_NEEDED, true);
237:
238: // Test with invalid values
239:
240: /** TODO Verify this logic */
241: try {
242: assertNull(map.getFromCache("", NO_REFRESH_NEEDED));
243: } catch (NeedsRefreshException nre) {
244: map.cancelUpdate("");
245: } catch (Exception e) {
246: }
247:
248: try {
249: assertNull(map.getFromCache(null, NO_REFRESH_NEEDED));
250: } catch (NeedsRefreshException nre) {
251: map.cancelUpdate(null);
252: } catch (Exception e) {
253: }
254: }
255:
256: /**
257: * Verify that we can put item in the cache and that they are correctly retrieved
258: */
259: public void testPutGetFromCacheWithPolicy() {
260: // We put content in the cache and get it back
261: map.putInCache(ENTRY_KEY + "policy", CONTENT,
262: new DummyAlwayRefreshEntryPolicy());
263:
264: // Should get a refresh
265: try {
266: map.getFromCache(ENTRY_KEY + "policy", -1);
267: fail("Should have got a refresh.");
268: } catch (NeedsRefreshException nre) {
269: map.cancelUpdate(ENTRY_KEY + "policy");
270: }
271: }
272:
273: protected void tearDown() throws Exception {
274: if (map != null) {
275: map.clear();
276: }
277: }
278:
279: /**
280: * Retrieve the content in the cache
281: * <p>
282: * @param map The Cache in which the data is stored
283: * @param content The content expected to be retrieved
284: * @param refresh Time interval to determine if the cache object needs refresh
285: * @param exceptionExpected Specify if a NeedsRefreshException is expected
286: */
287: private void getBackContent(Cache map, Object content, int refresh,
288: boolean exceptionExpected) {
289: try {
290: assertEquals(content, map.getFromCache(ENTRY_KEY, refresh));
291:
292: if (exceptionExpected) {
293: fail("NeedsRefreshException should have been thrown!");
294: }
295: } catch (NeedsRefreshException nre) {
296: map.cancelUpdate(ENTRY_KEY);
297:
298: if (!exceptionExpected) {
299: fail("NeedsRefreshException shouldn't have been thrown!");
300: }
301: }
302: }
303: }
|