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