1 /* 2 * Copyright (C) 2012 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.cache; 18 19 import com.google.common.annotations.GwtCompatible; 20 import com.google.common.collect.ImmutableList; 21 import com.google.common.collect.ImmutableMap; 22 import com.google.common.collect.ImmutableSet; 23 import com.google.common.testing.FakeTicker; 24 import java.util.HashSet; 25 import java.util.Iterator; 26 import java.util.Map; 27 import java.util.Map.Entry; 28 import java.util.Set; 29 import java.util.concurrent.Callable; 30 import java.util.concurrent.ConcurrentMap; 31 import java.util.concurrent.ExecutionException; 32 import java.util.concurrent.TimeUnit; 33 import junit.framework.TestCase; 34 35 /** 36 * Test suite for {@link CacheBuilder}. TODO(cpovirk): merge into CacheBuilderTest? 37 * 38 * @author Jon Donovan 39 */ 40 @GwtCompatible 41 public class CacheBuilderGwtTest extends TestCase { 42 43 private FakeTicker fakeTicker; 44 45 @Override setUp()46 protected void setUp() throws Exception { 47 super.setUp(); 48 49 fakeTicker = new FakeTicker(); 50 } 51 testLoader()52 public void testLoader() throws ExecutionException { 53 54 final Cache<Integer, Integer> cache = CacheBuilder.newBuilder().build(); 55 56 Callable<Integer> loader = 57 new Callable<Integer>() { 58 private int i = 0; 59 60 @Override 61 public Integer call() throws Exception { 62 return ++i; 63 } 64 }; 65 66 cache.put(0, 10); 67 68 assertEquals(Integer.valueOf(10), cache.get(0, loader)); 69 assertEquals(Integer.valueOf(1), cache.get(20, loader)); 70 assertEquals(Integer.valueOf(2), cache.get(34, loader)); 71 72 cache.invalidate(0); 73 assertEquals(Integer.valueOf(3), cache.get(0, loader)); 74 75 cache.put(0, 10); 76 cache.invalidateAll(); 77 assertEquals(Integer.valueOf(4), cache.get(0, loader)); 78 } 79 testSizeConstraint()80 public void testSizeConstraint() { 81 final Cache<Integer, Integer> cache = CacheBuilder.newBuilder().maximumSize(4).build(); 82 83 cache.put(1, 10); 84 cache.put(2, 20); 85 cache.put(3, 30); 86 cache.put(4, 40); 87 cache.put(5, 50); 88 89 assertEquals(null, cache.getIfPresent(10)); 90 // Order required to remove dependence on access order / write order constraint. 91 assertEquals(Integer.valueOf(20), cache.getIfPresent(2)); 92 assertEquals(Integer.valueOf(30), cache.getIfPresent(3)); 93 assertEquals(Integer.valueOf(40), cache.getIfPresent(4)); 94 assertEquals(Integer.valueOf(50), cache.getIfPresent(5)); 95 96 cache.put(1, 10); 97 assertEquals(Integer.valueOf(10), cache.getIfPresent(1)); 98 assertEquals(Integer.valueOf(30), cache.getIfPresent(3)); 99 assertEquals(Integer.valueOf(40), cache.getIfPresent(4)); 100 assertEquals(Integer.valueOf(50), cache.getIfPresent(5)); 101 assertEquals(null, cache.getIfPresent(2)); 102 } 103 testLoadingCache()104 public void testLoadingCache() throws ExecutionException { 105 CacheLoader<Integer, Integer> loader = 106 new CacheLoader<Integer, Integer>() { 107 int i = 0; 108 109 @Override 110 public Integer load(Integer key) throws Exception { 111 return i++; 112 } 113 }; 114 115 LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder().build(loader); 116 117 cache.put(10, 20); 118 119 Map<Integer, Integer> map = cache.getAll(ImmutableList.of(10, 20, 30, 54, 443, 1)); 120 121 assertEquals(Integer.valueOf(20), map.get(10)); 122 assertEquals(Integer.valueOf(0), map.get(20)); 123 assertEquals(Integer.valueOf(1), map.get(30)); 124 assertEquals(Integer.valueOf(2), map.get(54)); 125 assertEquals(Integer.valueOf(3), map.get(443)); 126 assertEquals(Integer.valueOf(4), map.get(1)); 127 assertEquals(Integer.valueOf(5), cache.get(6)); 128 assertEquals(Integer.valueOf(6), cache.apply(7)); 129 } 130 testExpireAfterAccess()131 public void testExpireAfterAccess() { 132 final Cache<Integer, Integer> cache = 133 CacheBuilder.newBuilder() 134 .expireAfterAccess(1000, TimeUnit.MILLISECONDS) 135 .ticker(fakeTicker) 136 .build(); 137 138 cache.put(0, 10); 139 cache.put(2, 30); 140 141 fakeTicker.advance(999, TimeUnit.MILLISECONDS); 142 assertEquals(Integer.valueOf(30), cache.getIfPresent(2)); 143 fakeTicker.advance(1, TimeUnit.MILLISECONDS); 144 assertEquals(Integer.valueOf(30), cache.getIfPresent(2)); 145 fakeTicker.advance(1000, TimeUnit.MILLISECONDS); 146 assertEquals(null, cache.getIfPresent(0)); 147 } 148 testExpireAfterWrite()149 public void testExpireAfterWrite() { 150 final Cache<Integer, Integer> cache = 151 CacheBuilder.newBuilder() 152 .expireAfterWrite(1000, TimeUnit.MILLISECONDS) 153 .ticker(fakeTicker) 154 .build(); 155 156 cache.put(10, 100); 157 cache.put(20, 200); 158 cache.put(4, 2); 159 160 fakeTicker.advance(999, TimeUnit.MILLISECONDS); 161 assertEquals(Integer.valueOf(100), cache.getIfPresent(10)); 162 assertEquals(Integer.valueOf(200), cache.getIfPresent(20)); 163 assertEquals(Integer.valueOf(2), cache.getIfPresent(4)); 164 165 fakeTicker.advance(2, TimeUnit.MILLISECONDS); 166 assertEquals(null, cache.getIfPresent(10)); 167 assertEquals(null, cache.getIfPresent(20)); 168 assertEquals(null, cache.getIfPresent(4)); 169 170 cache.put(10, 20); 171 assertEquals(Integer.valueOf(20), cache.getIfPresent(10)); 172 173 fakeTicker.advance(1000, TimeUnit.MILLISECONDS); 174 assertEquals(null, cache.getIfPresent(10)); 175 } 176 testExpireAfterWriteAndAccess()177 public void testExpireAfterWriteAndAccess() { 178 final Cache<Integer, Integer> cache = 179 CacheBuilder.newBuilder() 180 .expireAfterWrite(1000, TimeUnit.MILLISECONDS) 181 .expireAfterAccess(500, TimeUnit.MILLISECONDS) 182 .ticker(fakeTicker) 183 .build(); 184 185 cache.put(10, 100); 186 cache.put(20, 200); 187 cache.put(4, 2); 188 189 fakeTicker.advance(499, TimeUnit.MILLISECONDS); 190 assertEquals(Integer.valueOf(100), cache.getIfPresent(10)); 191 assertEquals(Integer.valueOf(200), cache.getIfPresent(20)); 192 193 fakeTicker.advance(2, TimeUnit.MILLISECONDS); 194 assertEquals(Integer.valueOf(100), cache.getIfPresent(10)); 195 assertEquals(Integer.valueOf(200), cache.getIfPresent(20)); 196 assertEquals(null, cache.getIfPresent(4)); 197 198 fakeTicker.advance(499, TimeUnit.MILLISECONDS); 199 assertEquals(null, cache.getIfPresent(10)); 200 assertEquals(null, cache.getIfPresent(20)); 201 202 cache.put(10, 20); 203 assertEquals(Integer.valueOf(20), cache.getIfPresent(10)); 204 205 fakeTicker.advance(500, TimeUnit.MILLISECONDS); 206 assertEquals(null, cache.getIfPresent(10)); 207 } 208 testMapMethods()209 public void testMapMethods() { 210 Cache<Integer, Integer> cache = CacheBuilder.newBuilder().build(); 211 212 ConcurrentMap<Integer, Integer> asMap = cache.asMap(); 213 214 cache.put(10, 100); 215 cache.put(2, 52); 216 217 asMap.replace(2, 79); 218 asMap.replace(3, 60); 219 220 assertEquals(null, cache.getIfPresent(3)); 221 assertEquals(null, asMap.get(3)); 222 223 assertEquals(Integer.valueOf(79), cache.getIfPresent(2)); 224 assertEquals(Integer.valueOf(79), asMap.get(2)); 225 226 asMap.replace(10, 100, 50); 227 asMap.replace(2, 52, 99); 228 229 assertEquals(Integer.valueOf(50), cache.getIfPresent(10)); 230 assertEquals(Integer.valueOf(50), asMap.get(10)); 231 assertEquals(Integer.valueOf(79), cache.getIfPresent(2)); 232 assertEquals(Integer.valueOf(79), asMap.get(2)); 233 234 asMap.remove(10, 100); 235 asMap.remove(2, 79); 236 237 assertEquals(Integer.valueOf(50), cache.getIfPresent(10)); 238 assertEquals(Integer.valueOf(50), asMap.get(10)); 239 assertEquals(null, cache.getIfPresent(2)); 240 assertEquals(null, asMap.get(2)); 241 242 asMap.putIfAbsent(2, 20); 243 asMap.putIfAbsent(10, 20); 244 245 assertEquals(Integer.valueOf(20), cache.getIfPresent(2)); 246 assertEquals(Integer.valueOf(20), asMap.get(2)); 247 assertEquals(Integer.valueOf(50), cache.getIfPresent(10)); 248 assertEquals(Integer.valueOf(50), asMap.get(10)); 249 } 250 testRemovalListener()251 public void testRemovalListener() { 252 final int[] stats = new int[4]; 253 254 RemovalListener<Integer, Integer> countingListener = 255 new RemovalListener<Integer, Integer>() { 256 @Override 257 public void onRemoval(RemovalNotification<Integer, Integer> notification) { 258 switch (notification.getCause()) { 259 case EXPIRED: 260 stats[0]++; 261 break; 262 case EXPLICIT: 263 stats[1]++; 264 break; 265 case REPLACED: 266 stats[2]++; 267 break; 268 case SIZE: 269 stats[3]++; 270 break; 271 default: 272 throw new IllegalStateException("No collected exceptions in GWT CacheBuilder."); 273 } 274 } 275 }; 276 277 Cache<Integer, Integer> cache = 278 CacheBuilder.newBuilder() 279 .expireAfterWrite(1000, TimeUnit.MILLISECONDS) 280 .removalListener(countingListener) 281 .ticker(fakeTicker) 282 .maximumSize(2) 283 .build(); 284 285 // Add more than two elements to increment size removals. 286 cache.put(3, 20); 287 cache.put(6, 2); 288 cache.put(98, 45); 289 cache.put(56, 76); 290 cache.put(23, 84); 291 292 // Replace the two present elements. 293 cache.put(23, 20); 294 cache.put(56, 49); 295 cache.put(23, 2); 296 cache.put(56, 4); 297 298 // Expire the two present elements. 299 fakeTicker.advance(1001, TimeUnit.MILLISECONDS); 300 301 cache.getIfPresent(23); 302 cache.getIfPresent(56); 303 304 // Add two elements and invalidate them. 305 cache.put(1, 4); 306 cache.put(2, 8); 307 308 cache.invalidateAll(); 309 310 assertEquals(2, stats[0]); 311 assertEquals(2, stats[1]); 312 assertEquals(4, stats[2]); 313 assertEquals(3, stats[3]); 314 } 315 testPutAll()316 public void testPutAll() { 317 Cache<Integer, Integer> cache = CacheBuilder.newBuilder().build(); 318 319 cache.putAll(ImmutableMap.of(10, 20, 30, 50, 60, 90)); 320 321 assertEquals(Integer.valueOf(20), cache.getIfPresent(10)); 322 assertEquals(Integer.valueOf(50), cache.getIfPresent(30)); 323 assertEquals(Integer.valueOf(90), cache.getIfPresent(60)); 324 325 cache.asMap().putAll(ImmutableMap.of(10, 50, 30, 20, 60, 70, 5, 5)); 326 327 assertEquals(Integer.valueOf(50), cache.getIfPresent(10)); 328 assertEquals(Integer.valueOf(20), cache.getIfPresent(30)); 329 assertEquals(Integer.valueOf(70), cache.getIfPresent(60)); 330 assertEquals(Integer.valueOf(5), cache.getIfPresent(5)); 331 } 332 testInvalidate()333 public void testInvalidate() { 334 Cache<Integer, Integer> cache = CacheBuilder.newBuilder().build(); 335 336 cache.put(654, 2675); 337 cache.put(2456, 56); 338 cache.put(2, 15); 339 340 cache.invalidate(654); 341 342 assertFalse(cache.asMap().containsKey(654)); 343 assertTrue(cache.asMap().containsKey(2456)); 344 assertTrue(cache.asMap().containsKey(2)); 345 } 346 testInvalidateAll()347 public void testInvalidateAll() { 348 Cache<Integer, Integer> cache = CacheBuilder.newBuilder().build(); 349 350 cache.put(654, 2675); 351 cache.put(2456, 56); 352 cache.put(2, 15); 353 354 cache.invalidateAll(); 355 assertFalse(cache.asMap().containsKey(654)); 356 assertFalse(cache.asMap().containsKey(2456)); 357 assertFalse(cache.asMap().containsKey(2)); 358 359 cache.put(654, 2675); 360 cache.put(2456, 56); 361 cache.put(2, 15); 362 cache.put(1, 3); 363 364 cache.invalidateAll(ImmutableSet.of(1, 2)); 365 366 assertFalse(cache.asMap().containsKey(1)); 367 assertFalse(cache.asMap().containsKey(2)); 368 assertTrue(cache.asMap().containsKey(654)); 369 assertTrue(cache.asMap().containsKey(2456)); 370 } 371 testAsMap_containsValue()372 public void testAsMap_containsValue() { 373 Cache<Integer, Integer> cache = 374 CacheBuilder.newBuilder() 375 .expireAfterWrite(20000, TimeUnit.MILLISECONDS) 376 .ticker(fakeTicker) 377 .build(); 378 379 cache.put(654, 2675); 380 fakeTicker.advance(10000, TimeUnit.MILLISECONDS); 381 cache.put(2456, 56); 382 cache.put(2, 15); 383 384 fakeTicker.advance(10001, TimeUnit.MILLISECONDS); 385 386 assertTrue(cache.asMap().containsValue(15)); 387 assertTrue(cache.asMap().containsValue(56)); 388 assertFalse(cache.asMap().containsValue(2675)); 389 } 390 testAsMap_containsKey()391 public void testAsMap_containsKey() { 392 Cache<Integer, Integer> cache = 393 CacheBuilder.newBuilder() 394 .expireAfterWrite(20000, TimeUnit.MILLISECONDS) 395 .ticker(fakeTicker) 396 .build(); 397 398 cache.put(654, 2675); 399 fakeTicker.advance(10000, TimeUnit.MILLISECONDS); 400 cache.put(2456, 56); 401 cache.put(2, 15); 402 403 fakeTicker.advance(10001, TimeUnit.MILLISECONDS); 404 405 assertTrue(cache.asMap().containsKey(2)); 406 assertTrue(cache.asMap().containsKey(2456)); 407 assertFalse(cache.asMap().containsKey(654)); 408 } 409 testAsMapValues_contains()410 public void testAsMapValues_contains() { 411 Cache<Integer, Integer> cache = 412 CacheBuilder.newBuilder() 413 .expireAfterWrite(1000, TimeUnit.MILLISECONDS) 414 .ticker(fakeTicker) 415 .build(); 416 417 cache.put(10, 20); 418 fakeTicker.advance(500, TimeUnit.MILLISECONDS); 419 cache.put(20, 22); 420 cache.put(5, 10); 421 422 fakeTicker.advance(501, TimeUnit.MILLISECONDS); 423 424 assertTrue(cache.asMap().values().contains(22)); 425 assertTrue(cache.asMap().values().contains(10)); 426 assertFalse(cache.asMap().values().contains(20)); 427 } 428 testAsMapKeySet()429 public void testAsMapKeySet() { 430 Cache<Integer, Integer> cache = 431 CacheBuilder.newBuilder() 432 .expireAfterWrite(1000, TimeUnit.MILLISECONDS) 433 .ticker(fakeTicker) 434 .build(); 435 436 cache.put(10, 20); 437 fakeTicker.advance(500, TimeUnit.MILLISECONDS); 438 cache.put(20, 22); 439 cache.put(5, 10); 440 441 fakeTicker.advance(501, TimeUnit.MILLISECONDS); 442 443 Set<Integer> foundKeys = new HashSet<>(cache.asMap().keySet()); 444 445 assertEquals(ImmutableSet.of(20, 5), foundKeys); 446 } 447 testAsMapKeySet_contains()448 public void testAsMapKeySet_contains() { 449 Cache<Integer, Integer> cache = 450 CacheBuilder.newBuilder() 451 .expireAfterWrite(1000, TimeUnit.MILLISECONDS) 452 .ticker(fakeTicker) 453 .build(); 454 455 cache.put(10, 20); 456 fakeTicker.advance(500, TimeUnit.MILLISECONDS); 457 cache.put(20, 22); 458 cache.put(5, 10); 459 460 fakeTicker.advance(501, TimeUnit.MILLISECONDS); 461 462 assertTrue(cache.asMap().keySet().contains(20)); 463 assertTrue(cache.asMap().keySet().contains(5)); 464 assertFalse(cache.asMap().keySet().contains(10)); 465 } 466 testAsMapEntrySet()467 public void testAsMapEntrySet() { 468 Cache<Integer, Integer> cache = 469 CacheBuilder.newBuilder() 470 .expireAfterWrite(1000, TimeUnit.MILLISECONDS) 471 .ticker(fakeTicker) 472 .build(); 473 474 cache.put(10, 20); 475 fakeTicker.advance(500, TimeUnit.MILLISECONDS); 476 cache.put(20, 22); 477 cache.put(5, 10); 478 479 fakeTicker.advance(501, TimeUnit.MILLISECONDS); 480 481 int sum = 0; 482 for (Entry<Integer, Integer> current : cache.asMap().entrySet()) { 483 sum += current.getKey() + current.getValue(); 484 } 485 assertEquals(57, sum); 486 } 487 testAsMapValues_iteratorRemove()488 public void testAsMapValues_iteratorRemove() { 489 Cache<Integer, Integer> cache = 490 CacheBuilder.newBuilder() 491 .expireAfterWrite(1000, TimeUnit.MILLISECONDS) 492 .ticker(fakeTicker) 493 .build(); 494 495 cache.put(10, 20); 496 Iterator<Integer> iterator = cache.asMap().values().iterator(); 497 iterator.next(); 498 iterator.remove(); 499 500 assertEquals(0, cache.size()); 501 } 502 } 503