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  }