package main import ( "strings" "testing" "time" "github.com/carlosframework/platform/internal/dbdoor" ) func TestParseDBAt(t *testing.T) { now := time.Date(2026, 10, 8, 12, 0, 0, 0, time.UTC) for _, ok := range []string{"2026-10-07T14:00:00Z", "2026-10-07T15:00:00+01:00", "2026-10-07T14:00:00.5Z"} { got, err := parseDBAt(ok, now) if err != nil { t.Errorf("parseDBAt(%q) = %v, want a time", ok, err) } else if !got.Before(now) { t.Errorf("parseDBAt(%q) = %v, want before %v", ok, got, now) } } // An explicit time that is Go's zero time must not read as "no --at" // (found in Astra's review). for _, early := range []string{"0001-01-01T00:00:00Z", "0001-01-01T01:00:00+01:00"} { if got, err := parseDBAt(early, now); err != nil || got.IsZero() { t.Errorf("parseDBAt(%q) = %v, %v, want a non-zero time before any history", early, got, err) } } if got, _ := parseDBAt("", now); !got.IsZero() { t.Errorf("parseDBAt(\"\") = %v, want zero (the newest copy)", got) } bad := map[string]string{ "2026-10-07 14:00": `--at "2026-10-07 14:00" is not a time. Write it in RFC 3339 with a time zone, for example 2026-10-07T14:00:00Z for UTC`, "2026-10-07T14:00:00": `--at "2026-10-07T14:00:00" is not a time. Write it in RFC 3339 with a time zone, for example 2026-10-07T14:00:00Z for UTC`, "yesterday": `--at "yesterday" is not a time. Write it in RFC 3339 with a time zone, for example 2026-10-07T14:00:00Z for UTC`, "2026-10-09T00:00:00Z": `--at 2026-10-09T00:00:00Z is in the future. Leave --at out to read the newest copy`, } for in, want := range bad { if _, err := parseDBAt(in, now); err == nil || err.Error() != want { t.Errorf("parseDBAt(%q) = %v, want %q", in, err, want) } } } func TestDBRestoreErrorsForAnAsOfRead(t *testing.T) { oldest := time.Date(2026, 10, 1, 9, 12, 44, 0, time.UTC) cases := map[error]string{ &dbdoor.BeforeHistoryError{Oldest: oldest}: "a.go.tito.io's replica does not go back that far. The oldest point it keeps is 2026-10-01 09:12:44 UTC", dbdoor.ErrNoTimes: "a.go.tito.io's replica can't be read as of a time yet. Leave --at out to read the newest copy", } for err, want := range cases { if got := dbRestoreError("a.go.tito.io", err).Error(); got != want { t.Errorf("%v -> %q, want %q", err, got, want) } } } func TestDBAsOfLines(t *testing.T) { r := &dbdoor.Restored{TXID: 42, At: time.Date(2026, 10, 7, 13, 58, 2, 0, time.UTC)} at := time.Date(2026, 10, 7, 15, 0, 0, 0, time.FixedZone("", 3600)) if got, want := dbPullHolds(r, at), "It holds every change up to transaction 42, written 2026-10-07 13:58:02 UTC, the last one replicated before 2026-10-07 14:00:00 UTC.\n"; got != want { t.Errorf("pull with --at:\n got %q\nwant %q", got, want) } if got, want := dbPullHolds(r, time.Time{}), "It holds every change up to transaction 42, written 2026-10-07 13:58:02 UTC.\n"; got != want { t.Errorf("pull without --at:\n got %q\nwant %q", got, want) } if got, want := dbQueryStatus("a.go.tito.io", r, at), "Querying a copy of a.go.tito.io's database as it was before 2026-10-07 14:00:00 UTC, up to transaction 42, written 2026-10-07 13:58:02 UTC. Nothing you run here reaches a.go.tito.io.\n"; got != want { t.Errorf("query with --at:\n got %q\nwant %q", got, want) } if got, want := dbQueryStatus("a.go.tito.io", r, time.Time{}), "Querying a copy of a.go.tito.io's database, up to transaction 42, written 2026-10-07 13:58:02 UTC. Nothing you run here reaches a.go.tito.io.\n"; got != want { t.Errorf("query without --at:\n got %q\nwant %q", got, want) } if !strings.Contains(dbUsage, "Add --at