Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Darling/Darling.Tests/AvailabilityGroupCountReadTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public sealed class AvailabilityGroupCountReadTests
private static string? ConnectionString => Environment.GetEnvironmentVariable("DARLING_TEST_PG");

/// <summary>Plants TWO distinct AGs under one server, so a count/topology pair that "agree" by both
/// landing on 0 or both landing on 1 does not pass this — <see cref="DarlingAgReader.AvailabilityGroupCountSql"/>'s
/// landing on 0 or both landing on 1 does not pass this — <see cref="PerformanceMonitor.Darling.Storage.DarlingAgStatesReader.ReplicaGroupCountSql"/>'s
/// doc explains why the database grain and the ORDER BY the topology read carries cannot change the
/// number either read reports.</summary>
[Fact]
Expand Down
98 changes: 4 additions & 94 deletions Darling/Darling.Tests/DarlingAgReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -392,98 +392,8 @@ public void SerializedShape_CarriesTheFieldsBothConsumersRead()
JsonAssert.DoesNotContain("\"severity\": 3", json);
}

/* ─────────────────────────── SQL dialect pins ─────────────────────────── */

[Fact]
public void ReadSql_IsPostgresDialect_WithPositionalServerFilter()
{
foreach (var sql in new[] { Reader.ReplicaStatesSql, Reader.DatabaseReplicaStatesSql })
{
/* Positional params (Npgsql), never a named @param or an N'' literal. */
Assert.Contains("$1", sql, StringComparison.Ordinal);
Assert.DoesNotContain("@", sql, StringComparison.Ordinal);
Assert.DoesNotContain("N'", sql, StringComparison.Ordinal);

/* The filter guards BOTH the inner latest-instant aggregate and the outer read — count, don't just
Contains, or deleting either WHERE leaves this green. */
Assert.Equal(2, Occurrences(sql, "$1::integer IS NULL"));
}
}

private static int Occurrences(string haystack, string needle)
{
var count = 0;
for (var i = haystack.IndexOf(needle, StringComparison.Ordinal); i >= 0;
i = haystack.IndexOf(needle, i + needle.Length, StringComparison.Ordinal))
{
count++;
}

return count;
}

[Fact]
public void ReadSql_RestrictsToTheEnabledServerRegistry()
{
/* Every other fleet read joins the enabled registry; without it a server disabled in the control plane
keeps producing AG cards until its rows age out, after it has already left /api/fleet and the sidebar. */
foreach (var sql in new[] { Reader.ReplicaStatesSql, Reader.DatabaseReplicaStatesSql })
{
Assert.Contains("JOIN servers AS s", sql, StringComparison.Ordinal);
Assert.Contains("s.is_enabled", sql, StringComparison.Ordinal);
}
}

[Fact]
public void ReadSql_KeepsEveryRowAtEachServersNewestCollection()
{
/* DISTINCT ON would keep ONE row per server — which is exactly wrong here, since a snapshot is many rows
(one per replica / per database). The join against MAX(collection_time) keeps them all. */
foreach (var sql in new[] { Reader.ReplicaStatesSql, Reader.DatabaseReplicaStatesSql })
{
Assert.Contains("MAX(collection_time)", sql, StringComparison.Ordinal);
Assert.Contains("GROUP BY server_id", sql, StringComparison.Ordinal);
Assert.DoesNotContain("DISTINCT ON", sql, StringComparison.Ordinal);
}
}

[Fact]
public void ReadSql_SelectsIsLocalOnBothGrains()
{
/* V37 put is_local on the replica grain; V34 already had it on the database grain. Inserting it shifted
the replica read's ordinals, which is the classic silent mis-map. */
Assert.Contains("r.is_local", Reader.ReplicaStatesSql, StringComparison.Ordinal);
Assert.Contains("d.is_local", Reader.DatabaseReplicaStatesSql, StringComparison.Ordinal);
}

[Fact]
public void ReadSql_ReadsTheCollectQualifiedBaseTables()
{
/* Post-V14 collectors get no v_* passthrough view, so the readers name the base tables directly. */
Assert.Contains("FROM collect.ag_replica_states", Reader.ReplicaStatesSql, StringComparison.Ordinal);
Assert.Contains("FROM collect.ag_database_replica_states", Reader.DatabaseReplicaStatesSql, StringComparison.Ordinal);
}

[Fact]
public void ReadSql_SelectsEveryColumnTheDtoSurfaces()
{
foreach (var column in new[]
{
"role_desc", "operational_state_desc", "connected_state_desc", "recovery_health_desc",
"synchronization_health_desc", "availability_mode_desc", "failover_mode_desc", "endpoint_url",
})
{
Assert.Contains(column, Reader.ReplicaStatesSql, StringComparison.Ordinal);
}

foreach (var column in new[]
{
"synchronization_state_desc", "last_hardened_lsn", "last_commit_lsn", "log_send_queue_size",
"redo_queue_size", "log_send_rate", "redo_rate", "is_suspended", "suspend_reason_desc",
"secondary_lag_seconds", "is_local",
})
{
Assert.Contains(column, Reader.DatabaseReplicaStatesSql, StringComparison.Ordinal);
}
}
/* The SQL dialect/shape pins used to live here, against this reader's own copy of the statement text. That
copy moved to DarlingAgStatesReaderTests (#4228) along with the statement text itself — see
DarlingAgStatesReader in PerformanceMonitor.Darling.Storage, now the one implementation ReadReplicasAsync
and ReadDatabasesAsync above map into this file's ReplicaRow / DatabaseRow. */
}
Loading
Loading