master
go 191 lines 4.71 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package dyncfg
4
5 import (
6 "testing"
7
8 "github.com/stretchr/testify/assert"
9 "github.com/stretchr/testify/require"
10 )
11
12 type testConfig struct {
13 uid string
14 key string
15 sourceType string
16 priority int
17 source string
18 hash uint64
19 }
20
21 func (c testConfig) UID() string { return c.uid }
22 func (c testConfig) ExposedKey() string { return c.key }
23 func (c testConfig) SourceType() string { return c.sourceType }
24 func (c testConfig) SourceTypePriority() int { return c.priority }
25 func (c testConfig) Source() string { return c.source }
26 func (c testConfig) Hash() uint64 { return c.hash }
27
28 func TestSeenCache_AddAndLookup(t *testing.T) {
29 c := NewSeenCache[testConfig]()
30 cfg := testConfig{uid: "uid1", key: "key1"}
31
32 c.Add(cfg)
33
34 got, ok := c.Lookup(cfg)
35 require.True(t, ok)
36 assert.Equal(t, cfg, got)
37 }
38
39 func TestSeenCache_LookupByUID(t *testing.T) {
40 c := NewSeenCache[testConfig]()
41 cfg := testConfig{uid: "uid1", key: "key1"}
42
43 c.Add(cfg)
44
45 got, ok := c.LookupByUID("uid1")
46 require.True(t, ok)
47 assert.Equal(t, cfg, got)
48
49 _, ok = c.LookupByUID("nonexistent")
50 assert.False(t, ok)
51 }
52
53 func TestSeenCache_Remove(t *testing.T) {
54 c := NewSeenCache[testConfig]()
55 cfg := testConfig{uid: "uid1", key: "key1"}
56
57 c.Add(cfg)
58 c.Remove(cfg)
59
60 _, ok := c.Lookup(cfg)
61 assert.False(t, ok)
62 }
63
64 func TestSeenCache_AddOverwrites(t *testing.T) {
65 c := NewSeenCache[testConfig]()
66 cfg1 := testConfig{uid: "uid1", key: "key1", hash: 100}
67 cfg2 := testConfig{uid: "uid1", key: "key1", hash: 200}
68
69 c.Add(cfg1)
70 c.Add(cfg2)
71
72 got, ok := c.LookupByUID("uid1")
73 require.True(t, ok)
74 assert.Equal(t, uint64(200), got.Hash())
75 }
76
77 func TestSeenCache_RemoveNonexistent(t *testing.T) {
78 c := NewSeenCache[testConfig]()
79 cfg := testConfig{uid: "uid1"}
80
81 // Should not panic.
82 c.Remove(cfg)
83 }
84
85 func TestExposedCache_AddAndLookup(t *testing.T) {
86 c := NewExposedCache[testConfig]()
87 cfg := testConfig{uid: "uid1", key: "key1"}
88 entry := &Entry[testConfig]{Cfg: cfg, Status: StatusAccepted}
89
90 c.Add(entry)
91
92 got, ok := c.LookupByKey("key1")
93 require.True(t, ok)
94 assert.Equal(t, StatusAccepted, got.Status)
95 assert.Equal(t, cfg, got.Cfg)
96 }
97
98 func TestExposedCache_LookupByKey_NotFound(t *testing.T) {
99 c := NewExposedCache[testConfig]()
100
101 _, ok := c.LookupByKey("nonexistent")
102 assert.False(t, ok)
103 }
104
105 func TestExposedCache_Remove(t *testing.T) {
106 c := NewExposedCache[testConfig]()
107 cfg := testConfig{uid: "uid1", key: "key1"}
108 entry := &Entry[testConfig]{Cfg: cfg, Status: StatusAccepted}
109
110 c.Add(entry)
111 c.Remove(cfg)
112
113 _, ok := c.LookupByKey("key1")
114 assert.False(t, ok)
115 }
116
117 func TestExposedCache_AddOverwritesByKey(t *testing.T) {
118 c := NewExposedCache[testConfig]()
119 cfg1 := testConfig{uid: "uid1", key: "key1"}
120 cfg2 := testConfig{uid: "uid2", key: "key1"} // same Key, different UID
121 entry1 := &Entry[testConfig]{Cfg: cfg1, Status: StatusRunning}
122 entry2 := &Entry[testConfig]{Cfg: cfg2, Status: StatusAccepted}
123
124 c.Add(entry1)
125 c.Add(entry2)
126
127 got, ok := c.LookupByKey("key1")
128 require.True(t, ok)
129 assert.Equal(t, "uid2", got.Cfg.UID())
130 assert.Equal(t, StatusAccepted, got.Status)
131 }
132
133 func TestExposedCache_PointerMutationVisible(t *testing.T) {
134 c := NewExposedCache[testConfig]()
135 cfg := testConfig{uid: "uid1", key: "key1"}
136 entry := &Entry[testConfig]{Cfg: cfg, Status: StatusAccepted}
137
138 c.Add(entry)
139
140 got, ok := c.LookupByKey("key1")
141 require.True(t, ok)
142
143 // Mutating through the returned pointer updates the cache.
144 got.Status = StatusRunning
145
146 got2, _ := c.LookupByKey("key1")
147 assert.Equal(t, StatusRunning, got2.Status)
148 }
149
150 func TestExposedCache_Count(t *testing.T) {
151 c := NewExposedCache[testConfig]()
152 assert.Equal(t, 0, c.Count())
153
154 c.Add(&Entry[testConfig]{Cfg: testConfig{key: "a"}})
155 c.Add(&Entry[testConfig]{Cfg: testConfig{key: "b"}})
156 assert.Equal(t, 2, c.Count())
157
158 c.Remove(testConfig{key: "a"})
159 assert.Equal(t, 1, c.Count())
160 }
161
162 func TestExposedCache_ForEach(t *testing.T) {
163 c := NewExposedCache[testConfig]()
164 c.Add(&Entry[testConfig]{Cfg: testConfig{key: "a"}, Status: StatusRunning})
165 c.Add(&Entry[testConfig]{Cfg: testConfig{key: "b"}, Status: StatusDisabled})
166
167 keys := make(map[string]Status)
168 c.ForEach(func(key string, entry *Entry[testConfig]) bool {
169 keys[key] = entry.Status
170 return true
171 })
172
173 assert.Len(t, keys, 2)
174 assert.Equal(t, StatusRunning, keys["a"])
175 assert.Equal(t, StatusDisabled, keys["b"])
176 }
177
178 func TestExposedCache_ForEach_EarlyStop(t *testing.T) {
179 c := NewExposedCache[testConfig]()
180 c.Add(&Entry[testConfig]{Cfg: testConfig{key: "a"}})
181 c.Add(&Entry[testConfig]{Cfg: testConfig{key: "b"}})
182 c.Add(&Entry[testConfig]{Cfg: testConfig{key: "c"}})
183
184 count := 0
185 c.ForEach(func(_ string, _ *Entry[testConfig]) bool {
186 count++
187 return false // stop after first
188 })
189
190 assert.Equal(t, 1, count)
191 }