package dyzurbot import ( "context" "os" "strconv" "testing" "time" "github.com/joho/godotenv" "google.golang.org/api/sheets/v4" ) // These are manual smoke tests that hit the real Google Sheet using the // credential in .env (GOOGLE_CREDENTIALS_FILE, GOOGLE_SHEETS_ID). They are // skipped unless their gate env var is set, so the normal `go test ./...` run // stays offline and side-effect-free. // TestLiveAuthRead proves the service-account credential loads and the sheet is // reachable. Read-only. Gate: DYZUR_LIVE_AUTH=1. func TestLiveAuthRead(t *testing.T) { if os.Getenv("DYZUR_LIVE_AUTH") != "1" { t.Skip("set DYZUR_LIVE_AUTH=1 to run") } _ = godotenv.Load() id := os.Getenv("GOOGLE_SHEETS_ID") rows, err := ReadSheet(context.Background(), id, resolveRange("", time.Now())) if err != nil { t.Fatalf("ReadSheet: %v", err) } t.Logf("OK: fetched %d rows", len(rows)) } // TestLiveWriteRoundTrip proves the spreadsheets (read+write) scope actually // grants writes: it creates a throwaway tab, writes a marker via WriteSheet, // reads it back, and deletes the tab — so no real rota data is touched. Gate: // DYZUR_LIVE_WRITE=1. func TestLiveWriteRoundTrip(t *testing.T) { if os.Getenv("DYZUR_LIVE_WRITE") != "1" { t.Skip("set DYZUR_LIVE_WRITE=1 to run") } _ = godotenv.Load() ctx := context.Background() id := os.Getenv("GOOGLE_SHEETS_ID") srv, err := newSheetsService(ctx) if err != nil { t.Fatalf("newSheetsService: %v", err) } // Create an isolated throwaway tab; the timestamp keeps the title unique. title := "scratch-" + strconv.FormatInt(time.Now().UnixNano(), 10) addResp, err := srv.Spreadsheets.BatchUpdate(id, &sheets.BatchUpdateSpreadsheetRequest{ Requests: []*sheets.Request{{ AddSheet: &sheets.AddSheetRequest{ Properties: &sheets.SheetProperties{Title: title}, }, }}, }).Context(ctx).Do() if err != nil { t.Fatalf("create scratch tab: %v", err) } sheetID := addResp.Replies[0].AddSheet.Properties.SheetId // Always remove the throwaway tab, even if the assertions below fail. defer func() { _, derr := srv.Spreadsheets.BatchUpdate(id, &sheets.BatchUpdateSpreadsheetRequest{ Requests: []*sheets.Request{{ DeleteSheet: &sheets.DeleteSheetRequest{SheetId: sheetID}, }}, }).Context(ctx).Do() if derr != nil { t.Errorf("cleanup: delete scratch tab %q: %v", title, derr) } }() const want = "dyzur-write-probe" writeRange := title + "!A1" if err := WriteSheet(ctx, id, writeRange, [][]interface{}{{want}}); err != nil { t.Fatalf("WriteSheet: %v", err) } rows, err := ReadSheet(ctx, id, writeRange) if err != nil { t.Fatalf("ReadSheet back: %v", err) } if len(rows) == 0 || len(rows[0]) == 0 || rows[0][0] != want { t.Fatalf("round-trip mismatch: got %v, want %q", rows, want) } t.Logf("OK: wrote and read back %q from throwaway tab %q", want, title) }