Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public async Task GetBlocking_FlagsThePagesRows_ByTheirOwnStoredPlans()
try
{
await DarlingMcpTestData.RegisterServerAsync(connection, ServerId, ServerName, ct);
/* The tool reads its "last N hours" window from the real clock, which the test clock override cannot move (#5608). */
var now = DarlingMcpTestData.TruncateToSeconds(DateTime.UtcNow);

/* Newest first by event_time: spid 101 (both plans), 102 (blocked only), 103 (blocking only), 104 (empty strings),
Expand Down Expand Up @@ -132,6 +133,7 @@ public async Task GetDeadlocks_FlagsThePagesRows_ByTheirOwnStoredPlans()
try
{
await DarlingMcpTestData.RegisterServerAsync(connection, ServerId, ServerName, ct);
/* The tool reads its "last N hours" window from the real clock, which the test clock override cannot move (#5608). */
var now = DarlingMcpTestData.TruncateToSeconds(DateTime.UtcNow);

/* Newest first by deadlock_time: a plan, an empty string, NULL, and an older plan the page of three leaves out. */
Expand Down Expand Up @@ -180,7 +182,7 @@ public async Task TheListStatements_PlannerOutput_NamesNoPlanColumn()
await connection.OpenAsync(ct);
await PrepareStoreAsync(cs, connection, ct);

var now = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
var now = LiveClock.Now();
foreach (var sql in new[]
{
DarlingBlockingReader.BlockedProcessReportsSql,
Expand Down
3 changes: 2 additions & 1 deletion Darling/Darling.Tests/CaptureDownChunkOrderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ outside the collector catalog and so outside ConvertToHypertablesAsync. */
/* Eight days of one-minute blocked_process_report and five-minute deadlocks rows, plus a filler
collector so the newest chunk holds rows the arms must skip past. All Kind-Unspecified: naive-UTC
storage, see DarlingObservability.LogCollectionAsync. */
var utcNow = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
/* #5608: the end of the window is a fixed point inside one chunk, so the chunk layout the plan is read against is the same at any hour. */
var utcNow = LiveClock.AnchoredEnd();
await SeedHistoryAsync(connection, utcNow, ct);

/* The two verdict rows. deadlocks: SESSION_MISSING three days ago, then a SUCCESS a minute ago — NOT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ private static void AssertOracleSaw(Result mcp, DateTime now)

private static DateTime Now()
{
var now = DateTime.UtcNow;
var now = DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc);
return new DateTime(now.Ticks - (now.Ticks % TimeSpan.TicksPerMillisecond), DateTimeKind.Utc);
}

Expand Down
6 changes: 3 additions & 3 deletions Darling/Darling.Tests/DailySummaryReadShapeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -556,9 +556,9 @@ private static async Task<Seeded> SeedAsync(string what)
await TimescaleSupport.EnsureContinuousAggregatesAsync(connection, null, ct);
await RegisterServerAsync(connection, ct);

var d0 = DateTime.SpecifyKind(DateTime.UtcNow.Date.AddDays(-14), DateTimeKind.Unspecified);
var d0 = LiveClock.Now().Date.AddDays(-14);
var days = Enumerable.Range(0, 10).Select(n => d0.AddDays(n)).ToArray();
Assert.True(DateTime.UtcNow - days[^1].AddDays(1) > TimescaleSupport.DailyRefreshStartSpan, "the seed must sit below every refresh policy's window");
Assert.True(DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc) - days[^1].AddDays(1) > TimescaleSupport.DailyRefreshStartSpan, "the seed must sit below every refresh policy's window");

foreach (var (day, hashes) in new[] { (0, 3), (2, 5), (3, 4), (5, 6), (6, 2), (7, 3), (8, 1) })
{
Expand Down Expand Up @@ -634,7 +634,7 @@ INSERT INTO servers (server_id, server_name, display_name, is_enabled, sql_major
command.Parameters.AddWithValue(ServerId);
command.Parameters.AddWithValue(ServerName);
command.Parameters.AddWithValue(ServerName);
command.Parameters.AddWithValue(DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified));
command.Parameters.AddWithValue(LiveClock.Now());
await command.ExecuteNonQueryAsync(ct);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public async Task AgStatesReader_MatchesTheOldUnboundedStatements_AcrossEverySer
var bodySucceeded = false;
try
{
var now = Micro(DateTime.UtcNow);
var now = Micro(DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc));
await SeedAsync(connection, now, ct);

var sentinelIds = new HashSet<int>(AllNames.Select(Id));
Expand Down Expand Up @@ -328,7 +328,7 @@ public async Task AgStatesReader_StepTwoStaysBounded_ForCurrentAndStaleServers_A
var bodySucceeded = false;
try
{
var now = Micro(DateTime.UtcNow);
var now = Micro(DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc));
await SeedAsync(connection, now, ct);
var sentinelIds = new HashSet<int>(AllNames.Select(Id));

Expand Down Expand Up @@ -443,7 +443,7 @@ ON CONFLICT (server_id) DO UPDATE SET is_enabled = $4, sql_major_version = 15
command.Parameters.AddWithValue(serverName);
command.Parameters.AddWithValue(serverName);
command.Parameters.AddWithValue(enabled);
command.Parameters.AddWithValue(DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified));
command.Parameters.AddWithValue(LiveClock.Now());
await command.ExecuteNonQueryAsync(ct);
}

Expand Down
4 changes: 2 additions & 2 deletions Darling/Darling.Tests/DarlingFleetReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ public async Task GetFleetOverview_ServerWithNoCollectionHistory_ReadsAwaitingFi
var bodySucceeded = false;
try
{
var now = DateTime.UtcNow;
var now = DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc);

/* Registered, but no collection_log row is ever inserted for this server_id. */
await InsertServerAsync(connection, NoHistoryServerId, NoHistoryName, 3, ct);
Expand Down Expand Up @@ -848,7 +848,7 @@ public async Task GetFleetOverview_PerServerFallbackAndBanding_AgainstDevPostgre
var bodySucceeded = false;
try
{
var now = DateTime.UtcNow;
var now = DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc);
var at = now.AddMinutes(-5); // inside the [now-1h, now] card window

/* Plant representative editions so the read-through card platform can be asserted end-to-end:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public async Task TheCensusExecutesAndAnswersOverThePopulation()
{
await DarlingMcpTestData.RegisterServerAsync(connection, ServerId, ServerName, ct);

var now = DarlingMcpTestData.TruncateToSeconds(DateTime.UtcNow);
var now = DarlingMcpTestData.TruncateToSeconds(DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc));
var newest = now.AddHours(-2);
var older = now.AddHours(-26);

Expand Down
4 changes: 2 additions & 2 deletions Darling/Darling.Tests/DarlingRetentionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ public async Task EndToEnd_PurgeDeletesExpiredRowsAndKeepsFreshOnes_AgainstDevPo
try
{
/* All timestamps Kind-Unspecified — naive-UTC storage, see PgCollectorRowWriter. */
var utcNow = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
var utcNow = LiveClock.Now();

/* wait_stats retention is 30 days: one row well past it, one fresh. Payload columns
are nullable, so the standard prefix is enough. */
Expand Down Expand Up @@ -905,7 +905,7 @@ exercised on every run. */
var bodySucceeded = false;
try
{
var utcNow = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
var utcNow = LiveClock.Now();

using (var insert = new NpgsqlCommand(
"INSERT INTO wait_stats (collection_id, collection_time, server_id, server_name) VALUES ($1, $2, $3, $4)", connection))
Expand Down
14 changes: 7 additions & 7 deletions Darling/Darling.Tests/DarlingSelfAlertTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5675,7 +5675,7 @@ public async Task LiveStoreReads_ComputeCollectionStoppedAndCaptureDown()
var bodySucceeded = false;
try
{
var utcNow = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
var utcNow = LiveClock.Now();

/* One old SUCCESS (45 min ago), then 12 recent ERRORs — the last 10 runs are all failures and
the last success is well past the staleness window. */
Expand All @@ -5693,14 +5693,14 @@ the last success is well past the staleness window. */
Assert.Equal(DarlingSelfAlertEvaluator.ConsecutiveFailureThreshold, recentRuns);
Assert.Equal(0, recentSuccess);
Assert.True(DarlingSelfAlertEvaluator.IsCollectionStopped(
lastSuccess, recentRuns, recentSuccess, DateTime.UtcNow, out _));
lastSuccess, recentRuns, recentSuccess, DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc), out _));

/* Full path (#4757): the seeded 45-minute-old success and the stored failure streak are both
pre-restart rows to an evaluator that has just started, so at startup it must stay silent: the
staleness is judged from the service start (the later of the two), and the stored streak is
not armed until the server has been seen online. Once it has, the streak fires. Real-time
clock so the seeded rows read as stale in the store. */
var h = new Harness { Now = DateTime.UtcNow };
var h = new Harness { Now = DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc) };
var evaluator = h.Build();

await evaluator.EvaluateStoreAlertsAsync(postgres, LiveServerId, Name, connected: true, ct);
Expand All @@ -5713,7 +5713,7 @@ clock so the seeded rows read as stale in the store. */
/* A second evaluator that never sees the server online is the server that stays down across a
restart: silent at the start, fired by the staleness arm once the window has passed since the
start. Taken before the capture-down rows below, which add a fresh success. */
var hDown = new Harness { Now = DateTime.UtcNow };
var hDown = new Harness { Now = DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc) };
var downEvaluator = hDown.Build();

await downEvaluator.EvaluateStoreAlertsAsync(postgres, LiveServerId, Name, connected: false, ct);
Expand Down Expand Up @@ -5780,7 +5780,7 @@ public async Task LiveStoreReads_RecentWindow_IsNewestByTimeFirst_WithLogIdBreak
var bodySucceeded = false;
try
{
var utcNow = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
var utcNow = LiveClock.Now();
var older = utcNow.AddMinutes(-10);
var newest = utcNow.AddMinutes(-1);

Expand Down Expand Up @@ -5863,7 +5863,7 @@ public async Task LiveStoreReads_ExecuteBothAgQueries_AndReturnTheNewestSnapshot
var bodySucceeded = false;
try
{
var utcNow = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
var utcNow = LiveClock.Now();
var older = utcNow.AddMinutes(-5);

/* An older snapshot that must be filtered out by the MAX(collection_time) predicate, a current one
Expand Down Expand Up @@ -5901,7 +5901,7 @@ public async Task LiveStoreReads_ExecuteBothAgQueries_AndReturnTheNewestSnapshot
/* End to end through the sweep entry point, against rows that are genuinely fresh: the disconnect
and the suspend are first sightings (silent baselines), and the 900-second lag is past the
300-second default, so exactly one alert lands. */
var h = new Harness { Now = DateTime.UtcNow };
var h = new Harness { Now = DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc) };
var evaluator = h.Build();
await evaluator.EvaluateStoreAlertsAsync(postgres, LiveServerId, Name, connected: true, ct);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ sits outside the collector catalog and so outside ConvertToHypertablesAsync. */
var bodySucceeded = false;
try
{
var nowUtc = DateTime.UtcNow;
/* #5608: the end of the window is a fixed point inside one chunk, so the chunk layout the plan is read against is the same at any hour. */
var nowUtc = DateTime.SpecifyKind(LiveClock.AnchoredEnd(), DateTimeKind.Utc);
long logId = 4_469_000_000;

/* 30 days of history, one row per collector per day, most of it old enough to compress —
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ read under test — the same race the plan-shape file's own live seeds guard aga
var bodySucceeded = false;
try
{
var nowUtc = DateTime.UtcNow;
/* #5608: the end of the window is a fixed point inside one chunk, so the chunk layout the plan is read against is the same at any hour. */
var nowUtc = DateTime.SpecifyKind(LiveClock.AnchoredEnd(), DateTimeKind.Utc);
long logId = 4_469_200_000;

/* 30 days of history, one row per collector per day — most chunks close to a day wide and old
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ public async Task ReadCollectorWatermarksAsync_MatchesTheBoundedGroupByOracle()
var bodySucceeded = false;
try
{
var nowUtc = DateTime.UtcNow;
/* #5608: the end of the window is a fixed point inside one chunk, so the chunk layout the plan is read against is the same at any hour. */
var nowUtc = DateTime.SpecifyKind(LiveClock.AnchoredEnd(), DateTimeKind.Utc);
long logId = 4_150_100_000;

/* Several real collector names (a mix of cadences), 10 days of history so most chunks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ public async Task TheFlooredReads_ReturnExactlyWhatTheUnflooredReadsReturned_Aga
try
{
await DeleteSentinelRowsAsync(connection, ct);
var now = Micro(DateTime.UtcNow);
var now = Micro(DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc));
var marks = Marks(now);
await SeedAsync(connection, now, marks, ct);

Expand Down Expand Up @@ -365,7 +365,7 @@ public async Task TheFlooredReads_PlanAtMostThreeChunksForA24HourWindow_AgainstD
try
{
await DeleteSentinelRowsAsync(connection, ct);
var now = Micro(DateTime.UtcNow);
var now = Micro(DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc));
var marks = Marks(now);
await SeedAsync(connection, now, marks, ct);
var floor = EventWindowFloor.For(marks.WindowStart);
Expand Down
10 changes: 5 additions & 5 deletions Darling/Darling.Tests/FleetReadsAreBoundedByTheFleetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ public async Task TheBoundedReads_ReturnTheUnboundedReadsRows_AgainstDevPostgres
try
{
await DeleteSentinelRowsAsync(connection, ct);
var now = Micro(DateTime.UtcNow);
var now = Micro(DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc));
await SeedAsync(connection, now, ct);

/* The newest-row reads: identical rows for every compared sentinel. */
Expand Down Expand Up @@ -513,7 +513,7 @@ public async Task TheOverview_BuildsEachCardFromItsNewestReading_AgainstDevPostg
try
{
await DeleteSentinelRowsAsync(connection, ct);
var now = Micro(DateTime.UtcNow);
var now = Micro(DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc));
await SeedAsync(connection, now, ct);

var result = await DarlingFleetReader.GetFleetOverviewAsync(postgres, now.AddHours(-1), now, now, cancellationToken: ct);
Expand Down Expand Up @@ -551,7 +551,7 @@ before the window (an index descent, FleetOlderCollectionSql), so the page can s
Assert.Equal(ServerCollectionStatus.Offline.Word(), dark.Status);
Assert.False(dark.AwaitingFirstCollection);
Assert.NotNull(dark.LastCollectionTime);
Assert.InRange((DateTime.UtcNow - dark.LastCollectionTime!.Value).TotalDays, 4.5, 5.5);
Assert.InRange((DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc) - dark.LastCollectionTime!.Value).TotalDays, 4.5, 5.5);

var never = cards[NeverCollected];
Assert.Null(never.CpuPercent);
Expand Down Expand Up @@ -620,7 +620,7 @@ public async Task TheOlderCollectionRead_NeedsOnlyOneConnectionAtATime_AndIsCach
try
{
await DeleteSentinelRowsAsync(connection, ct);
var now = Micro(DateTime.UtcNow);
var now = Micro(DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc));
await SeedAsync(connection, now, ct);

var first = await DarlingFleetReader.ReadLastCollectionAsync(postgres, now, null, ct);
Expand Down Expand Up @@ -680,7 +680,7 @@ public async Task TheBoundedReads_StopAtTheNewestChunk_AndPlanOnlyTheWindowsChun
try
{
await DeleteSentinelRowsAsync(connection, ct);
var now = Micro(DateTime.UtcNow);
var now = Micro(DateTime.SpecifyKind(LiveClock.Now(), DateTimeKind.Utc));
await SeedAsync(connection, now, ct);
using (var analyze = new NpgsqlCommand("ANALYZE collect.memory_stats; ANALYZE collect.deadlocks; ANALYZE collect.servers;", connection))
{
Expand Down
6 changes: 5 additions & 1 deletion Darling/Darling.Tests/ForcePlanFailuresAccessPathTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,11 @@ public async Task TheShippedRead_PlansAsAnIndexOnlyScanOnTheCoveringIndex_Agains
100 ns, so a raw UtcNow does not survive the round trip and the #3579 stamp assertion below
(tick-equality against what was seeded) would fail on any clock that is not itself
microsecond-aligned — Windows' is not; the first CI run proved it by three ticks. */
var rawNow = DateTime.UtcNow;
/* #5608: the real clock on purpose, not LiveClock. GetForcePlanFailuresAsync below takes its two-hour
window from the product's own clock, so a seed placed by DARLING_TEST_CLOCK_UTC falls outside it and
the read comes back empty (five of five runs at a 00:30 override, with every plan assertion above
already passed). The plan assertions hold across a chunk boundary, so the seed needs no anchor. */
var rawNow = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc);
var utcNow = DateTime.SpecifyKind(new DateTime(rawNow.Ticks - (rawNow.Ticks % 10)), DateTimeKind.Unspecified);
for (var pass = 7; pass >= 0; pass--)
{
Expand Down
Loading
Loading