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 }