github.com/Jeffail/benthos/v3@v3.65.0/public/service/cache_test.go (about) 1 package service 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 "time" 8 9 "github.com/Jeffail/benthos/v3/lib/metrics" 10 "github.com/Jeffail/benthos/v3/lib/types" 11 "github.com/stretchr/testify/assert" 12 ) 13 14 type testCacheItem struct { 15 b []byte 16 ttl *time.Duration 17 } 18 19 type closableCache struct { 20 m map[string]testCacheItem 21 err error 22 closed bool 23 } 24 25 func (c *closableCache) Get(ctx context.Context, key string) ([]byte, error) { 26 if c.err != nil { 27 return nil, c.err 28 } 29 i, ok := c.m[key] 30 if !ok { 31 return nil, types.ErrKeyNotFound 32 } 33 return i.b, nil 34 } 35 36 func (c *closableCache) Set(ctx context.Context, key string, value []byte, ttl *time.Duration) error { 37 if c.err != nil { 38 return c.err 39 } 40 c.m[key] = testCacheItem{ 41 b: value, ttl: ttl, 42 } 43 return nil 44 } 45 46 func (c *closableCache) Add(ctx context.Context, key string, value []byte, ttl *time.Duration) error { 47 if c.err != nil { 48 return c.err 49 } 50 if _, ok := c.m[key]; ok { 51 return types.ErrKeyAlreadyExists 52 } 53 c.m[key] = testCacheItem{ 54 b: value, ttl: ttl, 55 } 56 return nil 57 58 } 59 60 func (c *closableCache) Delete(ctx context.Context, key string) error { 61 if c.err != nil { 62 return c.err 63 } 64 delete(c.m, key) 65 return nil 66 } 67 68 func (c *closableCache) Close(ctx context.Context) error { 69 c.closed = true 70 return nil 71 } 72 73 type closableCacheMulti struct { 74 *closableCache 75 76 multiItems map[string]testCacheItem 77 } 78 79 func (c *closableCacheMulti) SetMulti(ctx context.Context, keyValues ...CacheItem) error { 80 if c.closableCache.err != nil { 81 return c.closableCache.err 82 } 83 for _, kv := range keyValues { 84 c.multiItems[kv.Key] = testCacheItem{ 85 b: kv.Value, 86 ttl: kv.TTL, 87 } 88 } 89 return nil 90 } 91 92 func TestCacheAirGapShutdown(t *testing.T) { 93 rl := &closableCache{} 94 agrl := newAirGapCache(rl, metrics.Noop()) 95 96 err := agrl.WaitForClose(time.Millisecond * 5) 97 assert.EqualError(t, err, "action timed out") 98 assert.False(t, rl.closed) 99 100 agrl.CloseAsync() 101 err = agrl.WaitForClose(time.Millisecond * 5) 102 assert.NoError(t, err) 103 assert.True(t, rl.closed) 104 } 105 106 func TestCacheAirGapGet(t *testing.T) { 107 rl := &closableCache{ 108 m: map[string]testCacheItem{ 109 "foo": { 110 b: []byte("bar"), 111 }, 112 }, 113 } 114 agrl := newAirGapCache(rl, metrics.Noop()) 115 116 b, err := agrl.Get("foo") 117 assert.NoError(t, err) 118 assert.Equal(t, "bar", string(b)) 119 120 _, err = agrl.Get("not exist") 121 assert.Equal(t, err, ErrKeyNotFound) 122 assert.EqualError(t, err, "key does not exist") 123 } 124 125 func TestCacheAirGapSet(t *testing.T) { 126 rl := &closableCache{ 127 m: map[string]testCacheItem{}, 128 } 129 agrl := newAirGapCache(rl, metrics.Noop()) 130 131 err := agrl.Set("foo", []byte("bar")) 132 assert.NoError(t, err) 133 assert.Equal(t, map[string]testCacheItem{ 134 "foo": { 135 b: []byte("bar"), 136 ttl: nil, 137 }, 138 }, rl.m) 139 140 err = agrl.Set("foo", []byte("baz")) 141 assert.NoError(t, err) 142 assert.Equal(t, map[string]testCacheItem{ 143 "foo": { 144 b: []byte("baz"), 145 ttl: nil, 146 }, 147 }, rl.m) 148 } 149 150 func TestCacheAirGapSetMulti(t *testing.T) { 151 rl := &closableCache{ 152 m: map[string]testCacheItem{}, 153 } 154 agrl := newAirGapCache(rl, metrics.Noop()) 155 156 err := agrl.SetMulti(map[string][]byte{ 157 "first": []byte("bar"), 158 "second": []byte("baz"), 159 }) 160 assert.NoError(t, err) 161 assert.Equal(t, map[string]testCacheItem{ 162 "first": { 163 b: []byte("bar"), 164 ttl: nil, 165 }, 166 "second": { 167 b: []byte("baz"), 168 ttl: nil, 169 }, 170 }, rl.m) 171 } 172 173 func TestCacheAirGapSetMultiWithTTL(t *testing.T) { 174 rl := &closableCache{ 175 m: map[string]testCacheItem{}, 176 } 177 agrl := newAirGapCache(rl, metrics.Noop()).(types.CacheWithTTL) 178 179 ttl1, ttl2 := time.Second, time.Millisecond 180 181 err := agrl.SetMultiWithTTL(map[string]types.CacheTTLItem{ 182 "first": { 183 Value: []byte("bar"), 184 TTL: &ttl1, 185 }, 186 "second": { 187 Value: []byte("baz"), 188 TTL: &ttl2, 189 }, 190 }) 191 assert.NoError(t, err) 192 assert.Equal(t, map[string]testCacheItem{ 193 "first": { 194 b: []byte("bar"), 195 ttl: &ttl1, 196 }, 197 "second": { 198 b: []byte("baz"), 199 ttl: &ttl2, 200 }, 201 }, rl.m) 202 } 203 204 func TestCacheAirGapSetMultiWithTTLPassthrough(t *testing.T) { 205 rl := &closableCacheMulti{ 206 closableCache: &closableCache{ 207 m: map[string]testCacheItem{}, 208 }, 209 multiItems: map[string]testCacheItem{}, 210 } 211 agrl := newAirGapCache(rl, metrics.Noop()).(types.CacheWithTTL) 212 213 ttl1, ttl2 := time.Second, time.Millisecond 214 215 err := agrl.SetMultiWithTTL(map[string]types.CacheTTLItem{ 216 "first": { 217 Value: []byte("bar"), 218 TTL: &ttl1, 219 }, 220 "second": { 221 Value: []byte("baz"), 222 TTL: &ttl2, 223 }, 224 }) 225 assert.NoError(t, err) 226 assert.Equal(t, map[string]testCacheItem{}, rl.m) 227 assert.Equal(t, map[string]testCacheItem{ 228 "first": { 229 b: []byte("bar"), 230 ttl: &ttl1, 231 }, 232 "second": { 233 b: []byte("baz"), 234 ttl: &ttl2, 235 }, 236 }, rl.multiItems) 237 } 238 239 func TestCacheAirGapSetWithTTL(t *testing.T) { 240 rl := &closableCache{ 241 m: map[string]testCacheItem{}, 242 } 243 agrl := newAirGapCache(rl, metrics.Noop()).(types.CacheWithTTL) 244 245 ttl1, ttl2 := time.Second, time.Millisecond 246 err := agrl.SetWithTTL("foo", []byte("bar"), &ttl1) 247 assert.NoError(t, err) 248 assert.Equal(t, map[string]testCacheItem{ 249 "foo": { 250 b: []byte("bar"), 251 ttl: &ttl1, 252 }, 253 }, rl.m) 254 255 err = agrl.SetWithTTL("foo", []byte("baz"), &ttl2) 256 assert.NoError(t, err) 257 assert.Equal(t, map[string]testCacheItem{ 258 "foo": { 259 b: []byte("baz"), 260 ttl: &ttl2, 261 }, 262 }, rl.m) 263 } 264 265 func TestCacheAirGapAdd(t *testing.T) { 266 rl := &closableCache{ 267 m: map[string]testCacheItem{}, 268 } 269 agrl := newAirGapCache(rl, metrics.Noop()) 270 271 err := agrl.Add("foo", []byte("bar")) 272 assert.NoError(t, err) 273 assert.Equal(t, map[string]testCacheItem{ 274 "foo": { 275 b: []byte("bar"), 276 ttl: nil, 277 }, 278 }, rl.m) 279 280 err = agrl.Add("foo", []byte("baz")) 281 assert.Equal(t, err, ErrKeyAlreadyExists) 282 assert.EqualError(t, err, "key already exists") 283 } 284 285 func TestCacheAirGapAddWithTTL(t *testing.T) { 286 rl := &closableCache{ 287 m: map[string]testCacheItem{}, 288 } 289 agrl := newAirGapCache(rl, metrics.Noop()).(types.CacheWithTTL) 290 291 ttl := time.Second 292 err := agrl.AddWithTTL("foo", []byte("bar"), &ttl) 293 assert.NoError(t, err) 294 assert.Equal(t, map[string]testCacheItem{ 295 "foo": { 296 b: []byte("bar"), 297 ttl: &ttl, 298 }, 299 }, rl.m) 300 301 err = agrl.AddWithTTL("foo", []byte("baz"), nil) 302 assert.Equal(t, err, ErrKeyAlreadyExists) 303 assert.EqualError(t, err, "key already exists") 304 } 305 306 func TestCacheAirGapDelete(t *testing.T) { 307 rl := &closableCache{ 308 m: map[string]testCacheItem{ 309 "foo": { 310 b: []byte("bar"), 311 }, 312 }, 313 } 314 agrl := newAirGapCache(rl, metrics.Noop()) 315 316 err := agrl.Delete("foo") 317 assert.NoError(t, err) 318 assert.Equal(t, map[string]testCacheItem{}, rl.m) 319 } 320 321 type closableCacheType struct { 322 m map[string]testCacheItem 323 err error 324 closed bool 325 } 326 327 func (c *closableCacheType) Get(key string) ([]byte, error) { 328 if c.err != nil { 329 return nil, c.err 330 } 331 i, ok := c.m[key] 332 if !ok { 333 return nil, types.ErrKeyNotFound 334 } 335 return i.b, nil 336 } 337 338 func (c *closableCacheType) Set(key string, value []byte) error { 339 if c.err != nil { 340 return c.err 341 } 342 c.m[key] = testCacheItem{b: value} 343 return nil 344 } 345 func (c *closableCacheType) SetWithTTL(key string, value []byte, ttl *time.Duration) error { 346 if c.err != nil { 347 return c.err 348 } 349 c.m[key] = testCacheItem{ 350 b: value, ttl: ttl, 351 } 352 return nil 353 } 354 355 func (c *closableCacheType) SetMulti(map[string][]byte) error { 356 return errors.New("not implemented") 357 } 358 359 func (c *closableCacheType) SetMultiWithTTL(items map[string]types.CacheTTLItem) error { 360 return errors.New("not implemented") 361 } 362 363 func (c *closableCacheType) Add(key string, value []byte) error { 364 if c.err != nil { 365 return c.err 366 } 367 if _, ok := c.m[key]; ok { 368 return types.ErrKeyAlreadyExists 369 } 370 c.m[key] = testCacheItem{b: value} 371 return nil 372 373 } 374 375 func (c *closableCacheType) AddWithTTL(key string, value []byte, ttl *time.Duration) error { 376 if c.err != nil { 377 return c.err 378 } 379 if _, ok := c.m[key]; ok { 380 return types.ErrKeyAlreadyExists 381 } 382 c.m[key] = testCacheItem{ 383 b: value, ttl: ttl, 384 } 385 return nil 386 387 } 388 389 func (c *closableCacheType) Delete(key string) error { 390 if c.err != nil { 391 return c.err 392 } 393 delete(c.m, key) 394 return nil 395 } 396 397 func (c *closableCacheType) CloseAsync() { 398 c.closed = true 399 } 400 401 func (c *closableCacheType) WaitForClose(t time.Duration) error { 402 return nil 403 } 404 405 func TestCacheReverseAirGapShutdown(t *testing.T) { 406 rl := &closableCacheType{} 407 agrl := newReverseAirGapCache(rl) 408 409 err := agrl.Close(context.Background()) 410 assert.NoError(t, err) 411 assert.True(t, rl.closed) 412 } 413 414 func TestCacheReverseAirGapGet(t *testing.T) { 415 rl := &closableCacheType{ 416 m: map[string]testCacheItem{ 417 "foo": { 418 b: []byte("bar"), 419 }, 420 }, 421 } 422 agrl := newReverseAirGapCache(rl) 423 424 b, err := agrl.Get(context.Background(), "foo") 425 assert.NoError(t, err) 426 assert.Equal(t, "bar", string(b)) 427 428 _, err = agrl.Get(context.Background(), "not exist") 429 assert.Equal(t, err, ErrKeyNotFound) 430 assert.EqualError(t, err, "key does not exist") 431 } 432 433 func TestCacheReverseAirGapSet(t *testing.T) { 434 rl := &closableCacheType{ 435 m: map[string]testCacheItem{}, 436 } 437 agrl := newReverseAirGapCache(rl) 438 439 err := agrl.Set(context.Background(), "foo", []byte("bar"), nil) 440 assert.NoError(t, err) 441 assert.Equal(t, map[string]testCacheItem{ 442 "foo": { 443 b: []byte("bar"), 444 ttl: nil, 445 }, 446 }, rl.m) 447 448 err = agrl.Set(context.Background(), "foo", []byte("baz"), nil) 449 assert.NoError(t, err) 450 assert.Equal(t, map[string]testCacheItem{ 451 "foo": { 452 b: []byte("baz"), 453 ttl: nil, 454 }, 455 }, rl.m) 456 } 457 458 func TestCacheReverseAirGapSetWithTTL(t *testing.T) { 459 rl := &closableCacheType{ 460 m: map[string]testCacheItem{}, 461 } 462 agrl := newReverseAirGapCache(rl) 463 464 ttl1, ttl2 := time.Second, time.Millisecond 465 err := agrl.Set(context.Background(), "foo", []byte("bar"), &ttl1) 466 assert.NoError(t, err) 467 assert.Equal(t, map[string]testCacheItem{ 468 "foo": { 469 b: []byte("bar"), 470 ttl: &ttl1, 471 }, 472 }, rl.m) 473 474 err = agrl.Set(context.Background(), "foo", []byte("baz"), &ttl2) 475 assert.NoError(t, err) 476 assert.Equal(t, map[string]testCacheItem{ 477 "foo": { 478 b: []byte("baz"), 479 ttl: &ttl2, 480 }, 481 }, rl.m) 482 } 483 484 func TestCacheReverseAirGapAdd(t *testing.T) { 485 rl := &closableCacheType{ 486 m: map[string]testCacheItem{}, 487 } 488 agrl := newReverseAirGapCache(rl) 489 490 err := agrl.Add(context.Background(), "foo", []byte("bar"), nil) 491 assert.NoError(t, err) 492 assert.Equal(t, map[string]testCacheItem{ 493 "foo": { 494 b: []byte("bar"), 495 ttl: nil, 496 }, 497 }, rl.m) 498 499 err = agrl.Add(context.Background(), "foo", []byte("baz"), nil) 500 assert.Equal(t, err, ErrKeyAlreadyExists) 501 assert.EqualError(t, err, "key already exists") 502 } 503 504 func TestCacheReverseAirGapAddWithTTL(t *testing.T) { 505 rl := &closableCacheType{ 506 m: map[string]testCacheItem{}, 507 } 508 agrl := newReverseAirGapCache(rl) 509 510 ttl := time.Second 511 err := agrl.Add(context.Background(), "foo", []byte("bar"), &ttl) 512 assert.NoError(t, err) 513 assert.Equal(t, map[string]testCacheItem{ 514 "foo": { 515 b: []byte("bar"), 516 ttl: &ttl, 517 }, 518 }, rl.m) 519 520 err = agrl.Add(context.Background(), "foo", []byte("baz"), nil) 521 assert.Equal(t, err, ErrKeyAlreadyExists) 522 assert.EqualError(t, err, "key already exists") 523 } 524 525 func TestCacheReverseAirGapDelete(t *testing.T) { 526 rl := &closableCacheType{ 527 m: map[string]testCacheItem{ 528 "foo": { 529 b: []byte("bar"), 530 }, 531 }, 532 } 533 agrl := newReverseAirGapCache(rl) 534 535 err := agrl.Delete(context.Background(), "foo") 536 assert.NoError(t, err) 537 assert.Equal(t, map[string]testCacheItem{}, rl.m) 538 }