github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/ingester/tailer_test.go (about) 1 package ingester 2 3 import ( 4 "context" 5 "math/rand" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/prometheus/prometheus/model/labels" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 "github.com/grafana/loki/pkg/logproto" 15 ) 16 17 func TestTailer_sendRaceConditionOnSendWhileClosing(t *testing.T) { 18 runs := 100 19 20 stream := logproto.Stream{ 21 Labels: `{type="test"}`, 22 Entries: []logproto.Entry{ 23 {Timestamp: time.Unix(int64(1), 0), Line: "line 1"}, 24 {Timestamp: time.Unix(int64(2), 0), Line: "line 2"}, 25 }, 26 } 27 28 for run := 0; run < runs; run++ { 29 tailer, err := newTailer("org-id", stream.Labels, nil, 10) 30 require.NoError(t, err) 31 require.NotNil(t, tailer) 32 33 routines := sync.WaitGroup{} 34 routines.Add(2) 35 36 go assert.NotPanics(t, func() { 37 defer routines.Done() 38 time.Sleep(time.Duration(rand.Intn(1000)) * time.Microsecond) 39 tailer.send(stream, labels.Labels{{Name: "type", Value: "test"}}) 40 }) 41 42 go assert.NotPanics(t, func() { 43 defer routines.Done() 44 time.Sleep(time.Duration(rand.Intn(1000)) * time.Microsecond) 45 tailer.close() 46 }) 47 48 routines.Wait() 49 } 50 } 51 52 func Test_dropstream(t *testing.T) { 53 maxDroppedStreams := 10 54 55 entry := logproto.Entry{Timestamp: time.Now(), Line: "foo"} 56 57 cases := []struct { 58 name string 59 drop int 60 expected int 61 }{ 62 { 63 name: "less than maxDroppedStreams", 64 drop: maxDroppedStreams - 2, 65 expected: maxDroppedStreams - 2, 66 }, 67 { 68 name: "equal to maxDroppedStreams", 69 drop: maxDroppedStreams, 70 expected: maxDroppedStreams, 71 }, 72 { 73 name: "greater than maxDroppedStreams", 74 drop: maxDroppedStreams + 2, 75 expected: 2, // should be bounded to maxDroppedStreams 76 }, 77 } 78 79 for _, c := range cases { 80 t.Run(c.name, func(t *testing.T) { 81 tail, err := newTailer("foo", `{app="foo"} |= "foo"`, &fakeTailServer{}, maxDroppedStreams) 82 require.NoError(t, err) 83 84 for i := 0; i < c.drop; i++ { 85 tail.dropStream(logproto.Stream{ 86 Entries: []logproto.Entry{ 87 entry, 88 }, 89 }) 90 } 91 assert.Equal(t, c.expected, len(tail.droppedStreams)) 92 }) 93 } 94 } 95 96 type fakeTailServer struct{} 97 98 func (f *fakeTailServer) Send(*logproto.TailResponse) error { return nil } 99 func (f *fakeTailServer) Context() context.Context { return context.Background() } 100 101 func Test_TailerSendRace(t *testing.T) { 102 tail, err := newTailer("foo", `{app="foo"} |= "foo"`, &fakeTailServer{}, 10) 103 require.NoError(t, err) 104 105 var wg sync.WaitGroup 106 for i := 1; i <= 20; i++ { 107 wg.Add(1) 108 go func() { 109 lbs := makeRandomLabels() 110 tail.send(logproto.Stream{ 111 Labels: lbs.String(), 112 Entries: []logproto.Entry{ 113 {Timestamp: time.Unix(0, 1), Line: "1"}, 114 {Timestamp: time.Unix(0, 2), Line: "2"}, 115 {Timestamp: time.Unix(0, 3), Line: "3"}, 116 }, 117 }, lbs) 118 wg.Done() 119 }() 120 } 121 wg.Wait() 122 } 123 124 func Test_IsMatching(t *testing.T) { 125 for _, tt := range []struct { 126 name string 127 lbs labels.Labels 128 matchers []*labels.Matcher 129 matches bool 130 }{ 131 {"not in lbs", labels.Labels{{Name: "job", Value: "foo"}}, []*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}, false}, 132 {"equal", labels.Labels{{Name: "job", Value: "foo"}}, []*labels.Matcher{{Type: labels.MatchEqual, Name: "job", Value: "foo"}}, true}, 133 {"regex", labels.Labels{{Name: "job", Value: "foo"}}, []*labels.Matcher{labels.MustNewMatcher(labels.MatchRegexp, "job", ".+oo")}, true}, 134 } { 135 t.Run(tt.name, func(t *testing.T) { 136 require.Equal(t, tt.matches, isMatching(tt.lbs, tt.matchers)) 137 }) 138 } 139 }