001: /**
002: * Copyright (C) 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package com.google.inject.util;
016:
017: import static com.google.inject.util.ReferenceType.SOFT;
018: import static com.google.inject.util.ReferenceType.STRONG;
019: import static com.google.inject.util.ReferenceType.WEAK;
020:
021: import junit.framework.TestCase;
022:
023: import java.util.concurrent.CountDownLatch;
024:
025: /**
026: * @author crazybob@google.com (Bob Lee)
027: */
028: public class ReferenceCacheTest extends TestCase {
029:
030: public void testRuntimeException() {
031: class CreationException extends RuntimeException {
032: }
033: try {
034: new ReferenceCache() {
035: protected Object create(Object key) {
036: throw new CreationException();
037: }
038: }.get(new Object());
039: fail();
040: } catch (CreationException e) { /* expected */
041: }
042: }
043:
044: public void testApply() {
045: ReferenceMap<String, Integer> cache = ReferenceCache.of(WEAK,
046: WEAK, new SomeFunction());
047: assertEquals(Integer.valueOf(1), cache.get("foo"));
048: assertEquals(Integer.valueOf(1), cache.get("foo"));
049: assertEquals(Integer.valueOf(2), cache.get("bar"));
050: assertEquals(Integer.valueOf(1), cache.get("foo"));
051: assertEquals(Integer.valueOf(3), cache.get("baz"));
052: }
053:
054: public void testSleepConcurrency() throws InterruptedException {
055: ReferenceMap<String, Integer> cache = ReferenceCache.of(WEAK,
056: WEAK, new SleepFunction());
057: assertConcurrency(cache, false);
058: }
059:
060: public void testBusyConcurrency() throws InterruptedException {
061: ReferenceMap<String, Integer> cache = ReferenceCache.of(WEAK,
062: WEAK, new BusyFunction());
063: assertConcurrency(cache, false);
064: }
065:
066: public void testFastConcurrency() throws InterruptedException {
067: ReferenceMap<String, Integer> cache = ReferenceCache.of(WEAK,
068: WEAK, new SomeFunction());
069: assertConcurrency(cache, false);
070: }
071:
072: public void testSleepCanonical() throws InterruptedException {
073: ReferenceMap<String, Integer> cache = ReferenceCache.of(STRONG,
074: SOFT, new SleepFunction());
075: assertConcurrency(cache, true);
076: }
077:
078: public void testBusyCanonical() throws InterruptedException {
079: ReferenceMap<String, Integer> cache = ReferenceCache.of(STRONG,
080: SOFT, new BusyFunction());
081: assertConcurrency(cache, true);
082: }
083:
084: public void testFastCanonical() throws InterruptedException {
085: ReferenceMap<String, Integer> cache = ReferenceCache.of(STRONG,
086: SOFT, new SomeFunction());
087: assertConcurrency(cache, true);
088: }
089:
090: private static void assertConcurrency(
091: final ReferenceMap<String, Integer> cache,
092: final boolean simulateAliasing) throws InterruptedException {
093: final int n = 20;
094: final CountDownLatch startSignal = new CountDownLatch(1);
095: final CountDownLatch doneSignal = new CountDownLatch(n);
096: for (int i = 0; i < n; i++) {
097: new Thread() {
098: public void run() {
099: try {
100: startSignal.await();
101: for (int j = 0; j < n; j++) {
102: cache.get(simulateAliasing ? new String(
103: "foo") : "foo");
104: }
105: doneSignal.countDown();
106: } catch (InterruptedException ignored) {
107: }
108: }
109: }.start();
110: }
111:
112: startSignal.countDown();
113: doneSignal.await();
114: assertEquals(Integer.valueOf(1), cache.get("foo"));
115: assertEquals(Integer.valueOf(2), cache.get("bar"));
116: }
117:
118: private static class SomeFunction implements
119: Function<String, Integer> {
120: private int numApplies = 0;
121:
122: public Integer apply(String s) {
123: return ++numApplies;
124: }
125: }
126:
127: private static class SleepFunction implements
128: Function<String, Integer> {
129: private int numApplies = 0;
130:
131: public Integer apply(String s) {
132: try {
133: Thread.sleep(100);
134: } catch (InterruptedException e) {
135: throw new RuntimeException(e);
136: }
137: return ++numApplies;
138: }
139: }
140:
141: private static class BusyFunction implements
142: Function<String, Integer> {
143: private int numApplies = 0;
144:
145: public Integer apply(String s) {
146: for (int i = 0; i < 1000; i++) {
147: Math.sqrt(i);
148: }
149: return ++numApplies;
150: }
151: }
152: }
|