• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 static com.google.common.truth.Truth.assertThat;
20 
21 import java.util.concurrent.TimeUnit;
22 import java.util.function.IntConsumer;
23 import java.util.stream.IntStream;
24 import junit.framework.TestCase;
25 
26 /** Test Java8 map.compute in concurrent cache context. */
27 public class LocalCacheMapComputeTest extends TestCase {
28   final int count = 10000;
29   final String delimiter = "-";
30   final String key = "key";
31   Cache<String, String> cache;
32 
33   // helper
doParallelCacheOp(int count, IntConsumer consumer)34   private static void doParallelCacheOp(int count, IntConsumer consumer) {
35     IntStream.range(0, count).parallel().forEach(consumer);
36   }
37 
38   @Override
setUp()39   public void setUp() throws Exception {
40     super.setUp();
41     this.cache =
42         CacheBuilder.newBuilder()
43             .expireAfterAccess(500000, TimeUnit.MILLISECONDS)
44             .maximumSize(count)
45             .build();
46   }
47 
testComputeIfAbsent()48   public void testComputeIfAbsent() {
49     // simultaneous insertion for same key, expect 1 winner
50     doParallelCacheOp(
51         count,
52         n -> {
53           cache.asMap().computeIfAbsent(key, k -> "value" + n);
54         });
55     assertEquals(1, cache.size());
56   }
57 
testComputeIfAbsentEviction()58   public void testComputeIfAbsentEviction() {
59     // b/80241237
60 
61     Cache<String, String> c = CacheBuilder.newBuilder().maximumSize(1).build();
62 
63     assertThat(c.asMap().computeIfAbsent("hash-1", k -> "")).isEqualTo("");
64     assertThat(c.asMap().computeIfAbsent("hash-1", k -> "")).isEqualTo("");
65     assertThat(c.asMap().computeIfAbsent("hash-1", k -> "")).isEqualTo("");
66     assertThat(c.size()).isEqualTo(1);
67     assertThat(c.asMap().computeIfAbsent("hash-2", k -> "")).isEqualTo("");
68   }
69 
testComputeEviction()70   public void testComputeEviction() {
71     // b/80241237
72 
73     Cache<String, String> c = CacheBuilder.newBuilder().maximumSize(1).build();
74 
75     assertThat(c.asMap().compute("hash-1", (k, v) -> "a")).isEqualTo("a");
76     assertThat(c.asMap().compute("hash-1", (k, v) -> "b")).isEqualTo("b");
77     assertThat(c.asMap().compute("hash-1", (k, v) -> "c")).isEqualTo("c");
78     assertThat(c.size()).isEqualTo(1);
79     assertThat(c.asMap().computeIfAbsent("hash-2", k -> "")).isEqualTo("");
80   }
81 
testComputeIfPresent()82   public void testComputeIfPresent() {
83     cache.put(key, "1");
84     // simultaneous update for same key, expect count successful updates
85     doParallelCacheOp(
86         count,
87         n -> {
88           cache.asMap().computeIfPresent(key, (k, v) -> v + delimiter + n);
89         });
90     assertEquals(1, cache.size());
91     assertThat(cache.getIfPresent(key).split(delimiter)).hasLength(count + 1);
92   }
93 
testUpdates()94   public void testUpdates() {
95     cache.put(key, "1");
96     // simultaneous update for same key, some null, some non-null
97     doParallelCacheOp(
98         count,
99         n -> {
100           cache.asMap().compute(key, (k, v) -> n % 2 == 0 ? v + delimiter + n : null);
101         });
102     assertTrue(1 >= cache.size());
103   }
104 
testCompute()105   public void testCompute() {
106     cache.put(key, "1");
107     // simultaneous deletion
108     doParallelCacheOp(
109         count,
110         n -> {
111           cache.asMap().compute(key, (k, v) -> null);
112         });
113     assertEquals(0, cache.size());
114   }
115 
testComputeExceptionally()116   public void testComputeExceptionally() {
117     try {
118       doParallelCacheOp(
119           count,
120           n -> {
121             cache
122                 .asMap()
123                 .compute(
124                     key,
125                     (k, v) -> {
126                       throw new RuntimeException();
127                     });
128           });
129       fail("Should not get here");
130     } catch (RuntimeException ex) {
131     }
132   }
133 }
134