package config import ( "math" "strconv" "testing" "time" "github.com/stretchr/testify/require" ) func TestRollingCache(t *testing.T) { size := 30 shardCount := 1 cache := newRollingCache(size, shardCount) // Testing Set. channel := "channel1" value := channelOptionsResult{nsName: "value1"} ttl := 200 * time.Millisecond cache.Set(channel, value, ttl) // Testing Get after Set. gotValue, ok := cache.Get(channel) require.True(t, ok) require.Equal(t, value, gotValue) // Testing Get after expiry. time.Sleep(400 * time.Millisecond) _, ok = cache.Get(channel) require.False(t, ok) // Testing if data rolls over. // Setting more data than cache size, to see if rolling over works without errors. for i := 0; i < size+10; i++ { channel := "channel" + strconv.Itoa(i) value := channelOptionsResult{nsName: "value" + strconv.Itoa(i)} cache.Set(channel, value, ttl) } // The first 10 items should have been rolled over and replaced. // So, channel0, channel1, ... channel9 should no longer be in the cache. for i := 0; i < 10; i++ { channel := "channel" + strconv.Itoa(i) _, ok = cache.Get(channel) require.False(t, ok, channel) } // Whereas, the items from channel10 onwards should still be there. for i := 10; i < size+10; i++ { channel := "channel" + strconv.Itoa(i) gotValue, ok := cache.Get(channel) require.True(t, ok) require.Equal(t, channelOptionsResult{nsName: "value" + strconv.Itoa(i)}, gotValue) } } // TestRollingCacheIndexOverflow guards against the rolling index wrapping into // negative values. The index is bumped on every Set, so on a long-running node // it eventually overflows; with a signed counter the wrap made the modulo // negative and Set panicked with "index out of range". func TestRollingCacheIndexOverflow(t *testing.T) { cache := newRollingCache(channelOptionsCacheSize, 1) shard := cache.shardForKey("channel") shard.index.Store(math.MaxUint32) // Next Set wraps the index. ttl := time.Minute for i := 0; i < 2*channelOptionsCacheSize; i++ { channel := "channel" + strconv.Itoa(i) cache.Set(channel, channelOptionsResult{nsName: "value" + strconv.Itoa(i)}, ttl) } // The most recent shardSize items must still be readable after the wrap. for i := channelOptionsCacheSize; i < 2*channelOptionsCacheSize; i++ { channel := "channel" + strconv.Itoa(i) gotValue, ok := cache.Get(channel) require.True(t, ok, channel) require.Equal(t, channelOptionsResult{nsName: "value" + strconv.Itoa(i)}, gotValue) } }