94 lines
2.7 KiB
Go
94 lines
2.7 KiB
Go
package dyzurbot
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestLoadConfigDefaults(t *testing.T) {
|
|
t.Setenv("GOOGLE_SHEETS_ID", "sheet-123")
|
|
t.Setenv("SHEET_RANGE", "")
|
|
t.Setenv("ROTA_CACHE_PATH", "")
|
|
t.Setenv("SYNC_INTERVAL", "")
|
|
|
|
cfg, err := LoadConfig()
|
|
if err != nil {
|
|
t.Fatalf("LoadConfig: %v", err)
|
|
}
|
|
if cfg.SpreadsheetID != "sheet-123" {
|
|
t.Errorf("SpreadsheetID: got %q", cfg.SpreadsheetID)
|
|
}
|
|
wantRange := fmt.Sprintf("%d!A1:F100", time.Now().Year())
|
|
if cfg.SheetRange != wantRange {
|
|
t.Errorf("SheetRange default: got %q, want %q", cfg.SheetRange, wantRange)
|
|
}
|
|
if cfg.CachePath != "rota.json" {
|
|
t.Errorf("CachePath default: got %q", cfg.CachePath)
|
|
}
|
|
if cfg.SyncInterval != 30*time.Minute {
|
|
t.Errorf("SyncInterval default: got %v", cfg.SyncInterval)
|
|
}
|
|
}
|
|
|
|
func TestLoadConfigRequiresSpreadsheetID(t *testing.T) {
|
|
t.Setenv("GOOGLE_SHEETS_ID", "")
|
|
if _, err := LoadConfig(); err == nil {
|
|
t.Fatal("expected error when GOOGLE_SHEETS_ID is missing")
|
|
}
|
|
}
|
|
|
|
func TestLoadConfigRejectsBadInterval(t *testing.T) {
|
|
t.Setenv("GOOGLE_SHEETS_ID", "sheet-123")
|
|
t.Setenv("SYNC_INTERVAL", "not-a-duration")
|
|
if _, err := LoadConfig(); err == nil {
|
|
t.Fatal("expected error for unparseable SYNC_INTERVAL")
|
|
}
|
|
}
|
|
|
|
func TestLoadConfigRejectsNonPositiveInterval(t *testing.T) {
|
|
t.Setenv("GOOGLE_SHEETS_ID", "sheet-123")
|
|
t.Setenv("SYNC_INTERVAL", "0s")
|
|
if _, err := LoadConfig(); err == nil {
|
|
t.Fatal("expected error for non-positive SYNC_INTERVAL")
|
|
}
|
|
}
|
|
|
|
func TestSyncSuccessReplacesCache(t *testing.T) {
|
|
store := NewStore(filepath.Join(t.TempDir(), "rota.json"))
|
|
fixed := time.Date(2026, 6, 17, 20, 0, 0, 0, time.UTC)
|
|
|
|
sy := NewSyncer(store, func(context.Context) (Rota, error) { return sampleRota(), nil })
|
|
sy.now = func() time.Time { return fixed }
|
|
|
|
if err := sy.Sync(context.Background()); err != nil {
|
|
t.Fatalf("Sync: %v", err)
|
|
}
|
|
rota, ts := store.Snapshot()
|
|
if len(rota.People) != 1 || !ts.Equal(fixed) {
|
|
t.Errorf("cache not updated: people=%d ts=%v", len(rota.People), ts)
|
|
}
|
|
}
|
|
|
|
func TestSyncFailurePreservesCache(t *testing.T) {
|
|
store := NewStore(filepath.Join(t.TempDir(), "rota.json"))
|
|
good := time.Date(2026, 6, 17, 20, 0, 0, 0, time.UTC)
|
|
if err := store.Replace(sampleRota(), good); err != nil {
|
|
t.Fatalf("seed Replace: %v", err)
|
|
}
|
|
|
|
wantErr := errors.New("sheet unreachable")
|
|
sy := NewSyncer(store, func(context.Context) (Rota, error) { return Rota{}, wantErr })
|
|
|
|
if err := sy.Sync(context.Background()); !errors.Is(err, wantErr) {
|
|
t.Fatalf("Sync error: got %v, want %v", err, wantErr)
|
|
}
|
|
rota, ts := store.Snapshot()
|
|
if len(rota.People) != 1 || !ts.Equal(good) {
|
|
t.Errorf("cache should be untouched: people=%d ts=%v", len(rota.People), ts)
|
|
}
|
|
}
|