1 /*
2  * Copyright (C) 2011 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.collect.ImmutableList;
20 import com.google.common.collect.ImmutableMap;
21 import com.google.common.collect.Lists;
22 import com.google.common.util.concurrent.Futures;
23 import com.google.common.util.concurrent.ListenableFuture;
24 import java.util.LinkedList;
25 import java.util.Map;
26 import java.util.concurrent.Executor;
27 import java.util.concurrent.Future;
28 import java.util.concurrent.atomic.AtomicInteger;
29 import junit.framework.TestCase;
30 
31 /**
32  * Unit tests for {@link CacheLoader}.
33  *
34  * @author Charles Fry
35  */
36 public class CacheLoaderTest extends TestCase {
37 
38   private static class QueuingExecutor implements Executor {
39     private LinkedList<Runnable> tasks = Lists.newLinkedList();
40 
41     @Override
execute(Runnable task)42     public void execute(Runnable task) {
43       tasks.add(task);
44     }
45 
runNext()46     private void runNext() {
47       tasks.removeFirst().run();
48     }
49   }
50 
testAsyncReload()51   public void testAsyncReload() throws Exception {
52     final AtomicInteger loadCount = new AtomicInteger();
53     final AtomicInteger reloadCount = new AtomicInteger();
54     final AtomicInteger loadAllCount = new AtomicInteger();
55 
56     CacheLoader<Object, Object> baseLoader =
57         new CacheLoader<Object, Object>() {
58           @Override
59           public Object load(Object key) {
60             loadCount.incrementAndGet();
61             return new Object();
62           }
63 
64           @Override
65           public ListenableFuture<Object> reload(Object key, Object oldValue) {
66             reloadCount.incrementAndGet();
67             return Futures.immediateFuture(new Object());
68           }
69 
70           @Override
71           public Map<Object, Object> loadAll(Iterable<?> keys) {
72             loadAllCount.incrementAndGet();
73             return ImmutableMap.of();
74           }
75         };
76 
77     assertEquals(0, loadCount.get());
78     assertEquals(0, reloadCount.get());
79     assertEquals(0, loadAllCount.get());
80 
81     baseLoader.load(new Object());
82     @SuppressWarnings("unused") // go/futurereturn-lsc
83     Future<?> possiblyIgnoredError = baseLoader.reload(new Object(), new Object());
84     baseLoader.loadAll(ImmutableList.of(new Object()));
85     assertEquals(1, loadCount.get());
86     assertEquals(1, reloadCount.get());
87     assertEquals(1, loadAllCount.get());
88 
89     QueuingExecutor executor = new QueuingExecutor();
90     CacheLoader<Object, Object> asyncReloader = CacheLoader.asyncReloading(baseLoader, executor);
91 
92     asyncReloader.load(new Object());
93     @SuppressWarnings("unused") // go/futurereturn-lsc
94     Future<?> possiblyIgnoredError1 = asyncReloader.reload(new Object(), new Object());
95     asyncReloader.loadAll(ImmutableList.of(new Object()));
96     assertEquals(2, loadCount.get());
97     assertEquals(1, reloadCount.get());
98     assertEquals(2, loadAllCount.get());
99 
100     executor.runNext();
101     assertEquals(2, loadCount.get());
102     assertEquals(2, reloadCount.get());
103     assertEquals(2, loadAllCount.get());
104   }
105 }
106