Skip to content

Commit 8052ede

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

File tree

1 file changed

+235
-9
lines changed

1 file changed

+235
-9
lines changed

pkg/icingaredis/utils_test.go

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

33
import (
4+
"context"
5+
"fmt"
46
"github.com/icinga/icinga-go-library/database"
57
"github.com/icinga/icinga-go-library/redis"
8+
"github.com/icinga/icinga-go-library/types"
69
"github.com/icinga/icingadb/pkg/icingadb/v1"
710
"github.com/stretchr/testify/require"
811
"testing"
912
"time"
1013
)
1114

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+
1224
type testEntity struct {
1325
v1.EntityWithoutChecksum `json:",inline"`
1426
Data int `json:"data"`
@@ -59,15 +71,6 @@ func TestCreateEntities(t *testing.T) {
5971
},
6072
}
6173

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

0 commit comments

Comments
 (0)