feat(historian): QuestDb provider + Host wiring; conformance suite green on both backends
AtTime conformance stamps are the requested time (M3; identical on SQL Server). The QuestDB test fixture prunes idle pooled connections after 1 s: undisposed per-test data sources exhausted QuestDB's 64-connection PG-wire limit in a full run. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -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]
|
||||
|
||||
+11
-1
@@ -43,9 +43,19 @@ public sealed class QuestDbFixture : IAsyncLifetime
|
||||
/// <param name="retentionDays">Optional TTL.</param>
|
||||
/// <param name="autoCreate">AutoCreateSchema.</param>
|
||||
/// <returns>Valid options.</returns>
|
||||
/// <remarks>
|
||||
/// Pooled connections idle for more than a second are closed (<c>Connection Idle Lifetime</c> /
|
||||
/// <c>Connection Pruning Interval</c>). Many tests build their own <see cref="QuestDbConnection"/> (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.
|
||||
/// </remarks>
|
||||
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,
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user