package cache import ( "context" "sync" "testing" "time" ) func TestMemoryCacheSetGet(t *testing.T) { c := NewMemory() defer c.Close() ctx := context.Background() if err := c.Set(ctx, "k1", "v1", 0); err != nil { t.Fatalf("Set 失败: %v", err) } v, err := c.Get(ctx, "k1") if err != nil || v != "v1" { t.Fatalf("Get = (%q, %v)", v, err) } if _, err := c.Get(ctx, "missing"); err != ErrNotFound { t.Fatalf("缺失键应返回 ErrNotFound: %v", err) } _ = c.Delete(ctx, "k1") if _, err := c.Get(ctx, "k1"); err != ErrNotFound { t.Fatal("删除后应不存在") } } func TestMemoryCacheTTL(t *testing.T) { c := NewMemory() defer c.Close() ctx := context.Background() _ = c.Set(ctx, "ttl", "x", 50*time.Millisecond) if ok, _ := c.Exists(ctx, "ttl"); !ok { t.Fatal("TTL 内应存在") } time.Sleep(80 * time.Millisecond) if _, err := c.Get(ctx, "ttl"); err != ErrNotFound { t.Fatal("过期后应不存在") } } func TestMemoryCacheIncrWindow(t *testing.T) { c := NewMemory() defer c.Close() ctx := context.Background() for i := int64(1); i <= 3; i++ { n, err := c.Incr(ctx, "rl", time.Minute) if err != nil || n != i { t.Fatalf("Incr = (%d, %v), want (%d, nil)", n, err, i) } } // 窗口过期后重新计数 _ = c.Set(ctx, "short", "seed", time.Millisecond) time.Sleep(5 * time.Millisecond) n, err := c.Incr(ctx, "short", time.Millisecond) if err != nil || n != 1 { t.Fatalf("过期窗口重置失败: (%d, %v)", n, err) } } func TestMemoryCacheConcurrentIncr(t *testing.T) { c := NewMemory() defer c.Close() ctx := context.Background() var wg sync.WaitGroup for i := 0; i < 50; i++ { wg.Add(1) go func() { defer wg.Done() _, _ = c.Incr(ctx, "cnt", time.Minute) }() } wg.Wait() n, _ := c.Incr(ctx, "cnt", time.Minute) if n != 51 { t.Fatalf("并发计数丢失: %d != 51", n) } }