github.com/argoproj/argo-cd/v2@v2.10.5/util/cache/redis_test.go (about) 1 package cache 2 3 import ( 4 "context" 5 "strconv" 6 "testing" 7 "time" 8 9 promcm "github.com/prometheus/client_model/go" 10 11 "github.com/alicebob/miniredis/v2" 12 "github.com/prometheus/client_golang/prometheus" 13 "github.com/redis/go-redis/v9" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 var ( 18 redisRequestCounter = prometheus.NewCounterVec( 19 prometheus.CounterOpts{ 20 Name: "argocd_redis_request_total", 21 }, 22 []string{"initiator", "failed"}, 23 ) 24 redisRequestHistogram = prometheus.NewHistogramVec( 25 prometheus.HistogramOpts{ 26 Name: "argocd_redis_request_duration", 27 Buckets: []float64{0.1, 0.25, .5, 1, 2}, 28 }, 29 []string{"initiator"}, 30 ) 31 ) 32 33 type MockMetricsServer struct { 34 registry *prometheus.Registry 35 redisRequestCounter *prometheus.CounterVec 36 redisRequestHistogram *prometheus.HistogramVec 37 } 38 39 func NewMockMetricsServer() *MockMetricsServer { 40 registry := prometheus.NewRegistry() 41 registry.MustRegister(redisRequestCounter) 42 registry.MustRegister(redisRequestHistogram) 43 return &MockMetricsServer{ 44 registry: registry, 45 redisRequestCounter: redisRequestCounter, 46 redisRequestHistogram: redisRequestHistogram, 47 } 48 } 49 50 func (m *MockMetricsServer) IncRedisRequest(failed bool) { 51 m.redisRequestCounter.WithLabelValues("mock", strconv.FormatBool(failed)).Inc() 52 } 53 54 func (m *MockMetricsServer) ObserveRedisRequestDuration(duration time.Duration) { 55 m.redisRequestHistogram.WithLabelValues("mock").Observe(duration.Seconds()) 56 } 57 58 func TestRedisSetCache(t *testing.T) { 59 mr, err := miniredis.Run() 60 if err != nil { 61 panic(err) 62 } 63 defer mr.Close() 64 assert.NotNil(t, mr) 65 66 t.Run("Successful set", func(t *testing.T) { 67 client := NewRedisCache(redis.NewClient(&redis.Options{Addr: mr.Addr()}), 60*time.Second, RedisCompressionNone) 68 err = client.Set(&Item{Key: "foo", Object: "bar"}) 69 assert.NoError(t, err) 70 }) 71 72 t.Run("Successful get", func(t *testing.T) { 73 var res string 74 client := NewRedisCache(redis.NewClient(&redis.Options{Addr: mr.Addr()}), 10*time.Second, RedisCompressionNone) 75 err = client.Get("foo", &res) 76 assert.NoError(t, err) 77 assert.Equal(t, res, "bar") 78 }) 79 80 t.Run("Successful delete", func(t *testing.T) { 81 client := NewRedisCache(redis.NewClient(&redis.Options{Addr: mr.Addr()}), 10*time.Second, RedisCompressionNone) 82 err = client.Delete("foo") 83 assert.NoError(t, err) 84 }) 85 86 t.Run("Cache miss", func(t *testing.T) { 87 var res string 88 client := NewRedisCache(redis.NewClient(&redis.Options{Addr: mr.Addr()}), 10*time.Second, RedisCompressionNone) 89 err = client.Get("foo", &res) 90 assert.Error(t, err) 91 assert.Contains(t, err.Error(), "cache: key is missing") 92 }) 93 } 94 95 func TestRedisSetCacheCompressed(t *testing.T) { 96 mr, err := miniredis.Run() 97 if err != nil { 98 panic(err) 99 } 100 defer mr.Close() 101 assert.NotNil(t, mr) 102 103 redisClient := redis.NewClient(&redis.Options{Addr: mr.Addr()}) 104 105 client := NewRedisCache(redisClient, 10*time.Second, RedisCompressionGZip) 106 testValue := "my-value" 107 assert.NoError(t, client.Set(&Item{Key: "my-key", Object: testValue})) 108 109 compressedData, err := redisClient.Get(context.Background(), "my-key.gz").Bytes() 110 assert.NoError(t, err) 111 assert.True(t, len(compressedData) > len([]byte(testValue)), "compressed data is bigger than uncompressed") 112 113 var result string 114 assert.NoError(t, client.Get("my-key", &result)) 115 116 assert.Equal(t, testValue, result) 117 } 118 119 func TestRedisMetrics(t *testing.T) { 120 mr, err := miniredis.Run() 121 if err != nil { 122 panic(err) 123 } 124 defer mr.Close() 125 126 metric := &promcm.Metric{} 127 ms := NewMockMetricsServer() 128 redisClient := redis.NewClient(&redis.Options{Addr: mr.Addr()}) 129 faultyRedisClient := redis.NewClient(&redis.Options{Addr: "invalidredishost.invalid:12345"}) 130 CollectMetrics(redisClient, ms) 131 CollectMetrics(faultyRedisClient, ms) 132 133 client := NewRedisCache(redisClient, 60*time.Second, RedisCompressionNone) 134 faultyClient := NewRedisCache(faultyRedisClient, 60*time.Second, RedisCompressionNone) 135 var res string 136 137 //client successful request 138 err = client.Set(&Item{Key: "foo", Object: "bar"}) 139 assert.NoError(t, err) 140 err = client.Get("foo", &res) 141 assert.NoError(t, err) 142 143 c, err := ms.redisRequestCounter.GetMetricWithLabelValues("mock", "false") 144 assert.NoError(t, err) 145 err = c.Write(metric) 146 assert.NoError(t, err) 147 assert.Equal(t, metric.Counter.GetValue(), float64(2)) 148 149 //faulty client failed request 150 err = faultyClient.Get("foo", &res) 151 assert.Error(t, err) 152 c, err = ms.redisRequestCounter.GetMetricWithLabelValues("mock", "true") 153 assert.NoError(t, err) 154 err = c.Write(metric) 155 assert.NoError(t, err) 156 assert.Equal(t, metric.Counter.GetValue(), float64(1)) 157 158 //both clients histogram count 159 o, err := ms.redisRequestHistogram.GetMetricWithLabelValues("mock") 160 assert.NoError(t, err) 161 err = o.(prometheus.Metric).Write(metric) 162 assert.NoError(t, err) 163 assert.Equal(t, int(metric.Histogram.GetSampleCount()), 3) 164 }