github.com/thanos-io/thanos@v0.32.5/pkg/cache/memcached_test.go (about)

     1  // Copyright (c) The Thanos Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package cache
     5  
     6  import (
     7  	"context"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/go-kit/log"
    12  	"github.com/pkg/errors"
    13  	prom_testutil "github.com/prometheus/client_golang/prometheus/testutil"
    14  
    15  	"github.com/efficientgo/core/testutil"
    16  )
    17  
    18  func TestMemcachedCache(t *testing.T) {
    19  	t.Parallel()
    20  
    21  	// Init some data to conveniently define test cases later one.
    22  	key1 := "key1"
    23  	key2 := "key2"
    24  	key3 := "key3"
    25  	value1 := []byte{1}
    26  	value2 := []byte{2}
    27  	value3 := []byte{3}
    28  
    29  	tests := map[string]struct {
    30  		setup        map[string][]byte
    31  		mockedErr    error
    32  		fetchKeys    []string
    33  		expectedHits map[string][]byte
    34  	}{
    35  		"should return no hits on empty cache": {
    36  			setup:        nil,
    37  			fetchKeys:    []string{key1, key2},
    38  			expectedHits: map[string][]byte{},
    39  		},
    40  		"should return no misses on 100% hit ratio": {
    41  			setup: map[string][]byte{
    42  				key1: value1,
    43  				key2: value2,
    44  				key3: value3,
    45  			},
    46  			fetchKeys: []string{key1},
    47  			expectedHits: map[string][]byte{
    48  				key1: value1,
    49  			},
    50  		},
    51  		"should return hits and misses on partial hits": {
    52  			setup: map[string][]byte{
    53  				key1: value1,
    54  				key2: value2,
    55  			},
    56  			fetchKeys:    []string{key1, key3},
    57  			expectedHits: map[string][]byte{key1: value1},
    58  		},
    59  		"should return no hits on memcached error": {
    60  			setup: map[string][]byte{
    61  				key1: value1,
    62  				key2: value2,
    63  				key3: value3,
    64  			},
    65  			mockedErr:    errors.New("mocked error"),
    66  			fetchKeys:    []string{key1},
    67  			expectedHits: nil,
    68  		},
    69  	}
    70  
    71  	for testName, testData := range tests {
    72  		t.Run(testName, func(t *testing.T) {
    73  			memcached := newMockedMemcachedClient(testData.mockedErr)
    74  			c := NewMemcachedCache("test", log.NewNopLogger(), memcached, nil)
    75  
    76  			// Store the postings expected before running the test.
    77  			ctx := context.Background()
    78  			c.Store(testData.setup, time.Hour)
    79  
    80  			// Fetch postings from cached and assert on it.
    81  			hits := c.Fetch(ctx, testData.fetchKeys)
    82  			testutil.Equals(t, testData.expectedHits, hits)
    83  
    84  			// Assert on metrics.
    85  			testutil.Equals(t, float64(len(testData.fetchKeys)), prom_testutil.ToFloat64(c.requests))
    86  			testutil.Equals(t, float64(len(testData.expectedHits)), prom_testutil.ToFloat64(c.hits))
    87  		})
    88  	}
    89  }
    90  
    91  // mockedMemcachedClient is a mocked memcached client for testing.
    92  type mockedMemcachedClient struct {
    93  	cache       map[string][]byte
    94  	getMultiErr error
    95  }
    96  
    97  // newMockedMemcachedClient returns a mocked memcached client.
    98  func newMockedMemcachedClient(getMultiErr error) *mockedMemcachedClient {
    99  	return &mockedMemcachedClient{
   100  		cache:       map[string][]byte{},
   101  		getMultiErr: getMultiErr,
   102  	}
   103  }
   104  
   105  func (c *mockedMemcachedClient) GetMulti(_ context.Context, keys []string) map[string][]byte {
   106  	if c.getMultiErr != nil {
   107  		return nil
   108  	}
   109  
   110  	hits := map[string][]byte{}
   111  
   112  	for _, key := range keys {
   113  		if value, ok := c.cache[key]; ok {
   114  			hits[key] = value
   115  		}
   116  	}
   117  
   118  	return hits
   119  }
   120  
   121  func (c *mockedMemcachedClient) SetAsync(key string, value []byte, _ time.Duration) error {
   122  	c.cache[key] = value
   123  	return nil
   124  }
   125  
   126  func (c *mockedMemcachedClient) Stop() {
   127  	// Nothing to do.
   128  }