Skip to content

Commit e5dc8b8

Browse files
committed
Test icingaredis.SetChecksums()
1 parent 1d04ffe commit e5dc8b8

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
@@ -2,14 +2,25 @@ package icingaredis
22

33
import (
44
"context"
5+
"fmt"
56
"github.com/icinga/icinga-go-library/database"
67
"github.com/icinga/icinga-go-library/redis"
8+
"github.com/icinga/icinga-go-library/types"
79
"github.com/icinga/icingadb/pkg/icingadb/v1"
810
"github.com/stretchr/testify/require"
911
"testing"
1012
"time"
1113
)
1214

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

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

0 commit comments

Comments
 (0)