test(sql): live SQL Server gate for the row cap (R06:S-1)
An events table with 40 rows for one where-pair selector: the capped SELECT TOP (2) runs as real T-SQL, the ambiguous tag publishes BadConfigurationError, a single-row station reads Good through the same statement, and the driver stays Healthy. Live run 2026-10-22: SQL Server 22/22, Postgres 7/7 and Oracle 6/6 (LIMIT n / FETCH FIRST n ROWS ONLY after WHERE) all green on 10.100.0.35. Refs #744 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -58,6 +58,64 @@ public sealed class SqlServerReadTests
|
||||
driver.GetHostStatuses().ShouldHaveSingleItem().State.ShouldBe(HostState.Running);
|
||||
}
|
||||
|
||||
// ---- R06:S-1: the row cap, on real T-SQL ----
|
||||
|
||||
/// <summary>
|
||||
/// A where-pair selector pointed at an events table (40 rows for one station) used to pull every
|
||||
/// matching row on every poll. The plan now emits <c>SELECT TOP (2) …</c> — proven valid T-SQL here —
|
||||
/// and the second row makes the tag publish <c>BadConfigurationError</c> while the driver stays
|
||||
/// Healthy (the server answered). The positive control: a station with exactly one row reads Good
|
||||
/// through the same capped statement.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ReadAsync_realSqlServer_anAmbiguousSelectorIsRowCappedToAConfigurationError()
|
||||
{
|
||||
SkipUnlessLive();
|
||||
const string table = "RowCapEvents";
|
||||
|
||||
await using (var arrange = await _sql.OpenInspectionConnectionAsync())
|
||||
{
|
||||
await using var command = arrange.CreateCommand();
|
||||
command.CommandText = string.Create(CultureInfo.InvariantCulture, $"""
|
||||
IF OBJECT_ID(N'{SqlPollServerFixture.Schema}.{table}') IS NOT NULL DROP TABLE {SqlPollServerFixture.Schema}.{table};
|
||||
CREATE TABLE {SqlPollServerFixture.Schema}.{table} (
|
||||
{SqlPollServerFixture.WideRowSelectorColumn} int NOT NULL,
|
||||
oven_temp float NULL,
|
||||
{SqlPollServerFixture.TimestampColumn} datetime2 NOT NULL);
|
||||
INSERT INTO {SqlPollServerFixture.Schema}.{table} VALUES (1, 21.5, '2026-07-24T10:00:00');
|
||||
DECLARE @i int = 0;
|
||||
WHILE @i < 40
|
||||
BEGIN
|
||||
INSERT INTO {SqlPollServerFixture.Schema}.{table} VALUES (7, @i, DATEADD(second, @i, '2026-07-24T10:00:00'));
|
||||
SET @i += 1;
|
||||
END
|
||||
""");
|
||||
await command.ExecuteNonQueryAsync(TestContext.Current.CancellationToken);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await using var driver = await StartAsync(
|
||||
WideRowWhere("Sql/Events/Ambiguous", "oven_temp", "7", table),
|
||||
WideRowWhere("Sql/Events/Clean", "oven_temp", "1", table));
|
||||
|
||||
var snapshots = await driver.ReadAsync(
|
||||
["Sql/Events/Ambiguous", "Sql/Events/Clean"], TestContext.Current.CancellationToken);
|
||||
|
||||
snapshots[0].StatusCode.ShouldBe(SqlStatusCodes.BadConfigurationError);
|
||||
snapshots[1].StatusCode.ShouldBe(SqlStatusCodes.Good);
|
||||
Convert.ToDouble(snapshots[1].Value).ShouldBe(21.5);
|
||||
driver.GetHealth().State.ShouldBe(DriverState.Healthy);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await using var cleanup = await _sql.OpenInspectionConnectionAsync();
|
||||
await using var drop = cleanup.CreateCommand();
|
||||
drop.CommandText = $"DROP TABLE IF EXISTS {SqlPollServerFixture.Schema}.{table}";
|
||||
await drop.ExecuteNonQueryAsync(CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- key-value model ----
|
||||
|
||||
/// <summary>The plan's headline case: a seeded key-value row round-trips as a Good snapshot.</summary>
|
||||
|
||||
Reference in New Issue
Block a user