github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/clients/pkg/promtail/client/batch_test.go (about)

     1  package client
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/prometheus/common/model"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/grafana/loki/clients/pkg/promtail/api"
    13  
    14  	"github.com/grafana/loki/pkg/logproto"
    15  )
    16  
    17  func TestBatch_add(t *testing.T) {
    18  	t.Parallel()
    19  
    20  	tests := map[string]struct {
    21  		inputEntries      []api.Entry
    22  		expectedSizeBytes int
    23  	}{
    24  		"empty batch": {
    25  			inputEntries:      []api.Entry{},
    26  			expectedSizeBytes: 0,
    27  		},
    28  		"single stream with single log entry": {
    29  			inputEntries: []api.Entry{
    30  				{Labels: model.LabelSet{}, Entry: logEntries[0].Entry},
    31  			},
    32  			expectedSizeBytes: len(logEntries[0].Entry.Line),
    33  		},
    34  		"single stream with multiple log entries": {
    35  			inputEntries: []api.Entry{
    36  				{Labels: model.LabelSet{}, Entry: logEntries[0].Entry},
    37  				{Labels: model.LabelSet{}, Entry: logEntries[1].Entry},
    38  			},
    39  			expectedSizeBytes: len(logEntries[0].Entry.Line) + len(logEntries[1].Entry.Line),
    40  		},
    41  		"multiple streams with multiple log entries": {
    42  			inputEntries: []api.Entry{
    43  				{Labels: model.LabelSet{"type": "a"}, Entry: logEntries[0].Entry},
    44  				{Labels: model.LabelSet{"type": "a"}, Entry: logEntries[1].Entry},
    45  				{Labels: model.LabelSet{"type": "b"}, Entry: logEntries[2].Entry},
    46  			},
    47  			expectedSizeBytes: len(logEntries[0].Entry.Line) + len(logEntries[1].Entry.Line) + len(logEntries[2].Entry.Line),
    48  		},
    49  	}
    50  
    51  	for testName, testData := range tests {
    52  		testData := testData
    53  
    54  		t.Run(testName, func(t *testing.T) {
    55  			b := newBatch()
    56  
    57  			for _, entry := range testData.inputEntries {
    58  				b.add(entry)
    59  			}
    60  
    61  			assert.Equal(t, testData.expectedSizeBytes, b.sizeBytes())
    62  		})
    63  	}
    64  }
    65  
    66  func TestBatch_encode(t *testing.T) {
    67  	t.Parallel()
    68  
    69  	tests := map[string]struct {
    70  		inputBatch           *batch
    71  		expectedEntriesCount int
    72  	}{
    73  		"empty batch": {
    74  			inputBatch:           newBatch(),
    75  			expectedEntriesCount: 0,
    76  		},
    77  		"single stream with single log entry": {
    78  			inputBatch: newBatch(
    79  				api.Entry{Labels: model.LabelSet{}, Entry: logEntries[0].Entry},
    80  			),
    81  			expectedEntriesCount: 1,
    82  		},
    83  		"single stream with multiple log entries": {
    84  			inputBatch: newBatch(
    85  				api.Entry{Labels: model.LabelSet{}, Entry: logEntries[0].Entry},
    86  				api.Entry{Labels: model.LabelSet{}, Entry: logEntries[1].Entry},
    87  			),
    88  			expectedEntriesCount: 2,
    89  		},
    90  		"multiple streams with multiple log entries": {
    91  			inputBatch: newBatch(
    92  				api.Entry{Labels: model.LabelSet{"type": "a"}, Entry: logEntries[0].Entry},
    93  				api.Entry{Labels: model.LabelSet{"type": "a"}, Entry: logEntries[1].Entry},
    94  				api.Entry{Labels: model.LabelSet{"type": "b"}, Entry: logEntries[2].Entry},
    95  			),
    96  			expectedEntriesCount: 3,
    97  		},
    98  	}
    99  
   100  	for testName, testData := range tests {
   101  		testData := testData
   102  
   103  		t.Run(testName, func(t *testing.T) {
   104  			t.Parallel()
   105  
   106  			_, entriesCount, err := testData.inputBatch.encode()
   107  			require.NoError(t, err)
   108  			assert.Equal(t, testData.expectedEntriesCount, entriesCount)
   109  		})
   110  	}
   111  }
   112  
   113  func TestHashCollisions(t *testing.T) {
   114  	b := newBatch()
   115  
   116  	ls1 := model.LabelSet{"app": "l", "uniq0": "0", "uniq1": "1"}
   117  	ls2 := model.LabelSet{"app": "m", "uniq0": "1", "uniq1": "1"}
   118  
   119  	require.False(t, ls1.Equal(ls2))
   120  	require.Equal(t, ls1.FastFingerprint(), ls2.FastFingerprint())
   121  
   122  	const entriesPerLabel = 10
   123  
   124  	for i := 0; i < entriesPerLabel; i++ {
   125  		b.add(api.Entry{Labels: ls1, Entry: logproto.Entry{Timestamp: time.Now(), Line: fmt.Sprintf("line %d", i)}})
   126  		b.add(api.Entry{Labels: ls2, Entry: logproto.Entry{Timestamp: time.Now(), Line: fmt.Sprintf("line %d", i)}})
   127  	}
   128  
   129  	// make sure that colliding labels are stored properly as independent streams
   130  	req, entries := b.createPushRequest()
   131  	assert.Len(t, req.Streams, 2)
   132  	assert.Equal(t, 2*entriesPerLabel, entries)
   133  
   134  	if req.Streams[0].Labels == ls1.String() {
   135  		assert.Equal(t, ls1.String(), req.Streams[0].Labels)
   136  		assert.Equal(t, ls2.String(), req.Streams[1].Labels)
   137  	} else {
   138  		assert.Equal(t, ls2.String(), req.Streams[0].Labels)
   139  		assert.Equal(t, ls1.String(), req.Streams[1].Labels)
   140  	}
   141  }