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