refactor(dotnet): centralize runtime audit trail
This commit is contained in:
@@ -2,6 +2,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using QuantEngine.Application.Interfaces;
|
||||
using QuantEngine.Application.Services;
|
||||
using QuantEngine.Core.Domain;
|
||||
using QuantEngine.Core.Interfaces;
|
||||
@@ -15,39 +16,17 @@ public class FactorComputationServiceTests
|
||||
public async Task ComputeAndAppendFactorOutputs_WritesAuditAndHistory()
|
||||
{
|
||||
var storeMock = new Mock<IPostgresqlHistoryStore>();
|
||||
var auditTrailMock = new Mock<IRuntimeAuditTrailService>();
|
||||
storeMock.Setup(s => s.AppendAsync(It.IsAny<string>(), It.IsAny<IDictionary<string, object?>>()))
|
||||
.ReturnsAsync(1);
|
||||
|
||||
var history = new HistoryIngestionService(storeMock.Object);
|
||||
var service = new FactorComputationService(history);
|
||||
|
||||
var root = FindRepoRoot();
|
||||
var auditPath = Path.Combine(root, "Temp", "factor_audit", "005930.jsonl");
|
||||
if (File.Exists(auditPath))
|
||||
{
|
||||
File.Delete(auditPath);
|
||||
}
|
||||
var service = new FactorComputationService(history, auditTrailMock.Object);
|
||||
|
||||
var outputs = new FactorOutputs(1, 2, 3, 4, 5, 6, 7);
|
||||
await service.AppendFactorOutputsAsync("005930", "v1", outputs);
|
||||
|
||||
storeMock.Verify(s => s.AppendAsync("factor_output_history", It.IsAny<IDictionary<string, object?>>()), Times.Exactly(7));
|
||||
Assert.True(File.Exists(auditPath));
|
||||
Assert.Contains("PERSISTED", File.ReadAllText(auditPath));
|
||||
}
|
||||
|
||||
private static string FindRepoRoot()
|
||||
{
|
||||
var current = new DirectoryInfo(System.AppContext.BaseDirectory);
|
||||
while (current != null)
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(current.FullName, ".git")))
|
||||
{
|
||||
return current.FullName;
|
||||
}
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Repository root not found.");
|
||||
auditTrailMock.Verify(a => a.Append("factor_audit", "005930", It.IsAny<FactorComputationAudit>()), Times.Once);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ using Moq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using QuantEngine.Application.Interfaces;
|
||||
using QuantEngine.Application.Models;
|
||||
using QuantEngine.Core.Interfaces;
|
||||
using QuantEngine.Application.Services;
|
||||
|
||||
@@ -13,6 +15,7 @@ public class KisDataCollectionOrchestratorTests
|
||||
private readonly Mock<IKisApiClient> _kisApiClientMock;
|
||||
private readonly Mock<ICollectionRepository> _repositoryMock;
|
||||
private readonly Mock<ILogger<KisDataCollectionOrchestrator>> _loggerMock;
|
||||
private readonly Mock<IRuntimeAuditTrailService> _auditTrailMock;
|
||||
private readonly PriceDataNormalizer _normalizer;
|
||||
private readonly SourcePriorityResolver _priorityResolver;
|
||||
private readonly KisDataCollectionOrchestrator _orchestrator;
|
||||
@@ -22,6 +25,7 @@ public class KisDataCollectionOrchestratorTests
|
||||
_kisApiClientMock = new Mock<IKisApiClient>();
|
||||
_repositoryMock = new Mock<ICollectionRepository>();
|
||||
_loggerMock = new Mock<ILogger<KisDataCollectionOrchestrator>>();
|
||||
_auditTrailMock = new Mock<IRuntimeAuditTrailService>();
|
||||
_priorityResolver = new SourcePriorityResolver();
|
||||
_normalizer = new PriceDataNormalizer(_priorityResolver);
|
||||
|
||||
@@ -30,7 +34,8 @@ public class KisDataCollectionOrchestratorTests
|
||||
_repositoryMock.Object,
|
||||
_normalizer,
|
||||
_priorityResolver,
|
||||
_loggerMock.Object
|
||||
_loggerMock.Object,
|
||||
_auditTrailMock.Object
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,12 +98,6 @@ public class KisDataCollectionOrchestratorTests
|
||||
var runId = "test-run-002";
|
||||
var ticker = "005930";
|
||||
var account = "mock";
|
||||
var auditPath = Path.Combine(FindRepoRoot(), "Temp", "collection_audit", $"{runId}.jsonl");
|
||||
if (File.Exists(auditPath))
|
||||
{
|
||||
File.Delete(auditPath);
|
||||
}
|
||||
|
||||
_repositoryMock
|
||||
.Setup(r => r.GetLatestSnapshotsForTickerAsync(ticker, It.IsAny<int>()))
|
||||
.ReturnsAsync(new List<CollectionSnapshotRecord>());
|
||||
@@ -133,8 +132,7 @@ public class KisDataCollectionOrchestratorTests
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("COMPLETED", result.Status);
|
||||
Assert.Equal(1, result.SuccessCount);
|
||||
Assert.True(File.Exists(auditPath));
|
||||
Assert.Contains("COMPLETED", File.ReadAllText(auditPath));
|
||||
_auditTrailMock.Verify(a => a.Append("collection_audit", runId, It.IsAny<CollectionExecutionAudit>()), Times.Exactly(2));
|
||||
|
||||
_kisApiClientMock.Verify(
|
||||
k => k.GetCurrentPriceAsync(ticker, account),
|
||||
|
||||
Reference in New Issue
Block a user