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