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