Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
0bfbdcb
Tests: an Azure SQL Database master target must not alert on blocking…
erikdarlingdata Oct 1, 2026
a4621e3
Tests: get_deadlocks names the database each deadlock was captured for
erikdarlingdata Oct 1, 2026
88f4257
Azure SQL Database: a master target skips blocking and deadlock event…
erikdarlingdata Oct 1, 2026
7d396d7
MCP: get_deadlocks names the database each deadlock was captured for,…
erikdarlingdata Oct 1, 2026
4f25bde
Merge the get_deadlocks database pins into the master-duplicate tests
erikdarlingdata Oct 1, 2026
3746450
Merge the master-target alert skip into the master-duplicate fix
erikdarlingdata Oct 1, 2026
376ffbf
Merge the get_deadlocks database name into the master-duplicate fix
erikdarlingdata Oct 1, 2026
fb3ce66
Azure SQL Database: a master target's monitored-on-its-own list comes…
erikdarlingdata Oct 1, 2026
cb0bc44
Analysis context carries a master target's separately monitored datab…
erikdarlingdata Oct 1, 2026
4afd2c2
MCP: get_deadlocks says which database it records a deadlock under; t…
erikdarlingdata Oct 1, 2026
822f788
Tests: on an Azure SQL Database master, Lite's blocking and deadlock …
erikdarlingdata Oct 1, 2026
ece50bd
Lite analysis: an Azure SQL Database master's blocking and deadlock f…
erikdarlingdata Oct 1, 2026
b770d7a
Lite analysis: keep the provider's doc comment off the AnalyzeAsync s…
erikdarlingdata Oct 1, 2026
3f57bab
Tests: on an Azure SQL Database master, Darling's blocking and deadlo…
erikdarlingdata Oct 1, 2026
73096f1
Darling analysis: an Azure SQL Database master's blocking and deadloc…
erikdarlingdata Oct 1, 2026
d128b96
Tests: the CPU sample-time pin matches the snapshot argument without …
erikdarlingdata Oct 1, 2026
b790409
Merge remote-tracking branch 'origin/dev' into ci/4894-timehonesty-pin
erikdarlingdata Oct 1, 2026
e596ace
Merge the master-duplicate alert fix (#4894) into the analysis-findin…
erikdarlingdata Oct 1, 2026
1eb31ab
Merge the Darling analysis pins into the analysis-findings tests
erikdarlingdata Oct 1, 2026
a2fdc5e
Merge the Lite analysis fix into the analysis-findings change
erikdarlingdata Oct 1, 2026
2abea90
Merge the Darling analysis fix into the analysis-findings change
erikdarlingdata Oct 1, 2026
cf00546
Lite: master-target scope also covers BLOCKING_CHAIN, drill-down evid…
erikdarlingdata Oct 1, 2026
7fc8208
Scope blocking chains, drill-down evidence and read tools to an Azure…
erikdarlingdata Oct 1, 2026
9b0aa94
Merge the Darling half of the master analysis-scope fixes
erikdarlingdata Oct 1, 2026
6336f58
Darling: the master analysis scope also filters reconstructed chains,…
erikdarlingdata Oct 1, 2026
143e78e
Merge dev into the analysis-scope fix
erikdarlingdata Oct 1, 2026
b6cf349
Tests: analysis reads of blocked-process reports, deadlocks and the P…
erikdarlingdata Oct 1, 2026
7880325
Tests: Lite analysis reads of blocked-process reports and deadlocks w…
erikdarlingdata Oct 1, 2026
09c40fe
Tests: the Lite analysis window pins say what their three seeded rows…
erikdarlingdata Oct 1, 2026
3653d8e
Merge #4906's dev-merged head into the analysis event-time reads
erikdarlingdata Oct 1, 2026
5d81c0c
Analysis (Lite): the scoped deadlock read is bounded, a master-stampe…
erikdarlingdata Oct 1, 2026
b4ac0b1
Analysis: a master-stamped deadlock row is checked by its graph, and …
erikdarlingdata Oct 1, 2026
789bb76
Darling: the analysis facts, anomaly current-window counts and drill-…
erikdarlingdata Oct 1, 2026
84b5940
Lite: analysis facts, drill-downs, anomaly counts and event baselines…
erikdarlingdata Oct 1, 2026
b838557
Merge the Lite half of the deadlock scope fixes
erikdarlingdata Oct 1, 2026
294f524
Merge #4906's round-2 head into the analysis event-time reads
erikdarlingdata Oct 1, 2026
766d2f7
Tests: Lite's blocking and deadlock fact pins seed a second late-coll…
erikdarlingdata Oct 1, 2026
b302f31
Tests: Lite's anomaly pin names a missing spike in its failure message
erikdarlingdata Oct 1, 2026
47e8f9f
Tests: scoped drill-down and deadlock pins, chain-wait set pin, NULL-…
erikdarlingdata Oct 1, 2026
6406f8d
The two blocking-chain reads carry the collection-time floor, and the…
erikdarlingdata Oct 1, 2026
1f99487
SeparateDatabases takes a block body, so the member scan reads it whole
erikdarlingdata Oct 1, 2026
055468f
Tests: the analysis-pass worker fixture sets the server registry the …
erikdarlingdata Oct 1, 2026
9deb9bb
Tests: the event-baseline twin pin reads Lite's OnEventTime wrapper a…
erikdarlingdata Oct 1, 2026
e46b3ab
Tests: the scoped chain-fact pin reads the fact's real metadata keys
erikdarlingdata Oct 1, 2026
44c79b0
Merge commit 'e46b3ab5d8025fee839f9c0b387792d948fe4946' into ci/4913-…
erikdarlingdata Oct 1, 2026
e1490dd
Merge remote-tracking branch 'origin/dev' into ci/4913-dev-merge
erikdarlingdata Oct 1, 2026
8e8c547
Tests: the local-clock baseline pin uses Assert.Single for its one-ma…
erikdarlingdata Oct 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions Darling/Darling.Tests/AnomalyTileWindowEndTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ namespace Darling.Tests;
public sealed class AnomalyTileWindowEndTests
{
/// <summary>The closed spelling of the window end: a boundary sample is read.</summary>
private const string ClosedEnd = "collection_time <= $3";
private static readonly string[] ClosedEnds = ["collection_time <= $3", "event_time <= $3", "deadlock_time <= $3"];

/// <summary>The open spelling of the window end: a boundary sample is left for the next window.</summary>
private const string OpenEnd = "collection_time < $3";
private static readonly string[] OpenEnds = ["collection_time < $3", "event_time < $3", "deadlock_time < $3"];

/// <summary>The floor: at least these 11 reads end their window at $3 (three that were already open, eight that were closed). A read added later must use the open end too, which the closed-spelling check above guards.</summary>
private const int WindowReads = 11;
Expand All @@ -45,8 +45,11 @@ public void EveryWindowRead_ExcludesTheWindowEnd(string relative)
{
var source = ReadSource(relative);

Assert.DoesNotContain(ClosedEnd, source, StringComparison.Ordinal);
var found = CountOccurrences(source, OpenEnd);
foreach (var closed in ClosedEnds)
Assert.DoesNotContain(closed, source, StringComparison.Ordinal);
/* The blocking and deadlock counts window on the event time (event_time / deadlock_time), the rest on collection_time; all are open-ended. */
var found = 0;
foreach (var open in OpenEnds) found += CountOccurrences(source, open);
Assert.True(found >= WindowReads, $"Expected at least {WindowReads} reads ending at $3 with the open spelling, found {found}.");
}

Expand Down
25 changes: 25 additions & 0 deletions Darling/Darling.Tests/BlockingChainReadsFloorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using PerformanceMonitor.Darling.Analysis;
using Xunit;

namespace Darling.Tests;

/// <summary>
/// The two blocking-chain reads window on the report's own time like their siblings, so they also carry the
/// partition-column floor on <c>collection_time</c> (no upper side: a late-collected report still counts). Without
/// it every retained chunk of <c>blocked_process_reports</c> is opened to answer a window.
/// </summary>
public sealed class BlockingChainReadsFloorTests
{
[Theory]
[InlineData("fact")]
[InlineData("drill-down")]
public void ChainReads_CarryTheCollectionTimeFloor_AndNoUpperCollectionTimeBound(string read)
{
var sql = read == "fact" ? PgFactCollector.BlockingChainSql : PgDrillDownCollector.ReconstructedChainsSql;

Assert.Contains("event_time >= $2", sql, StringComparison.Ordinal);
Assert.Contains("collection_time >= $4", sql, StringComparison.Ordinal);
Assert.DoesNotContain("collection_time <", sql, StringComparison.Ordinal);
}
}
17 changes: 13 additions & 4 deletions Darling/Darling.Tests/DarlingEventBaselineCoveredDaysTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,16 @@ private static string EventBaselineBody(string source, string product)
return source[start..(end + End.Length)];
}

/// <summary>One provider's call of <c>EventBaselineSql</c> from a metric's arm: collector, log, event source, count.</summary>
private static (string Collector, string Log, string Events, string Count) ArmCall(string source, string metric, string product)
/// <summary>One provider's call of <c>EventBaselineSql</c> from a metric's arm: collector, log, event source, count,
/// and the event column when the arm wraps the call in Lite's <c>OnEventTime</c> (null when it does not).</summary>
private static (string Collector, string Log, string Events, string Count, string? EventColumn) ArmCall(string source, string metric, string product)
{
var match = Regex.Match(
source,
@"MetricNames\." + metric + @" => EventBaselineSql\(""([^""]+)"", ""([^""]+)"", ""([^""]+)"", ""([^""]+)""\)");
@"MetricNames\." + metric + @" => (?:OnEventTime\()?EventBaselineSql\(""([^""]+)"", ""([^""]+)"", ""([^""]+)"", ""([^""]+)""\)(?:, ""([^""]+)""\))?");
Assert.True(match.Success, $"{product}'s {metric} arm no longer calls EventBaselineSql with four literal arguments");
return (match.Groups[1].Value, match.Groups[2].Value, match.Groups[3].Value, match.Groups[4].Value);
return (match.Groups[1].Value, match.Groups[2].Value, match.Groups[3].Value, match.Groups[4].Value,
match.Groups[5].Success ? match.Groups[5].Value : null);
}

/// <summary>
Expand All @@ -192,6 +194,11 @@ private static (string Collector, string Log, string Events, string Count) ArmCa
/// product. What may differ is the four arguments, and those are pinned pairwise: the same collector name in both,
/// each product's log source the twin of the other's (<c>v_collection_log</c> is Lite's view over the table),
/// Lite's event source the view over the collector's own table and Darling's the collector's baseline aggregate.
///
/// <para>One deliberate difference rides OUTSIDE the shared body: Lite wraps its two arms in <c>OnEventTime</c>,
/// which moves the <c>events</c> CTE onto the time the event happened, while Darling's arms read the continuous
/// aggregate, which must bucket the hypertable's own <c>collection_time</c>. Pinned per arm, so the wrapper cannot
/// quietly vanish from Lite or appear in Darling.</para>
/// </summary>
[Fact]
public void TheTwoProducts_CarryTheSameEventBaselineBody_AndTheSameCollectors()
Expand Down Expand Up @@ -227,6 +234,8 @@ public void TheTwoProducts_CarryTheSameEventBaselineBody_AndTheSameCollectors()
Assert.Equal(aggregate, darlingCall.Events);
Assert.Equal("COUNT(*)", liteCall.Count);
Assert.Equal("SUM(event_count)", darlingCall.Count);
Assert.Equal(metric == "Blocking" ? "event_time" : "deadlock_time", liteCall.EventColumn);
Assert.Null(darlingCall.EventColumn);
}
}
}
Expand Down
Loading
Loading