golang.org/x/tools/gopls@v0.15.3/internal/util/lru/lru_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package lru_test 6 7 import ( 8 "bytes" 9 cryptorand "crypto/rand" 10 "fmt" 11 "log" 12 mathrand "math/rand" 13 "strings" 14 "testing" 15 16 "golang.org/x/sync/errgroup" 17 "golang.org/x/tools/gopls/internal/util/lru" 18 ) 19 20 func TestCache(t *testing.T) { 21 type get struct { 22 key string 23 want any 24 } 25 type set struct { 26 key, value string 27 } 28 29 tests := []struct { 30 label string 31 steps []any 32 }{ 33 {"empty cache", []any{ 34 get{"a", nil}, 35 get{"b", nil}, 36 }}, 37 {"zero-length string", []any{ 38 set{"a", ""}, 39 get{"a", ""}, 40 }}, 41 {"under capacity", []any{ 42 set{"a", "123"}, 43 set{"b", "456"}, 44 get{"a", "123"}, 45 get{"b", "456"}, 46 }}, 47 {"over capacity", []any{ 48 set{"a", "123"}, 49 set{"b", "456"}, 50 set{"c", "78901"}, 51 get{"a", nil}, 52 get{"b", "456"}, 53 get{"c", "78901"}, 54 }}, 55 {"access ordering", []any{ 56 set{"a", "123"}, 57 set{"b", "456"}, 58 get{"a", "123"}, 59 set{"c", "78901"}, 60 get{"a", "123"}, 61 get{"b", nil}, 62 get{"c", "78901"}, 63 }}, 64 } 65 66 for _, test := range tests { 67 t.Run(test.label, func(t *testing.T) { 68 c := lru.New(10) 69 for i, step := range test.steps { 70 switch step := step.(type) { 71 case get: 72 if got := c.Get(step.key); got != step.want { 73 t.Errorf("#%d: c.Get(%q) = %q, want %q", i, step.key, got, step.want) 74 } 75 case set: 76 c.Set(step.key, step.value, len(step.value)) 77 } 78 } 79 }) 80 } 81 } 82 83 // TestConcurrency exercises concurrent access to the same entry. 84 // 85 // It is a copy of TestConcurrency from the filecache package. 86 func TestConcurrency(t *testing.T) { 87 key := uniqueKey() 88 const N = 100 // concurrency level 89 90 // Construct N distinct values, each larger 91 // than a typical 4KB OS file buffer page. 92 var values [N][8192]byte 93 for i := range values { 94 if _, err := mathrand.Read(values[i][:]); err != nil { 95 t.Fatalf("rand: %v", err) 96 } 97 } 98 99 cache := lru.New(100 * 1e6) // 100MB cache 100 101 // get calls Get and verifies that the cache entry 102 // matches one of the values passed to Set. 103 get := func(mustBeFound bool) error { 104 got := cache.Get(key) 105 if got == nil { 106 if !mustBeFound { 107 return nil 108 } 109 return fmt.Errorf("Get did not return a value") 110 } 111 gotBytes := got.([]byte) 112 for _, want := range values { 113 if bytes.Equal(want[:], gotBytes) { 114 return nil // a match 115 } 116 } 117 return fmt.Errorf("Get returned a value that was never Set") 118 } 119 120 // Perform N concurrent calls to Set and Get. 121 // All sets must succeed. 122 // All gets must return nothing, or one of the Set values; 123 // there is no third possibility. 124 var group errgroup.Group 125 for i := range values { 126 i := i 127 v := values[i][:] 128 group.Go(func() error { 129 cache.Set(key, v, len(v)) 130 return nil 131 }) 132 group.Go(func() error { return get(false) }) 133 } 134 if err := group.Wait(); err != nil { 135 if strings.Contains(err.Error(), "operation not supported") || 136 strings.Contains(err.Error(), "not implemented") { 137 t.Skipf("skipping: %v", err) 138 } 139 t.Fatal(err) 140 } 141 142 // A final Get must report one of the values that was Set. 143 if err := get(true); err != nil { 144 t.Fatalf("final Get failed: %v", err) 145 } 146 } 147 148 // uniqueKey returns a key that has never been used before. 149 func uniqueKey() (key [32]byte) { 150 if _, err := cryptorand.Read(key[:]); err != nil { 151 log.Fatalf("rand: %v", err) 152 } 153 return 154 }