Skip to content

Commit ab60c73

Browse files
committed
Test icingaredis.SetChecksums()
1 parent 7aa4cde commit ab60c73

File tree

1 file changed

+234
-9
lines changed

1 file changed

+234
-9
lines changed

pkg/icingaredis/utils_test.go

Lines changed: 234 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
package icingaredis
22

33
import (
4+
"fmt"
45
"github.com/icinga/icinga-go-library/database"
56
"github.com/icinga/icinga-go-library/redis"
7+
"github.com/icinga/icinga-go-library/types"
68
"github.com/icinga/icingadb/pkg/icingadb/v1"
79
"github.com/stretchr/testify/require"
810
"testing"
911
"time"
1012
)
1113

14+
var latencies = []struct {
15+
name string
16+
latency time.Duration
17+
}{
18+
{"instantly", 0},
19+
{"1us", time.Microsecond},
20+
{"20ms", 20 * time.Millisecond},
21+
}
22+
1223
type testEntity struct {
1324
v1.EntityWithoutChecksum `json:",inline"`
1425
Data int `json:"data"`
@@ -59,15 +70,6 @@ func TestCreateEntities(t *testing.T) {
5970
},
6071
}
6172

62-
latencies := []struct {
63-
name string
64-
latency time.Duration
65-
}{
66-
{"instantly", 0},
67-
{"1us", time.Microsecond},
68-
{"20ms", 20 * time.Millisecond},
69-
}
70-
7173
for _, st := range subtests {
7274
t.Run(st.name, func(t *testing.T) {
7375
for _, l := range latencies {
@@ -145,3 +147,226 @@ func TestCreateEntities(t *testing.T) {
145147
})
146148
}
147149
}
150+
151+
type testEntityWithChecksum struct {
152+
v1.EntityWithChecksum `json:",inline"`
153+
Data types.Binary `json:"data"`
154+
}
155+
156+
func newTestEntityWithChecksum(id, checksum, data []byte) *testEntityWithChecksum {
157+
return &testEntityWithChecksum{
158+
EntityWithChecksum: v1.EntityWithChecksum{
159+
EntityWithoutChecksum: v1.EntityWithoutChecksum{IdMeta: v1.IdMeta{Id: id}},
160+
ChecksumMeta: v1.ChecksumMeta{PropertiesChecksum: checksum},
161+
},
162+
Data: data,
163+
}
164+
}
165+
166+
func newEntityWithChecksum(id, checksum []byte) *v1.EntityWithChecksum {
167+
return &v1.EntityWithChecksum{
168+
EntityWithoutChecksum: v1.EntityWithoutChecksum{IdMeta: v1.IdMeta{Id: id}},
169+
ChecksumMeta: v1.ChecksumMeta{PropertiesChecksum: checksum},
170+
}
171+
}
172+
173+
func TestSetChecksums(t *testing.T) {
174+
subtests := []struct {
175+
name string
176+
input []database.Entity
177+
checksums map[string]database.Entity
178+
output []database.Entity
179+
error bool
180+
}{
181+
{name: "nil"},
182+
{
183+
name: "empty",
184+
checksums: map[string]database.Entity{},
185+
},
186+
{
187+
name: "one",
188+
input: []database.Entity{newTestEntityWithChecksum([]byte{1}, nil, []byte{3})},
189+
checksums: map[string]database.Entity{"01": newEntityWithChecksum([]byte{1}, []byte{2})},
190+
output: []database.Entity{newTestEntityWithChecksum([]byte{1}, []byte{2}, []byte{3})},
191+
},
192+
{
193+
name: "two",
194+
input: []database.Entity{
195+
newTestEntityWithChecksum([]byte{4}, nil, []byte{6}),
196+
newTestEntityWithChecksum([]byte{7}, nil, []byte{9}),
197+
},
198+
checksums: map[string]database.Entity{
199+
"04": newEntityWithChecksum([]byte{4}, []byte{5}),
200+
"07": newEntityWithChecksum([]byte{7}, []byte{8}),
201+
},
202+
output: []database.Entity{
203+
newTestEntityWithChecksum([]byte{4}, []byte{5}, []byte{6}),
204+
newTestEntityWithChecksum([]byte{7}, []byte{8}, []byte{9}),
205+
},
206+
},
207+
{
208+
name: "three",
209+
input: []database.Entity{
210+
newTestEntityWithChecksum([]byte{10}, nil, []byte{12}),
211+
newTestEntityWithChecksum([]byte{13}, nil, []byte{15}),
212+
newTestEntityWithChecksum([]byte{16}, nil, []byte{18}),
213+
},
214+
checksums: map[string]database.Entity{
215+
"0a": newEntityWithChecksum([]byte{10}, []byte{11}),
216+
"0d": newEntityWithChecksum([]byte{13}, []byte{14}),
217+
"10": newEntityWithChecksum([]byte{16}, []byte{17}),
218+
},
219+
output: []database.Entity{
220+
newTestEntityWithChecksum([]byte{10}, []byte{11}, []byte{12}),
221+
newTestEntityWithChecksum([]byte{13}, []byte{14}, []byte{15}),
222+
newTestEntityWithChecksum([]byte{16}, []byte{17}, []byte{18}),
223+
},
224+
},
225+
{
226+
name: "superfluous-checksum",
227+
checksums: map[string]database.Entity{"13": newEntityWithChecksum([]byte{19}, []byte{20})},
228+
},
229+
{
230+
name: "missing-checksum",
231+
input: []database.Entity{newTestEntityWithChecksum([]byte{22}, nil, []byte{24})},
232+
error: true,
233+
},
234+
}
235+
236+
for _, st := range subtests {
237+
t.Run(st.name, func(t *testing.T) {
238+
for _, concurrency := range []int{1, 2, 30} {
239+
t.Run(fmt.Sprint(concurrency), func(t *testing.T) {
240+
for _, l := range latencies {
241+
t.Run(l.name, func(t *testing.T) {
242+
ctx, cancel := context.WithCancel(context.Background())
243+
defer cancel()
244+
245+
input := make(chan database.Entity, 1)
246+
go func() {
247+
defer close(input)
248+
249+
for _, v := range st.input {
250+
if l.latency > 0 {
251+
select {
252+
case <-time.After(l.latency):
253+
case <-ctx.Done():
254+
return
255+
}
256+
}
257+
258+
select {
259+
case input <- v:
260+
case <-ctx.Done():
261+
return
262+
}
263+
}
264+
}()
265+
266+
output, errs := SetChecksums(ctx, input, st.checksums, concurrency)
267+
268+
require.NotNil(t, output, "output channel should not be nil")
269+
require.NotNil(t, errs, "error channel should not be nil")
270+
271+
for _, expected := range st.output {
272+
select {
273+
case actual, ok := <-output:
274+
require.True(t, ok, "output channel should not be closed, yet")
275+
if concurrency == 1 || l.latency >= time.Millisecond {
276+
require.Equal(t, expected, actual)
277+
}
278+
case <-time.After(time.Second):
279+
require.Fail(t, "output channel should not block")
280+
}
281+
}
282+
283+
if st.error {
284+
select {
285+
case err, ok := <-errs:
286+
require.True(t, ok, "error channel should not be closed, yet")
287+
require.Error(t, err)
288+
case <-time.After(time.Second):
289+
require.Fail(t, "error channel should not block")
290+
}
291+
}
292+
293+
select {
294+
case actual, ok := <-output:
295+
require.False(t, ok, "output channel should be closed, got %#v", actual)
296+
case <-time.After(time.Second):
297+
require.Fail(t, "output channel should not block")
298+
}
299+
300+
select {
301+
case err, ok := <-errs:
302+
require.False(t, ok, "error channel should be closed, got %#v", err)
303+
case <-time.After(time.Second):
304+
require.Fail(t, "error channel should not block")
305+
}
306+
})
307+
}
308+
})
309+
}
310+
311+
for _, concurrency := range []int{0, -1, -2, -30} {
312+
t.Run(fmt.Sprint(concurrency), func(t *testing.T) {
313+
ctx, cancel := context.WithCancel(context.Background())
314+
defer cancel()
315+
316+
input := make(chan database.Entity, 1)
317+
input <- nil
318+
319+
output, errs := SetChecksums(ctx, input, st.checksums, concurrency)
320+
321+
require.NotNil(t, output, "output channel should not be nil")
322+
require.NotNil(t, errs, "error channel should not be nil")
323+
324+
select {
325+
case v, ok := <-output:
326+
require.False(t, ok, "output channel should be closed, got %#v", v)
327+
case <-time.After(time.Second):
328+
require.Fail(t, "output channel should not block")
329+
}
330+
331+
select {
332+
case err, ok := <-errs:
333+
require.False(t, ok, "error channel should be closed, got %#v", err)
334+
case <-time.After(time.Second):
335+
require.Fail(t, "error channel should not block")
336+
}
337+
338+
select {
339+
case input <- nil:
340+
require.Fail(t, "input channel should not be read from")
341+
default:
342+
}
343+
})
344+
}
345+
})
346+
}
347+
348+
t.Run("cancel-ctx", func(t *testing.T) {
349+
ctx, cancel := context.WithCancel(context.Background())
350+
cancel()
351+
352+
output, errs := SetChecksums(ctx, make(chan database.Entity), map[string]database.Entity{}, 1)
353+
354+
require.NotNil(t, output, "output channel should not be nil")
355+
require.NotNil(t, errs, "error channel should not be nil")
356+
357+
select {
358+
case v, ok := <-output:
359+
require.False(t, ok, "output channel should be closed, got %#v", v)
360+
case <-time.After(time.Second):
361+
require.Fail(t, "output channel should not block")
362+
}
363+
364+
select {
365+
case err, ok := <-errs:
366+
require.True(t, ok, "error channel should not be closed, yet")
367+
require.Error(t, err)
368+
case <-time.After(time.Second):
369+
require.Fail(t, "error channel should not block")
370+
}
371+
})
372+
}

0 commit comments

Comments
 (0)