github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/chunk/composite_store_test.go (about) 1 package chunk 2 3 import ( 4 "context" 5 "fmt" 6 "reflect" 7 "testing" 8 9 "github.com/stretchr/testify/require" 10 11 "github.com/prometheus/common/model" 12 "github.com/prometheus/prometheus/pkg/labels" 13 "github.com/weaveworks/common/test" 14 ) 15 16 type mockStore int 17 18 func (m mockStore) Put(ctx context.Context, chunks []Chunk) error { 19 return nil 20 } 21 22 func (m mockStore) PutOne(ctx context.Context, from, through model.Time, chunk Chunk) error { 23 return nil 24 } 25 26 func (m mockStore) Get(tx context.Context, userID string, from, through model.Time, matchers ...*labels.Matcher) ([]Chunk, error) { 27 return nil, nil 28 } 29 func (m mockStore) LabelValuesForMetricName(ctx context.Context, userID string, from, through model.Time, metricName string, labelName string) ([]string, error) { 30 return nil, nil 31 } 32 33 func (m mockStore) GetChunkRefs(tx context.Context, userID string, from, through model.Time, matchers ...*labels.Matcher) ([][]Chunk, []*Fetcher, error) { 34 return nil, nil, nil 35 } 36 37 func (m mockStore) LabelNamesForMetricName(ctx context.Context, userID string, from, through model.Time, metricName string) ([]string, error) { 38 return nil, nil 39 } 40 41 func (m mockStore) DeleteChunk(ctx context.Context, from, through model.Time, userID, chunkID string, metric labels.Labels, partiallyDeletedInterval *model.Interval) error { 42 return nil 43 } 44 func (m mockStore) DeleteSeriesIDs(ctx context.Context, from, through model.Time, userID string, metric labels.Labels) error { 45 return nil 46 } 47 48 func (m mockStore) GetChunkFetcher(tm model.Time) *Fetcher { 49 return nil 50 } 51 52 func (m mockStore) Stop() {} 53 54 func TestCompositeStore(t *testing.T) { 55 type result struct { 56 from, through model.Time 57 store Store 58 } 59 collect := func(results *[]result) func(_ context.Context, from, through model.Time, store Store) error { 60 return func(_ context.Context, from, through model.Time, store Store) error { 61 *results = append(*results, result{from, through, store}) 62 return nil 63 } 64 } 65 cs := compositeStore{ 66 stores: []compositeStoreEntry{ 67 {model.TimeFromUnix(0), mockStore(1)}, 68 {model.TimeFromUnix(100), mockStore(2)}, 69 {model.TimeFromUnix(200), mockStore(3)}, 70 }, 71 } 72 73 for i, tc := range []struct { 74 cs compositeStore 75 from, through int64 76 want []result 77 }{ 78 // Test we have sensible results when there are no schema's defined 79 {compositeStore{}, 0, 1, []result{}}, 80 81 // Test we have sensible results when there is a single schema 82 { 83 compositeStore{ 84 stores: []compositeStoreEntry{ 85 {model.TimeFromUnix(0), mockStore(1)}, 86 }, 87 }, 88 0, 10, 89 []result{ 90 {model.TimeFromUnix(0), model.TimeFromUnix(10), mockStore(1)}, 91 }, 92 }, 93 94 // Test we have sensible results for negative (ie pre 1970) times 95 { 96 compositeStore{ 97 stores: []compositeStoreEntry{ 98 {model.TimeFromUnix(0), mockStore(1)}, 99 }, 100 }, 101 -10, -9, 102 []result{}, 103 }, 104 { 105 compositeStore{ 106 stores: []compositeStoreEntry{ 107 {model.TimeFromUnix(0), mockStore(1)}, 108 }, 109 }, 110 -10, 10, 111 []result{ 112 {model.TimeFromUnix(0), model.TimeFromUnix(10), mockStore(1)}, 113 }, 114 }, 115 116 // Test we have sensible results when there is two schemas 117 { 118 compositeStore{ 119 stores: []compositeStoreEntry{ 120 {model.TimeFromUnix(0), mockStore(1)}, 121 {model.TimeFromUnix(100), mockStore(2)}, 122 }, 123 }, 124 34, 165, 125 []result{ 126 {model.TimeFromUnix(34), model.TimeFromUnix(100) - 1, mockStore(1)}, 127 {model.TimeFromUnix(100), model.TimeFromUnix(165), mockStore(2)}, 128 }, 129 }, 130 131 // Test all the various combination we can get when there are three schemas 132 { 133 cs, 34, 65, 134 []result{ 135 {model.TimeFromUnix(34), model.TimeFromUnix(65), mockStore(1)}, 136 }, 137 }, 138 139 { 140 cs, 244, 6785, 141 []result{ 142 {model.TimeFromUnix(244), model.TimeFromUnix(6785), mockStore(3)}, 143 }, 144 }, 145 146 { 147 cs, 34, 165, 148 []result{ 149 {model.TimeFromUnix(34), model.TimeFromUnix(100) - 1, mockStore(1)}, 150 {model.TimeFromUnix(100), model.TimeFromUnix(165), mockStore(2)}, 151 }, 152 }, 153 154 { 155 cs, 151, 264, 156 []result{ 157 {model.TimeFromUnix(151), model.TimeFromUnix(200) - 1, mockStore(2)}, 158 {model.TimeFromUnix(200), model.TimeFromUnix(264), mockStore(3)}, 159 }, 160 }, 161 162 { 163 cs, 32, 264, 164 []result{ 165 {model.TimeFromUnix(32), model.TimeFromUnix(100) - 1, mockStore(1)}, 166 {model.TimeFromUnix(100), model.TimeFromUnix(200) - 1, mockStore(2)}, 167 {model.TimeFromUnix(200), model.TimeFromUnix(264), mockStore(3)}, 168 }, 169 }, 170 } { 171 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 172 have := []result{} 173 err := tc.cs.forStores(context.Background(), userID, model.TimeFromUnix(tc.from), model.TimeFromUnix(tc.through), collect(&have)) 174 require.NoError(t, err) 175 if !reflect.DeepEqual(tc.want, have) { 176 t.Fatalf("wrong stores - %s", test.Diff(tc.want, have)) 177 } 178 }) 179 } 180 } 181 182 type mockStoreLabel struct { 183 mockStore 184 values []string 185 } 186 187 func (m mockStoreLabel) LabelValuesForMetricName(ctx context.Context, userID string, from, through model.Time, metricName string, labelName string) ([]string, error) { 188 return m.values, nil 189 } 190 191 func (m mockStoreLabel) LabelNamesForMetricName(ctx context.Context, userID string, from, through model.Time, metricName string) ([]string, error) { 192 return m.values, nil 193 } 194 195 func TestCompositeStoreLabels(t *testing.T) { 196 t.Parallel() 197 198 cs := compositeStore{ 199 stores: []compositeStoreEntry{ 200 {model.TimeFromUnix(0), mockStore(1)}, 201 {model.TimeFromUnix(20), mockStoreLabel{mockStore(1), []string{"b", "c", "e"}}}, 202 {model.TimeFromUnix(40), mockStoreLabel{mockStore(1), []string{"a", "b", "c", "f"}}}, 203 }, 204 } 205 206 for i, tc := range []struct { 207 from, through int64 208 want []string 209 }{ 210 { 211 0, 10, 212 nil, 213 }, 214 { 215 0, 30, 216 []string{"b", "c", "e"}, 217 }, 218 { 219 0, 40, 220 []string{"a", "b", "c", "e", "f"}, 221 }, 222 } { 223 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 224 have, err := cs.LabelNamesForMetricName(context.Background(), "", model.TimeFromUnix(tc.from), model.TimeFromUnix(tc.through), "") 225 require.NoError(t, err) 226 if !reflect.DeepEqual(tc.want, have) { 227 t.Fatalf("wrong label names - %s", test.Diff(tc.want, have)) 228 } 229 have, err = cs.LabelValuesForMetricName(context.Background(), "", model.TimeFromUnix(tc.from), model.TimeFromUnix(tc.through), "", "") 230 require.NoError(t, err) 231 if !reflect.DeepEqual(tc.want, have) { 232 t.Fatalf("wrong label values - %s", test.Diff(tc.want, have)) 233 } 234 }) 235 } 236 237 } 238 239 type mockStoreGetChunkFetcher struct { 240 mockStore 241 chunkFetcher *Fetcher 242 } 243 244 func (m mockStoreGetChunkFetcher) GetChunkFetcher(tm model.Time) *Fetcher { 245 return m.chunkFetcher 246 } 247 248 func TestCompositeStore_GetChunkFetcher(t *testing.T) { 249 cs := compositeStore{ 250 stores: []compositeStoreEntry{ 251 {model.TimeFromUnix(10), mockStoreGetChunkFetcher{mockStore(0), &Fetcher{}}}, 252 {model.TimeFromUnix(20), mockStoreGetChunkFetcher{mockStore(1), &Fetcher{}}}, 253 }, 254 } 255 256 for _, tc := range []struct { 257 name string 258 tm model.Time 259 expectedFetcher *Fetcher 260 }{ 261 { 262 name: "no matching store", 263 tm: model.TimeFromUnix(0), 264 }, 265 { 266 name: "first store", 267 tm: model.TimeFromUnix(10), 268 expectedFetcher: cs.stores[0].Store.(mockStoreGetChunkFetcher).chunkFetcher, 269 }, 270 { 271 name: "still first store", 272 tm: model.TimeFromUnix(11), 273 expectedFetcher: cs.stores[0].Store.(mockStoreGetChunkFetcher).chunkFetcher, 274 }, 275 { 276 name: "second store", 277 tm: model.TimeFromUnix(20), 278 expectedFetcher: cs.stores[1].Store.(mockStoreGetChunkFetcher).chunkFetcher, 279 }, 280 { 281 name: "still second store", 282 tm: model.TimeFromUnix(21), 283 expectedFetcher: cs.stores[1].Store.(mockStoreGetChunkFetcher).chunkFetcher, 284 }, 285 } { 286 t.Run(tc.name, func(t *testing.T) { 287 require.Same(t, tc.expectedFetcher, cs.GetChunkFetcher(tc.tm)) 288 }) 289 } 290 291 }