Skip to content

Implement unified time testing with controllable app_now() function#329

Open
tonyalaribe wants to merge 2 commits intomasterfrom
claude/unified-time-testing-EwfDg
Open

Implement unified time testing with controllable app_now() function#329
tonyalaribe wants to merge 2 commits intomasterfrom
claude/unified-time-testing-EwfDg

Conversation

@tonyalaribe
Copy link
Contributor

Summary

This PR introduces a unified time testing system that allows tests to control time across both Haskell effects and PostgreSQL triggers/defaults. It replaces the frozen time approach with a mutable, advanceable test clock that syncs with PostgreSQL's app_now() function via a custom GUC variable.

Key Changes

Database Migration

  • Added static/migrations/0033_app_now_function.sql which:
    • Creates app_now() function that reads from app.current_time GUC variable, falling back to NOW() in production
    • Updates set_updated_at() trigger to use app_now()
    • Updates new_anomaly_proc(), check_triggered_query_monitors(), and check_tests_to_trigger() procedures to use app_now() for background job scheduling

New Test Clock Module

  • Created src/Pkg/TestClock.hs providing:
    • TestClock type backed by an IORef UTCTime
    • advanceTime and setTestTime for controlling the test clock
    • runMutableTime to interpret the Time effect from a mutable clock
    • syncConnectionTime to sync the test clock to PostgreSQL's GUC on each connection checkout
    • runWithTimeSyncedPool to wrap connection pools with automatic time synchronization

Test Infrastructure Updates

  • Updated Pkg.TestUtils to:
    • Accept TestClock parameter in background job runners
    • Export time advancement helpers (advanceTestTime, advanceMinutes, advanceHours, advanceDays)
    • Create and manage TestClock in TestResources
    • Use runMutableTime and runWithTimeSyncedPool instead of runFrozenTime

Query Updates for Time Consistency

  • Updated multiple query functions to accept Time :> es constraint and use Time.currentTime instead of NOW():
    • Models.Apis.RequestDumps: getRequestDumpForReports, getRequestDumpsForPreviousReportPeriod
    • Models.Telemetry.Telemetry: getDataPointsData, getMetricChartListData
    • Models.Apis.Anomalies: countAnomalies, acknowledgeAnomalies
    • Models.Apis.Issues: updateIssueWithNewAnomaly, updateIssueEnhancement
    • Models.Apis.LogPatterns: acknowledgeLogPatterns
    • Models.Apis.Monitors: updateQMonitorTriggeredState
    • Models.Projects.Projects: projectCacheById
    • Models.Projects.ProjectMembers and Models.Projects.ProjectApiKeys: Similar updates

Test Updates

  • Updated integration tests to:
    • Pass TestClock to background job runners and response handlers
    • Use getTestTime instead of getCurrentTime for test assertions
    • Remove dependency on runFrozenTime in favor of mutable clock

Implementation Details

  • The test clock is synced to PostgreSQL connections via set_config('app.current_time', ?, true) which makes the setting transaction-scoped and auto-resets when connections return to the pool
  • All time-dependent queries now explicitly use the test clock's time rather than relying on database-side NOW() calls
  • This ensures consistent time behavior across Haskell effects, background job scheduling, and database triggers during testing

https://claude.ai/code/session_019Mn7XLed4oq6j7dWqciekH

claude and others added 2 commits February 27, 2026 13:01
…nction

Implements a hybrid approach to unify time management across the Haskell
app layer and PostgreSQL database in tests, enabling time fast-forwarding
for timeseries data and background job testing.

Three components:

1. Mutable TestClock (src/Pkg/TestClock.hs):
   - IORef-backed clock with advanceTime/setTestTime/getTestTime
   - runMutableTime: custom Time effect interpreter reading from IORef
   - runWithTimeSyncedPool: pool wrapper that sets DB GUC on each checkout

2. app_now() PostgreSQL function (migration 0033):
   - Reads app.current_time GUC, falls back to NOW() in production
   - Updated triggers: set_updated_at, new_anomaly_proc,
     check_triggered_query_monitors, check_tests_to_trigger

3. NOW() replaced with ? parameters in 16 source files:
   - All SQL queries now receive time from Time.currentTime effect
   - Production uses real time; tests use mutable TestClock time

Test infrastructure updates:
- TestResources gains trTestClock field
- All test runners thread TestClock through effect stacks
- Replaced getCurrentTime with getTestTime in all test specs
- Added advanceTestTime/advanceMinutes/advanceHours/advanceDays helpers

https://claude.ai/code/session_019Mn7XLed4oq6j7dWqciekH
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants