package executor import ( "context" "errors" "testing" "time" ) type mockCodexKVStore struct { data map[string]string getErr error setErr error lastSetK string lastTTL time.Duration } func (m *mockCodexKVStore) Get(_ context.Context, key string) (string, error) { if m.getErr != nil { return "", m.getErr } if m.data == nil { return "", nil } return m.data[key], nil } func (m *mockCodexKVStore) Set(_ context.Context, key, value string, ttl time.Duration) error { m.lastSetK = key m.lastTTL = ttl if m.setErr != nil { return m.setErr } if m.data == nil { m.data = make(map[string]string) } m.data[key] = value return nil } func (m *mockCodexKVStore) Del(_ context.Context, _ ...string) error { return nil } func (m *mockCodexKVStore) Ping(_ context.Context) error { return nil } func TestGetCodexCache_RedisHit(t *testing.T) { defer SetCodexKVStore(nil) store := &mockCodexKVStore{} SetCodexKVStore(store) exp := time.Now().Add(10 * time.Minute).UTC().Format(time.RFC3339Nano) store.data = map[string]string{ "codex:model:user": `{"ID":"abc","Expire":"` + exp + `"}`, } entry, ok := getCodexCache("model:user") if !ok { t.Fatalf("expected cache hit") } if entry.ID != "abc" { t.Fatalf("expected id abc, got %s", entry.ID) } } func TestGetCodexCache_FallbackToMemoryOnRedisError(t *testing.T) { defer SetCodexKVStore(nil) store := &mockCodexKVStore{getErr: errors.New("boom")} SetCodexKVStore(store) codexCacheMu.Lock() codexCacheMap = map[string]codexCache{ "m:u": {ID: "mem", Expire: time.Now().Add(10 * time.Minute)}, } codexCacheMu.Unlock() entry, ok := getCodexCache("m:u") if !ok { t.Fatalf("expected memory fallback hit") } if entry.ID != "mem" { t.Fatalf("expected memory id mem, got %s", entry.ID) } } func TestSetCodexCache_WritesRedisAndMemory(t *testing.T) { defer SetCodexKVStore(nil) store := &mockCodexKVStore{} SetCodexKVStore(store) entry := codexCache{ID: "cid", Expire: time.Now().Add(time.Hour)} setCodexCache("m:u", entry) if store.lastSetK != "codex:m:u" { t.Fatalf("expected redis key codex:m:u, got %s", store.lastSetK) } if store.lastTTL <= 0 { t.Fatalf("expected positive ttl") } codexCacheMu.RLock() mem, ok := codexCacheMap["m:u"] codexCacheMu.RUnlock() if !ok || mem.ID != "cid" { t.Fatalf("expected memory cache write") } }