diff --git a/tests/Drivers/Historian.Conformance/AtTimeConformance.cs b/tests/Drivers/Historian.Conformance/AtTimeConformance.cs index 8a2acea7..2f8a9341 100644 --- a/tests/Drivers/Historian.Conformance/AtTimeConformance.cs +++ b/tests/Drivers/Historian.Conformance/AtTimeConformance.cs @@ -35,7 +35,7 @@ public abstract class AtTimeConformance : ConformanceBase var s = (await B.CreateDataSource().ReadAtTimeAsync("A", [At(10), At(20)], Ct)).Samples; s[0].Value.ShouldBe(20d); s[0].StatusCode.ShouldBe(0u); - s[0].SourceTimestampUtc.ShouldBe(B.Round(At(10))); + s[0].SourceTimestampUtc.ShouldBe(At(10)); // the requested time itself, never rounded (M3) s[0].ServerTimestampUtc.ShouldBe(B.Round(At(11))); // the stored ServerTimeUtc s[1].Value.ShouldBe(30d); // a stored Bad sample comes back as stored s[1].StatusCode.ShouldBe(0x80000000u); @@ -50,7 +50,7 @@ public abstract class AtTimeConformance : ConformanceBase s[1].Value.ShouldBe(12.5d); // 10 + 10 * 2.5/10 s[2].Value.ShouldBe(42.5d); // 40 + 10 * 2.5/10 s.ShouldAllBe(x => x.StatusCode == GoodInterpolated); - s[0].SourceTimestampUtc.ShouldBe(B.Round(At(5))); // stamped at the requested (sub-ms) time + s[0].SourceTimestampUtc.ShouldBe(At(5)); // stamped at the requested (sub-µs) time itself, never rounded (M3) } [Fact] @@ -61,7 +61,7 @@ public abstract class AtTimeConformance : ConformanceBase var s = (await B.CreateDataSource().ReadAtTimeAsync("A", [before], Ct)).Samples.Single(); s.Value.ShouldBeNull(); s.StatusCode.ShouldBe(BadNoData); - s.SourceTimestampUtc.ShouldBe(B.Round(before)); + s.SourceTimestampUtc.ShouldBe(before); } [Fact] @@ -80,7 +80,7 @@ public abstract class AtTimeConformance : ConformanceBase var s = (await B.CreateDataSource().ReadAtTimeAsync("A", [At(25)], Ct)).Samples.Single(); s.Value.ShouldBeNull(); // NOT 35 (30→40) and NOT 30 (a Bad value) s.StatusCode.ShouldBe(0x80000000u); // the previous sample's Bad code — never upgraded to Uncertain - s.SourceTimestampUtc.ShouldBe(B.Round(At(25))); + s.SourceTimestampUtc.ShouldBe(At(25)); } [Fact] @@ -173,7 +173,7 @@ public abstract class AtTimeConformance : ConformanceBase var s = (await B.CreateDataSource().ReadAtTimeAsync("A", [At(5), At(-1), At(5), At(10)], Ct)).Samples; s.Count.ShouldBe(4); s.Select(x => x.Value).ShouldBe([15d, null, 15d, 20d]); - s.Select(x => x.SourceTimestampUtc).ShouldBe([B.Round(At(5)), B.Round(At(-1)), B.Round(At(5)), B.Round(At(10))]); + s.Select(x => x.SourceTimestampUtc).ShouldBe([At(5), At(-1), At(5), At(10)]); } [Fact] diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.IntegrationTests/QuestDbFixture.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.IntegrationTests/QuestDbFixture.cs index dcaba660..4d9d0877 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.IntegrationTests/QuestDbFixture.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.IntegrationTests/QuestDbFixture.cs @@ -43,9 +43,19 @@ public sealed class QuestDbFixture : IAsyncLifetime /// Optional TTL. /// AutoCreateSchema. /// Valid options. + /// + /// Pooled connections idle for more than a second are closed (Connection Idle Lifetime / + /// Connection Pruning Interval). Many tests build their own (one Npgsql + /// data source each) and never dispose it; with Npgsql's default 300 s idle lifetime their pooled connections + /// piled up until QuestDB's PG-wire limit (64) was reached and later tests' opens timed out after 15 s. + /// public QuestDbHistorianOptions Options(string prefix, int? retentionDays = null, bool autoCreate = true) => new() { - ConnectionString = ConnectionString, + ConnectionString = new NpgsqlConnectionStringBuilder(ConnectionString) + { + ConnectionIdleLifetime = 1, + ConnectionPruningInterval = 1, + }.ConnectionString, TablePrefix = prefix, RetentionDays = retentionDays, AutoCreateSchema = autoCreate, diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.IntegrationTests/ReadTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.IntegrationTests/ReadTests.cs index d0f29d5a..6345613b 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.IntegrationTests/ReadTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.QuestDb.IntegrationTests/ReadTests.cs @@ -184,7 +184,7 @@ public sealed class ReadTests(QuestDbFixture fx) : IAsyncLifetime times.Add(times[0]); var s = (await _b.CreateDataSource().ReadAtTimeAsync("A", times, Ct)).Samples; s.Count.ShouldBe(times.Count); - s.Select(x => x.SourceTimestampUtc).ShouldBe(times.Select(t => (DateTime?)_b.Round(t))); + s.Select(x => x.SourceTimestampUtc).ShouldBe(times.Select(t => (DateTime?)t)); // the requested times (M3) s[0].Value.ShouldBe(49d); // +39: 40 + 10 × 9/10 s[0].StatusCode.ShouldBe(GoodInterpolated); s[^1].Value.ShouldBe(49d); // the duplicate