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,12 +6,16 @@ import (
"testing"
"time"
"github.com/wotra/wotra/internal/clock"
"github.com/wotra/wotra/internal/domain"
"github.com/wotra/wotra/internal/service"
"github.com/wotra/wotra/internal/store"
)
func newFullServices(t *testing.T) (*service.EntryService, *service.DayService, *service.WeekService, *service.SettingsService) {
// weekTestAnchor is a fixed Tuesday (2026-W20) used as "now" across week service tests.
var weekTestAnchor = time.Date(2026, 5, 13, 10, 0, 0, 0, time.UTC)
func newFullServices(t *testing.T) (*service.EntryService, *service.DayService, *service.WeekService, *service.SettingsService, *clock.FixedClock) {
t.Helper()
db, err := store.Open(":memory:")
if err != nil {
@@ -26,12 +30,13 @@ func newFullServices(t *testing.T) (*service.EntryService, *service.DayService,
syncStore := store.NewSyncStore(db)
settingsStore := store.NewSettingsStore(db)
tz, _ := time.LoadLocation("UTC")
clk := clock.Fixed(weekTestAnchor)
entrySvc := service.NewEntryService(entryStore, closedDayStore, settingsStore, syncStore, tz)
daySvc := service.NewDayService(entryStore, closedDayStore, closedWeekStore, settingsStore, syncStore, tz)
weekSvc := service.NewWeekService(closedDayStore, closedWeekStore, entryStore, settingsStore, adjustmentStore, syncStore, db, tz)
settingsSvc := service.NewSettingsService(settingsStore, syncStore)
return entrySvc, daySvc, weekSvc, settingsSvc
entrySvc := service.NewEntryService(entryStore, closedDayStore, settingsStore, syncStore, tz, clk)
daySvc := service.NewDayService(entryStore, closedDayStore, closedWeekStore, settingsStore, syncStore, tz, clk)
weekSvc := service.NewWeekService(closedDayStore, closedWeekStore, entryStore, settingsStore, adjustmentStore, syncStore, db, tz, clk)
settingsSvc := service.NewSettingsService(settingsStore, syncStore, clk)
return entrySvc, daySvc, weekSvc, settingsSvc, clk
}
func TestWeekDayKeys(t *testing.T) {
@@ -65,7 +70,7 @@ func TestWeekDayKeys(t *testing.T) {
func TestCloseWeekBasic(t *testing.T) {
ctx := context.Background()
entrySvc, daySvc, weekSvc, _ := newFullServices(t)
entrySvc, daySvc, weekSvc, _, _ := newFullServices(t)
monday := time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC)
weekKey := "2024-W03"
@@ -98,7 +103,7 @@ func TestCloseWeekBasic(t *testing.T) {
func TestCloseWeekMissingDayFails(t *testing.T) {
ctx := context.Background()
entrySvc, daySvc, weekSvc, _ := newFullServices(t)
entrySvc, daySvc, weekSvc, _, _ := newFullServices(t)
monday := time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC)
@@ -125,7 +130,7 @@ func TestCloseWeekMissingDayFails(t *testing.T) {
func TestCloseWeekTwiceFails(t *testing.T) {
ctx := context.Background()
_, daySvc, weekSvc, _ := newFullServices(t)
_, daySvc, weekSvc, _, _ := newFullServices(t)
monday := time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC)
for i := 0; i < 5; i++ {
@@ -142,7 +147,7 @@ func TestCloseWeekTwiceFails(t *testing.T) {
func TestReopenWeek(t *testing.T) {
ctx := context.Background()
_, daySvc, weekSvc, _ := newFullServices(t)
_, daySvc, weekSvc, _, _ := newFullServices(t)
monday := time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC)
for i := 0; i < 5; i++ {
@@ -161,11 +166,13 @@ func TestReopenWeek(t *testing.T) {
}
func TestCloseWeekMidWeek(t *testing.T) {
// weekTestAnchor = 2026-05-13 (Tuesday, 2026-W20).
// Mon 2026-05-11 and Tue 2026-05-13 are past workdays; Wed-Fri are future.
ctx := context.Background()
_, daySvc, weekSvc, _ := newFullServices(t)
_, daySvc, weekSvc, _, clk := newFullServices(t)
tz, _ := time.LoadLocation("UTC")
now := time.Now().In(tz)
now := clk.Now().In(tz)
isoYear, isoWeek := now.ISOWeek()
weekKey := fmt.Sprintf("%d-W%02d", isoYear, isoWeek)
@@ -191,7 +198,7 @@ func TestWeekSnapshotUpdatesWhenDayReopened(t *testing.T) {
// Regression: closing a day after the week is already closed must update
// the frozen worked_ms/delta_ms on the closed week.
ctx := context.Background()
entrySvc, daySvc, weekSvc, _ := newFullServices(t)
entrySvc, daySvc, weekSvc, _, _ := newFullServices(t)
weekKey := "2024-W03"
monday := time.Date(2024, 1, 15, 0, 0, 0, 0, time.UTC)
@@ -246,7 +253,7 @@ func TestWeekSnapshotUpdatesWhenDayReopened(t *testing.T) {
func TestWeekServiceBalance(t *testing.T) {
ctx := context.Background()
_, daySvc, weekSvc, _ := newFullServices(t)
_, daySvc, weekSvc, _, clk := newFullServices(t)
// Empty — no closed weeks, no adjustments.
bal, err := weekSvc.Balance(ctx)
@@ -287,8 +294,8 @@ func TestWeekServiceBalance(t *testing.T) {
t.Errorf("weeks-only total: want 0, got %+v", bal)
}
// Add a +2h adjustment.
now := time.Now().UnixMilli()
// Add a +2h adjustment; use the fixed clock's time for timestamps.
now := clk.Now().UnixMilli()
adj, err := weekSvc.CreateAdjustment(ctx, &domain.BalanceAdjustment{
ID: "adj-1", DeltaMs: 7_200_000, Note: "carry-over",
EffectiveAt: now, CreatedAt: now, UpdatedAt: now,