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  }