blob: f8e31539be48adeda214011c4246f71763a4d75a [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
2// SPDX-License-Identifier: Apache-2.0
3
Jan Schär75ea9f42024-07-29 17:01:41 +02004package cache
5
6// Taken and modified from CoreDNS, under Apache 2.0.
7
8import (
9 "testing"
10)
11
12// newShard returns a new shard with size.
13func newShard[T any](size int) *shard[T] { return &shard[T]{items: make(map[uint64]T), size: size} }
14
15func TestShardAddAndGet(t *testing.T) {
16 s := newShard[int](1)
17 s.Put(1, 1)
18
19 if _, found := s.Get(1); !found {
20 t.Fatal("Failed to find inserted record")
21 }
22
23 s.Put(2, 1)
24 if _, found := s.Get(1); found {
25 t.Fatal("Failed to evict record")
26 }
27 if _, found := s.Get(2); !found {
28 t.Fatal("Failed to find inserted record")
29 }
30}
31
32func TestGetOrPut(t *testing.T) {
33 s := newShard[int](1)
34 el, exists := s.GetOrPut(1, 2)
35 if exists {
36 t.Fatalf("Element should not have existed")
37 }
38 if el != 2 {
39 t.Fatalf("Expected element %d, got %d ", 2, el)
40 }
41
42 el, exists = s.GetOrPut(1, 3)
43 if !exists {
44 t.Fatalf("Element should have existed")
45 }
46 if el != 2 {
47 t.Fatalf("Expected element %d, got %d ", 2, el)
48 }
49}
50
51func TestShardRemove(t *testing.T) {
52 s := newShard[int](2)
53 s.Put(1, 1)
54 s.Put(2, 2)
55
56 s.Remove(1)
57
58 if _, found := s.Get(1); found {
59 t.Fatal("Failed to remove record")
60 }
61 if _, found := s.Get(2); !found {
62 t.Fatal("Failed to find inserted record")
63 }
64}
65
66func TestAddEvict(t *testing.T) {
67 const size = 1024
68 s := newShard[int](size)
69
70 for i := uint64(0); i < size; i++ {
71 s.Put(i, 1)
72 }
73 for i := uint64(0); i < size; i++ {
74 s.Put(i, 1)
75 if len(s.items) != size {
76 t.Fatal("A item was unnecessarily evicted from the cache")
77 }
78 }
79}
80
81func TestShardLen(t *testing.T) {
82 s := newShard[int](4)
83
84 s.Put(1, 1)
85 if l := len(s.items); l != 1 {
86 t.Fatalf("Shard size should %d, got %d", 1, l)
87 }
88
89 s.Put(1, 1)
90 if l := len(s.items); l != 1 {
91 t.Fatalf("Shard size should %d, got %d", 1, l)
92 }
93
94 s.Put(2, 2)
95 if l := len(s.items); l != 2 {
96 t.Fatalf("Shard size should %d, got %d", 2, l)
97 }
98}
99
100func TestShardEvict(t *testing.T) {
101 s := newShard[int](1)
102 s.Put(1, 1)
103 s.Put(2, 2)
104 // 1 should be gone
105
106 if _, found := s.Get(1); found {
107 t.Fatal("Found item that should have been evicted")
108 }
109}
110
111func TestShardLenEvict(t *testing.T) {
112 s := newShard[int](4)
113 s.Put(1, 1)
114 s.Put(2, 1)
115 s.Put(3, 1)
116 s.Put(4, 1)
117
118 if l := len(s.items); l != 4 {
119 t.Fatalf("Shard size should %d, got %d", 4, l)
120 }
121
122 // This should evict one element
123 s.Put(5, 1)
124 if l := len(s.items); l != 4 {
125 t.Fatalf("Shard size should %d, got %d", 4, l)
126 }
127
128 // Make sure we don't accidentally evict an element when
129 // we the key is already stored.
130 for i := 0; i < 4; i++ {
131 s.Put(5, 1)
132 if l := len(s.items); l != 4 {
133 t.Fatalf("Shard size should %d, got %d", 4, l)
134 }
135 }
136}
137
138func BenchmarkShard(b *testing.B) {
139 s := newShard[int](shardSize)
140 b.ResetTimer()
141 for i := 0; i < b.N; i++ {
142 k := uint64(i) % shardSize * 2
143 s.Put(k, 1)
144 s.Get(k)
145 }
146}
147
148func BenchmarkShardParallel(b *testing.B) {
149 s := newShard[int](shardSize)
150 b.ResetTimer()
151 b.RunParallel(func(pb *testing.PB) {
152 for i := uint64(0); pb.Next(); i++ {
153 k := i % shardSize * 2
154 s.Put(k, 1)
155 s.Get(k)
156 }
157 })
158}