Files
QuantEngineByItz/src/dotnet/QuantEngine.Core.Tests/HistoryIngestionE2ETests.cs
T
2026-06-26 18:06:36 +09:00

94 lines
3.4 KiB
C#

using QuantEngine.Application.Services;
using QuantEngine.Core.Interfaces;
namespace QuantEngine.Core.Tests;
public class HistoryIngestionE2ETests
{
[Fact]
public async Task AppendDecisionThenReadSnapshotRoundTripsThroughApplicationFlow()
{
var store = new FakeHistoryStore();
var ingestion = new HistoryIngestionService(store);
var reader = new PostgresqlHistorySnapshotReader(store);
var appendCount = await ingestion.AppendDecisionAsync(new Dictionary<string, object?>
{
["decision_id"] = "dec-001",
["decided_at"] = DateTimeOffset.Parse("2026-06-26T09:00:00+09:00"),
["instrument_id"] = "005930",
["action"] = "BUY",
["gate"] = "PASS",
["score"] = 87.5,
["source_version"] = "v1",
["provenance"] = new Dictionary<string, object?>
{
["source"] = "unit-test"
}
});
Assert.Equal(1, appendCount);
var rows = await reader.ReadAsync("decision_result_history", 10);
Assert.Single(rows);
Assert.Equal("dec-001", rows[0]["decision_id"]);
Assert.Equal("005930", rows[0]["instrument_id"]);
Assert.Equal("BUY", rows[0]["action"]);
Assert.Equal("PASS", rows[0]["gate"]);
Assert.Equal(87.5, rows[0]["score"]);
}
[Fact]
public async Task AppendFactorOutputThenReadSnapshotPreservesPayload()
{
var store = new FakeHistoryStore();
var ingestion = new HistoryIngestionService(store);
var reader = new PostgresqlHistorySnapshotReader(store);
var appendCount = await ingestion.AppendFactorOutputAsync(
factorId: "RS_VERDICT_V2",
factorVersion: "2026-06-26",
outputValue: 1.23,
outputGate: "PASS",
sourceVersion: "source-42",
observedAt: DateTimeOffset.Parse("2026-06-26T10:00:00+09:00"));
Assert.Equal(1, appendCount);
var rows = await reader.ReadAsync("factor_output_history", 10);
Assert.Single(rows);
Assert.Equal("RS_VERDICT_V2", rows[0]["factor_id"]);
Assert.Equal("2026-06-26", rows[0]["factor_version"]);
Assert.Equal(1.23, rows[0]["output_value"]);
Assert.Equal("PASS", rows[0]["output_gate"]);
Assert.Equal("source-42", rows[0]["source_version"]);
}
private sealed class FakeHistoryStore : IPostgresqlHistoryStore
{
private readonly Dictionary<string, List<IDictionary<string, object?>>> _rows = new();
public Task<int> AppendAsync(string domain, IDictionary<string, object?> payload)
{
if (!_rows.TryGetValue(domain, out var list))
{
list = new List<IDictionary<string, object?>>();
_rows[domain] = list;
}
list.Add(new Dictionary<string, object?>(payload));
return Task.FromResult(1);
}
public Task<IReadOnlyList<IDictionary<string, object?>>> SnapshotAsync(string domain, int limit = 500)
{
if (!_rows.TryGetValue(domain, out var list))
{
return Task.FromResult<IReadOnlyList<IDictionary<string, object?>>>(Array.Empty<IDictionary<string, object?>>());
}
return Task.FromResult<IReadOnlyList<IDictionary<string, object?>>>(list.Take(limit).ToList());
}
}
}