package cache import ( "context" "errors" "fuj-management/go/internal/io/drive" "os" "testing" "time" ) func TestGet_FreshFetch(t *testing.T) { dir := t.TempDir() d := &drive.Fake{Times: map[string]string{"sheet1": "2026-01-01T00:00:00Z"}} fc := New(d, dir, map[string]string{"mykey": "sheet1"}, time.Minute, time.Minute) calls := 0 got, err := Get(context.Background(), fc, "mykey", func(_ context.Context) ([]string, error) { calls++ return []string{"a", "b"}, nil }) if err != nil { t.Fatal(err) } if len(got) != 2 || got[0] != "a" { t.Errorf("unexpected: %v", got) } if calls != 1 { t.Errorf("want 1 fetch call, got %d", calls) } } func TestGet_CacheHit(t *testing.T) { dir := t.TempDir() d := &drive.Fake{Times: map[string]string{"sheet1": "2026-01-01T00:00:00Z"}} fc := New(d, dir, map[string]string{"mykey": "sheet1"}, time.Minute, time.Minute) fetch := func(_ context.Context) ([]string, error) { return []string{"a"}, nil } if _, err := Get(context.Background(), fc, "mykey", fetch); err != nil { t.Fatal(err) } // Second call — modifiedTime unchanged, should hit cache calls := 0 got, err := Get(context.Background(), fc, "mykey", func(_ context.Context) ([]string, error) { calls++ return []string{"SHOULD_NOT_CALL"}, nil }) if err != nil { t.Fatal(err) } if got[0] != "a" { t.Errorf("want cache hit with 'a', got %q", got[0]) } if calls != 0 { t.Errorf("want 0 fetch calls on hit, got %d", calls) } } func TestGet_CacheMiss_OnModifiedTimeChange(t *testing.T) { dir := t.TempDir() d := &drive.Fake{Times: map[string]string{"sheet1": "2026-01-01T00:00:00Z"}} // No TTL guards so we always hit Drive fc := New(d, dir, map[string]string{"mykey": "sheet1"}, 0, 0) fetch := func(_ context.Context) ([]string, error) { return []string{"v1"}, nil } if _, err := Get(context.Background(), fc, "mykey", fetch); err != nil { t.Fatal(err) } // Sheet updated — change modifiedTime d.Times["sheet1"] = "2026-02-01T00:00:00Z" got, err := Get(context.Background(), fc, "mykey", func(_ context.Context) ([]string, error) { return []string{"v2"}, nil }) if err != nil { t.Fatal(err) } if got[0] != "v2" { t.Errorf("want v2 after sheet update, got %q", got[0]) } } func TestGet_DriveFailureFallback(t *testing.T) { dir := t.TempDir() d := &drive.Fake{Err: errors.New("drive down")} fc := New(d, dir, nil, 0, 0) calls := 0 _, err := Get(context.Background(), fc, "mykey", func(_ context.Context) ([]string, error) { calls++ return []string{"fallback"}, nil }) if err != nil { t.Fatal(err) } if calls != 1 { t.Errorf("want 1 fetch call, got %d", calls) } } func TestFlush(t *testing.T) { dir := t.TempDir() d := &drive.Fake{Times: map[string]string{"sheet1": "t1"}} fc := New(d, dir, map[string]string{"k": "sheet1"}, 0, 0) if _, err := Get(context.Background(), fc, "k", func(_ context.Context) (int, error) { return 42, nil }); err != nil { t.Fatal(err) } n, err := fc.Flush() if err != nil { t.Fatal(err) } if n != 1 { t.Errorf("want 1 deleted file, got %d", n) } // Cache dir should be empty of _cache.json files entries, _ := os.ReadDir(dir) for _, e := range entries { if e.Name() != "" { t.Errorf("expected empty dir after flush, found %s", e.Name()) } } }