94 lines
3.4 KiB
C#
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());
|
|
}
|
|
}
|
|
}
|