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  }