github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/storage/stores/tsdb/index/chunk_test.go (about)

     1  package index
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  )
     9  
    10  // Test all sort variants
    11  func TestChunkMetasSort(t *testing.T) {
    12  	for _, tc := range []struct {
    13  		desc string
    14  		a, b ChunkMeta
    15  	}{
    16  		{
    17  			desc: "prefer mintime",
    18  			a: ChunkMeta{
    19  				MinTime: 0,
    20  				MaxTime: 5,
    21  			},
    22  			b: ChunkMeta{
    23  				MinTime: 1,
    24  				MaxTime: 4,
    25  			},
    26  		},
    27  		{
    28  			desc: "delegate maxtime",
    29  			a: ChunkMeta{
    30  				MaxTime:  2,
    31  				Checksum: 2,
    32  			},
    33  			b: ChunkMeta{
    34  				MaxTime:  3,
    35  				Checksum: 1,
    36  			},
    37  		},
    38  		{
    39  			desc: "delegate checksum",
    40  			a: ChunkMeta{
    41  				Checksum: 1,
    42  			},
    43  			b: ChunkMeta{
    44  				Checksum: 2,
    45  			},
    46  		},
    47  	} {
    48  		t.Run(tc.desc, func(t *testing.T) {
    49  			xs := ChunkMetas{tc.a, tc.b}
    50  			require.Equal(t, true, xs.Less(0, 1))
    51  			require.Equal(t, false, xs.Less(1, 0))
    52  		})
    53  	}
    54  }
    55  
    56  func TestChunkMetasFinalize(t *testing.T) {
    57  	mkMeta := func(x int) ChunkMeta {
    58  		return ChunkMeta{
    59  			MinTime:  int64(x),
    60  			Checksum: uint32(x),
    61  		}
    62  	}
    63  	for _, tc := range []struct {
    64  		desc          string
    65  		input, output ChunkMetas
    66  	}{
    67  		{
    68  			desc: "reorder",
    69  			input: []ChunkMeta{
    70  				mkMeta(2),
    71  				mkMeta(1),
    72  				mkMeta(3),
    73  			},
    74  			output: []ChunkMeta{
    75  				mkMeta(1),
    76  				mkMeta(2),
    77  				mkMeta(3),
    78  			},
    79  		},
    80  		{
    81  			desc: "remove duplicates",
    82  			input: []ChunkMeta{
    83  				mkMeta(1),
    84  				mkMeta(2),
    85  				mkMeta(2),
    86  				mkMeta(3),
    87  			},
    88  			output: []ChunkMeta{
    89  				mkMeta(1),
    90  				mkMeta(2),
    91  				mkMeta(3),
    92  			},
    93  		},
    94  		{
    95  			desc: "remove trailing duplicates",
    96  			input: []ChunkMeta{
    97  				mkMeta(1),
    98  				mkMeta(2),
    99  				mkMeta(2),
   100  				mkMeta(3),
   101  				mkMeta(4),
   102  				mkMeta(4),
   103  				mkMeta(5),
   104  				mkMeta(5),
   105  			},
   106  			output: []ChunkMeta{
   107  				mkMeta(1),
   108  				mkMeta(2),
   109  				mkMeta(3),
   110  				mkMeta(4),
   111  				mkMeta(5),
   112  			},
   113  		},
   114  		{
   115  			desc: "cleanup after last duplicate",
   116  			input: []ChunkMeta{
   117  				mkMeta(1),
   118  				mkMeta(2),
   119  				mkMeta(2),
   120  				mkMeta(3),
   121  				mkMeta(4),
   122  				mkMeta(5),
   123  				mkMeta(5),
   124  				mkMeta(6),
   125  				mkMeta(7),
   126  			},
   127  			output: []ChunkMeta{
   128  				mkMeta(1),
   129  				mkMeta(2),
   130  				mkMeta(3),
   131  				mkMeta(4),
   132  				mkMeta(5),
   133  				mkMeta(6),
   134  				mkMeta(7),
   135  			},
   136  		},
   137  	} {
   138  		t.Run(tc.desc, func(t *testing.T) {
   139  			require.Equal(t, tc.output, tc.input.Finalize())
   140  		})
   141  	}
   142  }
   143  
   144  func TestChunkMetas_Add(t *testing.T) {
   145  	chunkMetas := ChunkMetas{
   146  		{
   147  			MinTime:  1,
   148  			MaxTime:  1,
   149  			Checksum: 1,
   150  		},
   151  		{
   152  			MinTime:  2,
   153  			MaxTime:  3,
   154  			Checksum: 1,
   155  		},
   156  		{
   157  			MinTime:  4,
   158  			MaxTime:  5,
   159  			Checksum: 1,
   160  		},
   161  		{
   162  			MinTime:  4,
   163  			MaxTime:  6,
   164  			Checksum: 1,
   165  		},
   166  		{
   167  			MinTime:  4,
   168  			MaxTime:  6,
   169  			Checksum: 2,
   170  		},
   171  	}.Finalize()
   172  
   173  	for i, tc := range []struct {
   174  		chunkMetas  ChunkMetas
   175  		toAdd       ChunkMeta
   176  		expectedPos int
   177  	}{
   178  		// no existing chunks
   179  		{
   180  			chunkMetas: ChunkMetas{},
   181  			toAdd:      ChunkMeta{MinTime: 0},
   182  		},
   183  		// add to the beginning
   184  		{
   185  			chunkMetas: chunkMetas,
   186  			toAdd:      ChunkMeta{MinTime: 0},
   187  		},
   188  		{
   189  			chunkMetas: chunkMetas,
   190  			toAdd: ChunkMeta{
   191  				MinTime:  1,
   192  				MaxTime:  1,
   193  				Checksum: 0,
   194  			},
   195  		},
   196  		// add in between
   197  		{
   198  			chunkMetas: chunkMetas,
   199  			toAdd: ChunkMeta{
   200  				MinTime: 2,
   201  				MaxTime: 2,
   202  			},
   203  			expectedPos: 1,
   204  		},
   205  		{
   206  			chunkMetas: chunkMetas,
   207  			toAdd: ChunkMeta{
   208  				MinTime:  3,
   209  				MaxTime:  5,
   210  				Checksum: 1,
   211  			},
   212  			expectedPos: 2,
   213  		},
   214  		{
   215  			chunkMetas: chunkMetas,
   216  			toAdd: ChunkMeta{
   217  				MinTime:  4,
   218  				MaxTime:  4,
   219  				Checksum: 1,
   220  			},
   221  			expectedPos: 2,
   222  		},
   223  		{
   224  			chunkMetas: chunkMetas,
   225  			toAdd: ChunkMeta{
   226  				MinTime:  4,
   227  				MaxTime:  5,
   228  				Checksum: 0,
   229  			},
   230  			expectedPos: 2,
   231  		},
   232  		// add to the end
   233  		{
   234  			chunkMetas: chunkMetas,
   235  			toAdd: ChunkMeta{
   236  				MinTime:  5,
   237  				MaxTime:  6,
   238  				Checksum: 2,
   239  			},
   240  			expectedPos: 5,
   241  		},
   242  		{
   243  			chunkMetas: chunkMetas,
   244  			toAdd: ChunkMeta{
   245  				MinTime:  4,
   246  				MaxTime:  7,
   247  				Checksum: 2,
   248  			},
   249  			expectedPos: 5,
   250  		},
   251  		{
   252  			chunkMetas: chunkMetas,
   253  			toAdd: ChunkMeta{
   254  				MinTime:  4,
   255  				MaxTime:  6,
   256  				Checksum: 3,
   257  			},
   258  			expectedPos: 5,
   259  		},
   260  		// chunk already exists
   261  		{
   262  			chunkMetas: chunkMetas,
   263  			toAdd: ChunkMeta{
   264  				MinTime:  4,
   265  				MaxTime:  6,
   266  				Checksum: 2,
   267  			},
   268  			expectedPos: 4,
   269  		},
   270  	} {
   271  		t.Run(fmt.Sprint(i), func(t *testing.T) {
   272  			chunkMetasCopy := make(ChunkMetas, len(tc.chunkMetas))
   273  			copy(chunkMetasCopy, tc.chunkMetas)
   274  			chunkMetasCopy = append(chunkMetasCopy, tc.toAdd)
   275  
   276  			chunkMetas := tc.chunkMetas.Add(tc.toAdd)
   277  			require.Equal(t, chunkMetasCopy.Finalize(), chunkMetas)
   278  			require.Equal(t, tc.toAdd, chunkMetas[tc.expectedPos])
   279  		})
   280  	}
   281  }
   282  
   283  func TestChunkMetas_Drop(t *testing.T) {
   284  	chunkMetas := ChunkMetas{
   285  		{
   286  			MinTime:  1,
   287  			MaxTime:  1,
   288  			Checksum: 1,
   289  		},
   290  		{
   291  			MinTime:  2,
   292  			MaxTime:  3,
   293  			Checksum: 1,
   294  		},
   295  		{
   296  			MinTime:  4,
   297  			MaxTime:  5,
   298  			Checksum: 1,
   299  		},
   300  		{
   301  			MinTime:  4,
   302  			MaxTime:  6,
   303  			Checksum: 1,
   304  		},
   305  		{
   306  			MinTime:  4,
   307  			MaxTime:  6,
   308  			Checksum: 2,
   309  		},
   310  	}.Finalize()
   311  
   312  	// dropChunkMeta makes a copy of ChunkMetas and drops the element at index i
   313  	dropChunkMeta := func(i int) ChunkMetas {
   314  		chunkMetasCopy := make(ChunkMetas, len(chunkMetas))
   315  		copy(chunkMetasCopy, chunkMetas)
   316  
   317  		return append(chunkMetasCopy[:i], chunkMetasCopy[i+1:]...)
   318  	}
   319  
   320  	for i, tc := range []struct {
   321  		chunkMetas         ChunkMetas
   322  		toDrop             ChunkMeta
   323  		expectedChunkMetas ChunkMetas
   324  		expectedChunkFound bool
   325  	}{
   326  		// no existing chunk
   327  		{
   328  			chunkMetas:         ChunkMetas{},
   329  			toDrop:             ChunkMeta{MinTime: 0},
   330  			expectedChunkMetas: ChunkMetas{},
   331  		},
   332  		// drop the first chunk
   333  		{
   334  			chunkMetas:         chunkMetas,
   335  			toDrop:             chunkMetas[0],
   336  			expectedChunkMetas: dropChunkMeta(0),
   337  			expectedChunkFound: true,
   338  		},
   339  		// drop in between
   340  		{
   341  			chunkMetas:         chunkMetas,
   342  			toDrop:             chunkMetas[1],
   343  			expectedChunkMetas: dropChunkMeta(1),
   344  			expectedChunkFound: true,
   345  		},
   346  		{
   347  			chunkMetas:         chunkMetas,
   348  			toDrop:             chunkMetas[2],
   349  			expectedChunkMetas: dropChunkMeta(2),
   350  			expectedChunkFound: true,
   351  		},
   352  		// drop from the end
   353  		{
   354  			chunkMetas:         chunkMetas,
   355  			toDrop:             chunkMetas[len(chunkMetas)-1],
   356  			expectedChunkMetas: dropChunkMeta(len(chunkMetas) - 1),
   357  			expectedChunkFound: true,
   358  		},
   359  	} {
   360  		t.Run(fmt.Sprint(i), func(t *testing.T) {
   361  			chunkMetasCopy := make(ChunkMetas, len(tc.chunkMetas))
   362  			copy(chunkMetasCopy, tc.chunkMetas)
   363  
   364  			chunkMetasCopy, chunkFound := chunkMetasCopy.Drop(tc.toDrop)
   365  			require.Equal(t, tc.expectedChunkFound, chunkFound)
   366  			require.Equal(t, tc.expectedChunkMetas, chunkMetasCopy)
   367  		})
   368  	}
   369  }