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
17package com.google.common.cache;
18
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.Lists;
22import com.google.common.util.concurrent.Futures;
23import com.google.common.util.concurrent.ListenableFuture;
24
25import junit.framework.TestCase;
26
27import java.util.LinkedList;
28import java.util.Map;
29import java.util.concurrent.Executor;
30import java.util.concurrent.atomic.AtomicInteger;
31
32/**
33 * Unit tests for {@link CacheLoader}.
34 *
35 * @author Charles Fry
36 */
37public class CacheLoaderTest extends TestCase {
38
39  private static class QueuingExecutor implements Executor {
40    private LinkedList<Runnable> tasks = Lists.newLinkedList();
41
42    @Override
43    public void execute(Runnable task) {
44      tasks.add(task);
45    }
46
47    private void runNext() {
48      tasks.removeFirst().run();
49    }
50  }
51
52  public void testAsyncReload() throws Exception {
53    final AtomicInteger loadCount = new AtomicInteger();
54    final AtomicInteger reloadCount = new AtomicInteger();
55    final AtomicInteger loadAllCount = new AtomicInteger();
56
57    CacheLoader<Object, Object> baseLoader = 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<? extends Object> 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    baseLoader.reload(new Object(), new Object());
83    baseLoader.loadAll(ImmutableList.of(new Object()));
84    assertEquals(1, loadCount.get());
85    assertEquals(1, reloadCount.get());
86    assertEquals(1, loadAllCount.get());
87
88    QueuingExecutor executor = new QueuingExecutor();
89    CacheLoader<Object, Object> asyncReloader =
90        CacheLoader.asyncReloading(baseLoader, executor);
91
92    asyncReloader.load(new Object());
93    asyncReloader.reload(new Object(), new Object());
94    asyncReloader.loadAll(ImmutableList.of(new Object()));
95    assertEquals(2, loadCount.get());
96    assertEquals(1, reloadCount.get());
97    assertEquals(2, loadAllCount.get());
98
99    executor.runNext();
100    assertEquals(2, loadCount.get());
101    assertEquals(2, reloadCount.get());
102    assertEquals(2, loadAllCount.get());
103  }
104}
105