github.com/rajeev159/opa@v0.45.0/topdown/cache/cache_test.go (about) 1 // Copyright 2020 The OPA Authors. All rights reserved. 2 // Use of this source code is governed by an Apache2 3 // license that can be found in the LICENSE file. 4 5 package cache 6 7 import ( 8 "reflect" 9 "testing" 10 11 "github.com/open-policy-agent/opa/ast" 12 ) 13 14 func TestParseCachingConfig(t *testing.T) { 15 maxSize := new(int64) 16 *maxSize = defaultMaxSizeBytes 17 expected := &Config{InterQueryBuiltinCache: InterQueryBuiltinCacheConfig{MaxSizeBytes: maxSize}} 18 19 tests := map[string]struct { 20 input []byte 21 wantErr bool 22 }{ 23 "empty_config": { 24 input: nil, 25 wantErr: false, 26 }, 27 "default_limit": { 28 input: []byte(`{"inter_query_builtin_cache": {},}`), 29 wantErr: false, 30 }, 31 "bad_limit": { 32 input: []byte(`{"inter_query_builtin_cache": {"max_size_bytes": "100"},}`), 33 wantErr: true, 34 }, 35 } 36 37 for name, tc := range tests { 38 t.Run(name, func(t *testing.T) { 39 40 config, err := ParseCachingConfig(tc.input) 41 if tc.wantErr { 42 if err == nil { 43 t.Fatal("Expected error but got nil") 44 } 45 } else { 46 if err != nil { 47 t.Fatalf("Unexpected error %v", err) 48 } 49 } 50 51 if !tc.wantErr && !reflect.DeepEqual(config, expected) { 52 t.Fatalf("want %v got %v", expected, config) 53 } 54 }) 55 } 56 57 // cache limit specified 58 in := `{"inter_query_builtin_cache": {"max_size_bytes": 100},}` 59 60 config, err := ParseCachingConfig([]byte(in)) 61 if err != nil { 62 t.Fatalf("Unexpected error %v", err) 63 } 64 65 limit := int64(100) 66 expected.InterQueryBuiltinCache.MaxSizeBytes = &limit 67 68 if !reflect.DeepEqual(config, expected) { 69 t.Fatalf("want %v got %v", expected, config) 70 } 71 } 72 73 func TestInsert(t *testing.T) { 74 75 in := `{"inter_query_builtin_cache": {"max_size_bytes": 20},}` // 20 byte limit for test purposes 76 77 config, err := ParseCachingConfig([]byte(in)) 78 if err != nil { 79 t.Fatalf("Unexpected error %v", err) 80 } 81 82 cache := NewInterQueryCache(config) 83 84 // large cache value that exceeds limit 85 cacheValueLarge := newInterQueryCacheValue(ast.StringTerm("bar").Value, 40) 86 dropped := cache.Insert(ast.StringTerm("foo").Value, cacheValueLarge) 87 88 if dropped != 1 { 89 t.Fatal("Expected dropped to be one") 90 } 91 92 _, found := cache.Get(ast.StringTerm("foo").Value) 93 if found { 94 t.Fatal("Unexpected key \"foo\" in cache") 95 } 96 97 cacheValue := newInterQueryCacheValue(ast.StringTerm("bar").Value, 20) 98 dropped = cache.Insert(ast.StringTerm("foo").Value, cacheValue) 99 100 if dropped != 0 { 101 t.Fatal("Expected dropped to be zero") 102 } 103 104 // exceed cache limit 105 cacheValue2 := newInterQueryCacheValue(ast.StringTerm("bar2").Value, 20) 106 dropped = cache.Insert(ast.StringTerm("foo2").Value, cacheValue2) 107 108 if dropped != 1 { 109 t.Fatal("Expected dropped to be one") 110 } 111 112 _, found = cache.Get(ast.StringTerm("foo2").Value) 113 if !found { 114 t.Fatal("Expected key \"foo2\" in cache") 115 } 116 117 _, found = cache.Get(ast.StringTerm("foo").Value) 118 if found { 119 t.Fatal("Unexpected key \"foo\" in cache") 120 } 121 } 122 123 func TestDelete(t *testing.T) { 124 config, err := ParseCachingConfig(nil) 125 if err != nil { 126 t.Fatalf("Unexpected error %v", err) 127 } 128 129 cache := NewInterQueryCache(config) 130 cacheValue := newInterQueryCacheValue(ast.StringTerm("bar").Value, 20) 131 132 dropped := cache.Insert(ast.StringTerm("foo").Value, cacheValue) 133 134 if dropped != 0 { 135 t.Fatal("Expected dropped to be zero") 136 } 137 138 cache.Delete(ast.StringTerm("foo").Value) 139 140 _, found := cache.Get(ast.StringTerm("foo").Value) 141 if found { 142 t.Fatal("Unexpected key \"foo\" in cache") 143 } 144 } 145 146 func TestUpdateConfig(t *testing.T) { 147 config, err := ParseCachingConfig(nil) 148 if err != nil { 149 t.Fatalf("Unexpected error %v", err) 150 } 151 c := NewInterQueryCache(config) 152 actualC, ok := c.(*cache) 153 if !ok { 154 t.Fatal("Unexpected error converting InterQueryCache to cache struct") 155 } 156 if actualC.config != config { 157 t.Fatal("Cache config is different than expected") 158 } 159 actualC.UpdateConfig(nil) 160 if actualC.config != config { 161 t.Fatal("Cache config is different than expected after a nil update") 162 } 163 config2, err := ParseCachingConfig(nil) 164 if err != nil { 165 t.Fatalf("Unexpected error: %v", err) 166 } 167 actualC.UpdateConfig(config2) 168 if actualC.config != config2 { 169 t.Fatal("Cache config is different than expected after update") 170 } 171 } 172 173 func TestDefaultMaxSizeBytes(t *testing.T) { 174 c := NewInterQueryCache(nil) 175 actualC, ok := c.(*cache) 176 if !ok { 177 t.Fatal("Unexpected error converting InterQueryCache to cache struct") 178 } 179 if actualC.maxSizeBytes() != defaultMaxSizeBytes { 180 t.Fatal("Expected maxSizeBytes() to return default when config is nil") 181 } 182 } 183 184 type testInterQueryCacheValue struct { 185 value ast.Value 186 size int 187 } 188 189 func newInterQueryCacheValue(value ast.Value, size int) *testInterQueryCacheValue { 190 return &testInterQueryCacheValue{value: value, size: size} 191 } 192 193 func (p testInterQueryCacheValue) SizeInBytes() int64 { 194 return int64(p.size) 195 }