diff options
-rw-r--r-- | conn_test.go | 31 | ||||
-rw-r--r-- | encoding_test.go | 34 | ||||
-rw-r--r-- | evict_test.go | 30 | ||||
-rw-r--r-- | internal/pausedtimer/timer_test.go | 14 |
4 files changed, 109 insertions, 0 deletions
diff --git a/conn_test.go b/conn_test.go index d1581f3..d6c284e 100644 --- a/conn_test.go +++ b/conn_test.go @@ -17,6 +17,23 @@ func setupTestDB[K any, V any](t testing.TB) *DB[K, V] { db.Close() }) return &db +func TestDBConcurrentAccess(t *testing.T) { + db := setupTestDB[string, string](t) + + go func() { + for i := 0; i < 100; i++ { + db.Set(fmt.Sprintf("Key%d", i), "Value", 0) + } + }() + + go func() { + for i := 0; i < 100; i++ { + db.GetValue(fmt.Sprintf("Key%d", i)) + } + }() + + // Allow some time for goroutines to complete + time.Sleep(1 * time.Second) } func TestDBGetSet(t *testing.T) { @@ -64,6 +81,20 @@ func TestDBGetSet(t *testing.T) { assert.NoError(t, err) assert.Equal(t, want, got) }) + + t.Run("Key Expiry", func(t *testing.T) { + t.Parallel() + + db := setupTestDB[string, string](t) + + err := db.Set("Key", "Value", 500*time.Millisecond) + assert.NoError(t, err) + + time.Sleep(600 * time.Millisecond) + + _, _, err = db.GetValue("Key") + assert.ErrorIs(t, err, ErrKeyNotFound) + }) } func TestDBDelete(t *testing.T) { diff --git a/encoding_test.go b/encoding_test.go index 5fc4c9a..bac148c 100644 --- a/encoding_test.go +++ b/encoding_test.go @@ -40,6 +40,40 @@ func TestEncodeDecodeUint64(t *testing.T) { assert.Equal(t, tt.value, decodedValue) }) } +func TestDecodeUint64Error(t *testing.T) { + var buf bytes.Buffer + buf.Write([]byte{0xFF}) // Invalid data for uint64 + decoder := newDecoder(&buf) + + _, err := decoder.DecodeUint64() + assert.Error(t, err) +func TestEncodeDecodeTimeBoundary(t *testing.T) { + tests := []struct { + name string + value time.Time + }{ + {name: "Unix Epoch", value: time.Unix(0, 0)}, + {name: "Far Future", value: time.Unix(1<<63-1, 0)}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var buf bytes.Buffer + e := newEncoder(&buf) + + err := e.EncodeTime(tt.value) + assert.NoError(t, err) + err = e.Flush() + assert.NoError(t, err) + + decoder := newDecoder(bytes.NewReader(buf.Bytes())) + + decodedValue, err := decoder.DecodeTime() + assert.NoError(t, err) + + assert.Equal(t, tt.value, decodedValue) + }) + } } func TestEncodeDecodeTime(t *testing.T) { diff --git a/evict_test.go b/evict_test.go index ba73c24..1813e94 100644 --- a/evict_test.go +++ b/evict_test.go @@ -86,6 +86,36 @@ func TestFIFOPolicy(t *testing.T) { assert.Nil(t, policy.Evict()) }) }) + + t.Run("Eviction Order", func(t *testing.T) { + t.Parallel() + + policy := lfuPolicy{evict: createSentinel(t)} + + n0 := &node{Key: []byte("0"), Access: 1} + n1 := &node{Key: []byte("1"), Access: 1} + + policy.OnInsert(n0) + policy.OnInsert(n1) + + evictedNode := policy.Evict() + assert.Same(t, n0, evictedNode) // Assuming FIFO order for same access count + }) + + t.Run("With Zero TTL", func(t *testing.T) { + t.Parallel() + + policy := ltrPolicy{evict: createSentinel(t), evictZero: false} + + n0 := &node{Key: []byte("0"), Expiration: time.Time{}} + n1 := &node{Key: []byte("1"), Expiration: time.Now().Add(1 * time.Hour)} + + policy.OnInsert(n0) + policy.OnInsert(n1) + + evictedNode := policy.Evict() + assert.Same(t, n1, evictedNode) // n0 should not be evicted due to zero TTL + }) } func TestLRUPolicy(t *testing.T) { diff --git a/internal/pausedtimer/timer_test.go b/internal/pausedtimer/timer_test.go index 6e15001..ac42690 100644 --- a/internal/pausedtimer/timer_test.go +++ b/internal/pausedtimer/timer_test.go @@ -12,6 +12,20 @@ func TestNew(t *testing.T) { timer := New(d) assert.Equal(t, d, timer.duration) assert.NotNil(t, timer.Ticker) +func TestPauseTimerPauseAndResume(t *testing.T) { + d := 1 * time.Second + timer := New(d) + timer.Stop() // Simulate pause + time.Sleep(500 * time.Millisecond) + timer.Resume() + + select { + case <-timer.C: + // Timer should not have fired yet + t.Fatal("Timer fired too early") + case <-time.After(600 * time.Millisecond): + // Timer should fire after resuming + } } func TestPauseTimerReset(t *testing.T) { |