github.com/sequix/cortex@v1.1.6/pkg/chunk/storage/index_client_test.go (about)

     1  package storage
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/sequix/cortex/pkg/chunk"
    12  	"github.com/sequix/cortex/pkg/chunk/cache"
    13  )
    14  
    15  func TestIndexBasic(t *testing.T) {
    16  	forAllFixtures(t, func(t *testing.T, client chunk.IndexClient, _ chunk.ObjectClient) {
    17  		// Write out 30 entries, into different hash and range values.
    18  		batch := client.NewWriteBatch()
    19  		for i := 0; i < 30; i++ {
    20  			batch.Add(tableName, fmt.Sprintf("hash%d", i), []byte(fmt.Sprintf("range%d", i)), nil)
    21  		}
    22  		err := client.BatchWrite(ctx, batch)
    23  		require.NoError(t, err)
    24  
    25  		// Make sure we get back the correct entries by hash value.
    26  		for i := 0; i < 30; i++ {
    27  			entries := []chunk.IndexQuery{
    28  				{
    29  					TableName: tableName,
    30  					HashValue: fmt.Sprintf("hash%d", i),
    31  				},
    32  			}
    33  			var have []chunk.IndexEntry
    34  			err := client.QueryPages(ctx, entries, func(_ chunk.IndexQuery, read chunk.ReadBatch) bool {
    35  				iter := read.Iterator()
    36  				for iter.Next() {
    37  					have = append(have, chunk.IndexEntry{
    38  						RangeValue: iter.RangeValue(),
    39  					})
    40  				}
    41  				return true
    42  			})
    43  			require.NoError(t, err)
    44  			require.Equal(t, []chunk.IndexEntry{
    45  				{RangeValue: []byte(fmt.Sprintf("range%d", i))},
    46  			}, have)
    47  		}
    48  	})
    49  }
    50  
    51  var entries = []chunk.IndexEntry{
    52  	{
    53  		TableName:  tableName,
    54  		HashValue:  "foo",
    55  		RangeValue: []byte("bar:1"),
    56  		Value:      []byte("10"),
    57  	},
    58  	{
    59  		TableName:  tableName,
    60  		HashValue:  "foo",
    61  		RangeValue: []byte("bar:2"),
    62  		Value:      []byte("20"),
    63  	},
    64  	{
    65  		TableName:  tableName,
    66  		HashValue:  "foo",
    67  		RangeValue: []byte("bar:3"),
    68  		Value:      []byte("30"),
    69  	},
    70  	{
    71  		TableName:  tableName,
    72  		HashValue:  "foo",
    73  		RangeValue: []byte("baz:1"),
    74  		Value:      []byte("10"),
    75  	},
    76  	{
    77  		TableName:  tableName,
    78  		HashValue:  "foo",
    79  		RangeValue: []byte("baz:2"),
    80  		Value:      []byte("20"),
    81  	},
    82  	{
    83  		TableName:  tableName,
    84  		HashValue:  "flip",
    85  		RangeValue: []byte("bar:1"),
    86  		Value:      []byte("abc"),
    87  	},
    88  	{
    89  		TableName:  tableName,
    90  		HashValue:  "flip",
    91  		RangeValue: []byte("bar:2"),
    92  		Value:      []byte("abc"),
    93  	},
    94  	{
    95  		TableName:  tableName,
    96  		HashValue:  "flip",
    97  		RangeValue: []byte("bar:3"),
    98  		Value:      []byte("abc"),
    99  	},
   100  }
   101  
   102  func TestQueryPages(t *testing.T) {
   103  	forAllFixtures(t, func(t *testing.T, client chunk.IndexClient, _ chunk.ObjectClient) {
   104  		batch := client.NewWriteBatch()
   105  		for _, entry := range entries {
   106  			batch.Add(entry.TableName, entry.HashValue, entry.RangeValue, entry.Value)
   107  		}
   108  
   109  		err := client.BatchWrite(ctx, batch)
   110  		require.NoError(t, err)
   111  
   112  		tests := []struct {
   113  			name   string
   114  			query  chunk.IndexQuery
   115  			repeat bool
   116  			want   []chunk.IndexEntry
   117  		}{
   118  			{
   119  				"check HashValue only",
   120  				chunk.IndexQuery{
   121  					TableName: tableName,
   122  					HashValue: "flip",
   123  				},
   124  				false,
   125  				[]chunk.IndexEntry{entries[5], entries[6], entries[7]},
   126  			},
   127  			{
   128  				"check RangeValueStart",
   129  				chunk.IndexQuery{
   130  					TableName:       tableName,
   131  					HashValue:       "foo",
   132  					RangeValueStart: []byte("bar:2"),
   133  				},
   134  				false,
   135  				[]chunk.IndexEntry{entries[1], entries[2], entries[3], entries[4]},
   136  			},
   137  			{
   138  				"check RangeValuePrefix",
   139  				chunk.IndexQuery{
   140  					TableName:        tableName,
   141  					HashValue:        "foo",
   142  					RangeValuePrefix: []byte("baz:"),
   143  				},
   144  				false,
   145  				[]chunk.IndexEntry{entries[3], entries[4]},
   146  			},
   147  			{
   148  				"check ValueEqual",
   149  				chunk.IndexQuery{
   150  					TableName:        tableName,
   151  					HashValue:        "foo",
   152  					RangeValuePrefix: []byte("bar"),
   153  					ValueEqual:       []byte("20"),
   154  				},
   155  				false,
   156  				[]chunk.IndexEntry{entries[1]},
   157  			},
   158  			{
   159  				"check retry logic",
   160  				chunk.IndexQuery{
   161  					TableName:        tableName,
   162  					HashValue:        "foo",
   163  					RangeValuePrefix: []byte("bar"),
   164  					ValueEqual:       []byte("20"),
   165  				},
   166  				true,
   167  				[]chunk.IndexEntry{entries[1]},
   168  			},
   169  		}
   170  
   171  		for _, tt := range tests {
   172  			t.Run(tt.name, func(t *testing.T) {
   173  				run := true
   174  				for run {
   175  					var have []chunk.IndexEntry
   176  					err = client.QueryPages(ctx, []chunk.IndexQuery{tt.query}, func(_ chunk.IndexQuery, read chunk.ReadBatch) bool {
   177  						iter := read.Iterator()
   178  						for iter.Next() {
   179  							have = append(have, chunk.IndexEntry{
   180  								TableName:  tt.query.TableName,
   181  								HashValue:  tt.query.HashValue,
   182  								RangeValue: iter.RangeValue(),
   183  								Value:      iter.Value(),
   184  							})
   185  						}
   186  						return true
   187  					})
   188  					require.NoError(t, err)
   189  					require.Equal(t, tt.want, have)
   190  
   191  					if tt.repeat {
   192  						tt.repeat = false
   193  					} else {
   194  						run = false
   195  					}
   196  				}
   197  			})
   198  		}
   199  	})
   200  }
   201  
   202  func TestCardinalityLimit(t *testing.T) {
   203  	forAllFixtures(t, func(t *testing.T, client chunk.IndexClient, _ chunk.ObjectClient) {
   204  		limits, err := defaultLimits()
   205  		require.NoError(t, err)
   206  
   207  		client = newCachingIndexClient(client, cache.NewMockCache(), time.Minute, limits)
   208  		batch := client.NewWriteBatch()
   209  		for i := 0; i < 10; i++ {
   210  			batch.Add(tableName, "bar", []byte(strconv.Itoa(i)), []byte(strconv.Itoa(i)))
   211  		}
   212  		err = client.BatchWrite(ctx, batch)
   213  		require.NoError(t, err)
   214  
   215  		var have int
   216  		err = client.QueryPages(ctx, []chunk.IndexQuery{{
   217  			TableName: tableName,
   218  			HashValue: "bar",
   219  		}}, func(_ chunk.IndexQuery, read chunk.ReadBatch) bool {
   220  			iter := read.Iterator()
   221  			for iter.Next() {
   222  				have++
   223  			}
   224  			return true
   225  		})
   226  		require.Error(t, err, "cardinality limit exceeded for {}; 10 entries, more than limit of 5")
   227  		require.Equal(t, 0, have)
   228  	})
   229  }