github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/querier/ingester_querier_test.go (about)

     1  package querier
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/grafana/dskit/ring"
     9  	"github.com/prometheus/prometheus/model/labels"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/mock"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/grafana/loki/pkg/logproto"
    15  )
    16  
    17  func TestQuerier_tailDisconnectedIngesters(t *testing.T) {
    18  	t.Parallel()
    19  
    20  	tests := map[string]struct {
    21  		connectedIngestersAddr []string
    22  		ringIngesters          []ring.InstanceDesc
    23  		expectedClientsAddr    []string
    24  	}{
    25  		"no connected ingesters and empty ring": {
    26  			connectedIngestersAddr: []string{},
    27  			ringIngesters:          []ring.InstanceDesc{},
    28  			expectedClientsAddr:    []string{},
    29  		},
    30  		"no connected ingesters and ring containing new ingesters": {
    31  			connectedIngestersAddr: []string{},
    32  			ringIngesters:          []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.ACTIVE)},
    33  			expectedClientsAddr:    []string{"1.1.1.1"},
    34  		},
    35  		"connected ingesters and ring contain the same ingesters": {
    36  			connectedIngestersAddr: []string{"1.1.1.1", "2.2.2.2"},
    37  			ringIngesters:          []ring.InstanceDesc{mockInstanceDesc("2.2.2.2", ring.ACTIVE), mockInstanceDesc("1.1.1.1", ring.ACTIVE)},
    38  			expectedClientsAddr:    []string{},
    39  		},
    40  		"ring contains new ingesters compared to the connected one": {
    41  			connectedIngestersAddr: []string{"1.1.1.1"},
    42  			ringIngesters:          []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.ACTIVE), mockInstanceDesc("2.2.2.2", ring.ACTIVE), mockInstanceDesc("3.3.3.3", ring.ACTIVE)},
    43  			expectedClientsAddr:    []string{"2.2.2.2", "3.3.3.3"},
    44  		},
    45  		"connected ingesters contain ingesters not in the ring anymore": {
    46  			connectedIngestersAddr: []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"},
    47  			ringIngesters:          []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.ACTIVE), mockInstanceDesc("3.3.3.3", ring.ACTIVE)},
    48  			expectedClientsAddr:    []string{},
    49  		},
    50  		"connected ingesters contain ingesters not in the ring anymore and the ring contains new ingesters too": {
    51  			connectedIngestersAddr: []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"},
    52  			ringIngesters:          []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.ACTIVE), mockInstanceDesc("3.3.3.3", ring.ACTIVE), mockInstanceDesc("4.4.4.4", ring.ACTIVE)},
    53  			expectedClientsAddr:    []string{"4.4.4.4"},
    54  		},
    55  		"ring contains ingester in LEAVING state not listed in the connected ingesters": {
    56  			connectedIngestersAddr: []string{"1.1.1.1"},
    57  			ringIngesters:          []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.ACTIVE), mockInstanceDesc("2.2.2.2", ring.LEAVING)},
    58  			expectedClientsAddr:    []string{},
    59  		},
    60  		"ring contains ingester in PENDING state not listed in the connected ingesters": {
    61  			connectedIngestersAddr: []string{"1.1.1.1"},
    62  			ringIngesters:          []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.ACTIVE), mockInstanceDesc("2.2.2.2", ring.PENDING)},
    63  			expectedClientsAddr:    []string{},
    64  		},
    65  	}
    66  
    67  	for testName, testData := range tests {
    68  		testData := testData
    69  
    70  		t.Run(testName, func(t *testing.T) {
    71  			req := logproto.TailRequest{
    72  				Query:    "{type=\"test\"}",
    73  				DelayFor: 0,
    74  				Limit:    10,
    75  				Start:    time.Now(),
    76  			}
    77  
    78  			// For this test's purpose, whenever a new ingester client needs to
    79  			// be created, the factory will always return the same mock instance
    80  			ingesterClient := newQuerierClientMock()
    81  			ingesterClient.On("Tail", mock.Anything, &req, mock.Anything).Return(newTailClientMock(), nil)
    82  
    83  			ingesterQuerier, err := newIngesterQuerier(
    84  				mockIngesterClientConfig(),
    85  				newReadRingMock(testData.ringIngesters),
    86  				mockQuerierConfig().ExtraQueryDelay,
    87  				newIngesterClientMockFactory(ingesterClient),
    88  			)
    89  			require.NoError(t, err)
    90  
    91  			actualClients, err := ingesterQuerier.TailDisconnectedIngesters(context.Background(), &req, testData.connectedIngestersAddr)
    92  			require.NoError(t, err)
    93  
    94  			actualClientsAddr := make([]string, 0, len(actualClients))
    95  			for addr, client := range actualClients {
    96  				actualClientsAddr = append(actualClientsAddr, addr)
    97  
    98  				// The returned map of clients should never contain nil values
    99  				assert.NotNil(t, client)
   100  			}
   101  
   102  			assert.ElementsMatch(t, testData.expectedClientsAddr, actualClientsAddr)
   103  		})
   104  	}
   105  }
   106  
   107  func TestConvertMatchersToString(t *testing.T) {
   108  	for _, tc := range []struct {
   109  		name     string
   110  		matchers []*labels.Matcher
   111  		expected string
   112  	}{
   113  		{
   114  			name:     "empty matchers",
   115  			matchers: []*labels.Matcher{},
   116  			expected: "{}",
   117  		},
   118  		{
   119  			name: "with matchers",
   120  			matchers: []*labels.Matcher{
   121  				labels.MustNewMatcher(labels.MatchEqual, "foo", "equal"),
   122  				labels.MustNewMatcher(labels.MatchNotEqual, "bar", "not-equal"),
   123  			},
   124  			expected: "{foo=\"equal\",bar!=\"not-equal\"}",
   125  		},
   126  	} {
   127  		t.Run(tc.name, func(t *testing.T) {
   128  			require.Equal(t, tc.expected, convertMatchersToString(tc.matchers))
   129  		})
   130  	}
   131  }