refactor: introduce clock to make tests reproducible

This commit is contained in:
2026-05-13 20:24:56 +00:00
parent 7e6c47a50e
commit ca5f5f95e2
9 changed files with 140 additions and 84 deletions

View File

@@ -6,11 +6,15 @@ import (
"testing"
"time"
"github.com/wotra/wotra/internal/clock"
"github.com/wotra/wotra/internal/service"
"github.com/wotra/wotra/internal/store"
)
func newTestServices(t *testing.T) *service.EntryService {
// testAnchor is a fixed Tuesday used as "now" across entry service tests.
var testAnchor = time.Date(2026, 5, 13, 10, 0, 0, 0, time.UTC)
func newTestServices(t *testing.T) (*service.EntryService, *clock.FixedClock) {
t.Helper()
db, err := store.Open(":memory:")
if err != nil {
@@ -23,12 +27,14 @@ func newTestServices(t *testing.T) *service.EntryService {
settingsStore := store.NewSettingsStore(db)
tz, _ := time.LoadLocation("UTC")
return service.NewEntryService(entryStore, closedDayStore, settingsStore, store.NewSyncStore(db), tz)
clk := clock.Fixed(testAnchor)
svc := service.NewEntryService(entryStore, closedDayStore, settingsStore, store.NewSyncStore(db), tz, clk)
return svc, clk
}
func TestStartStop(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, _ := newTestServices(t)
entry, err := svc.Start(ctx, "test entry")
if err != nil {
@@ -55,7 +61,7 @@ func TestStartStop(t *testing.T) {
func TestStartTwiceFails(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, _ := newTestServices(t)
if _, err := svc.Start(ctx, ""); err != nil {
t.Fatal(err)
@@ -71,7 +77,7 @@ func TestStartTwiceFails(t *testing.T) {
func TestStopWithoutStart(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, _ := newTestServices(t)
_, err := svc.Stop(ctx)
if err != service.ErrEntryNotRunning {
@@ -81,7 +87,7 @@ func TestStopWithoutStart(t *testing.T) {
func TestUpdateEntry(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, _ := newTestServices(t)
entry, _ := svc.Start(ctx, "initial note")
stopped, _ := svc.Stop(ctx)
@@ -99,7 +105,7 @@ func TestUpdateEntry(t *testing.T) {
func TestDeleteEntry(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, _ := newTestServices(t)
entry, _ := svc.Start(ctx, "")
svc.Stop(ctx)
@@ -119,14 +125,14 @@ func TestDeleteEntry(t *testing.T) {
func TestListEntries(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, clk := newTestServices(t)
for i := 0; i < 3; i++ {
svc.Start(ctx, "")
svc.Stop(ctx)
}
today := time.Now().UTC().Format("2006-01-02")
today := clk.Now().UTC().Format("2006-01-02")
entries, err := svc.List(ctx, today, today)
if err != nil {
t.Fatal(err)
@@ -138,9 +144,9 @@ func TestListEntries(t *testing.T) {
func TestCreateInterval(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, clk := newTestServices(t)
now := time.Now().UTC()
now := clk.Now().UTC()
startMs := now.Add(-2 * time.Hour).UnixMilli()
endMs := now.Add(-1 * time.Hour).UnixMilli()
@@ -165,9 +171,9 @@ func TestCreateInterval(t *testing.T) {
func TestCreateIntervalEndBeforeStart(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, clk := newTestServices(t)
now := time.Now().UTC().UnixMilli()
now := clk.Now().UTC().UnixMilli()
_, err := svc.CreateInterval(ctx, service.CreateIntervalInput{
StartTime: now,
EndTime: now - 1000,
@@ -179,11 +185,11 @@ func TestCreateIntervalEndBeforeStart(t *testing.T) {
func TestCreateIntervalCrossesMidnight(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, clk := newTestServices(t)
yesterday := time.Now().UTC().Add(-24 * time.Hour)
yesterday := clk.Now().UTC().Add(-24 * time.Hour)
startMs := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 23, 0, 0, 0, time.UTC).UnixMilli()
endMs := time.Now().UTC().Add(time.Hour).UnixMilli()
endMs := clk.Now().UTC().Add(time.Hour).UnixMilli()
_, err := svc.CreateInterval(ctx, service.CreateIntervalInput{
StartTime: startMs,
@@ -212,13 +218,14 @@ func TestUpdateRejectsClosedDay(t *testing.T) {
settingsStore := store.NewSettingsStore(db)
syncStore := store.NewSyncStore(db)
tz, _ := time.LoadLocation("UTC")
svc := service.NewEntryService(entryStore, closedDayStore, settingsStore, syncStore, tz)
daySvc := service.NewDayService(entryStore, closedDayStore, closedWeekStore, settingsStore, syncStore, tz)
clk := clock.Fixed(testAnchor)
svc := service.NewEntryService(entryStore, closedDayStore, settingsStore, syncStore, tz, clk)
daySvc := service.NewDayService(entryStore, closedDayStore, closedWeekStore, settingsStore, syncStore, tz, clk)
entry, _ := svc.Start(ctx, "")
svc.Stop(ctx)
today := time.Now().UTC().Format("2006-01-02")
today := clk.Now().UTC().Format("2006-01-02")
if _, err := daySvc.CloseDay(ctx, today); err != nil {
t.Fatalf("CloseDay: %v", err)
}
@@ -235,10 +242,9 @@ func TestUpdateRejectsClosedDay(t *testing.T) {
func TestCreateIntervalRejectsFutureDay(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, clk := newTestServices(t)
// Build a start_time that is tomorrow.
tomorrow := time.Now().UTC().AddDate(0, 0, 1)
tomorrow := clk.Now().UTC().AddDate(0, 0, 1)
startMs := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), 9, 0, 0, 0, time.UTC).UnixMilli()
endMs := startMs + 3_600_000 // +1h
@@ -257,10 +263,9 @@ func TestCreateIntervalRejectsFutureDay(t *testing.T) {
func TestUpdateRejectsMoveToFutureDay(t *testing.T) {
ctx := context.Background()
svc := newTestServices(t)
svc, clk := newTestServices(t)
// Create a valid interval for today.
now := time.Now().UTC()
now := clk.Now().UTC()
startMs := time.Date(now.Year(), now.Month(), now.Day(), 8, 0, 0, 0, time.UTC).UnixMilli()
endMs := startMs + 3_600_000
entry, err := svc.CreateInterval(ctx, service.CreateIntervalInput{
@@ -271,7 +276,6 @@ func TestUpdateRejectsMoveToFutureDay(t *testing.T) {
t.Fatalf("CreateInterval: %v", err)
}
// Try to move start_time to tomorrow.
tomorrow := now.AddDate(0, 0, 1)
futureStart := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), 8, 0, 0, 0, time.UTC).UnixMilli()
_, err = svc.Update(ctx, entry.ID, service.UpdateEntryInput{