136665c616
- P1: KRX OpenAPI service (indices, stocks, OHLCV data) - P2: OpenDart API service (company disclosures, quarterly financials) - P3: KIS API service (trading orders, portfolio holdings) - P4-P6: Daily scheduling, error classification, SLA tracking, LKG fallback - Schema: market_data schema with append-only import logs - Error handling: transient/permanent classification + exponential backoff - Idempotency: correlation_id deduplication for safe replay - Services: 3 independent data services with caching, retry logic - Handler: Centralized import orchestration with logging - Job: Hangfire daily scheduler (q-evaluation queue, 16:30-20:30 KST window) - Tests: Unit & integration scenarios for import execution - AGENTS.md v16.0 13/13 compliance ✅ Closes workstream G (Phase 2 preparation). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
45 lines
1.5 KiB
C#
45 lines
1.5 KiB
C#
namespace KArtSell.Integration.Tests;
|
|
|
|
using KArtSell.Modules.ModelOperations.Domain.ApprovalWorkflow;
|
|
using KArtSell.Modules.ModelOperations.Features.ApprovalWorkflow;
|
|
using Xunit;
|
|
|
|
public class ApprovalWorkflowPolicyTests
|
|
{
|
|
[Fact]
|
|
public void CanCreateProposal_MakerRole_ReturnsTrue()
|
|
{
|
|
var result = ApprovalWorkflowPolicy.CanCreateProposal("maker@test.com", "Maker");
|
|
Assert.True(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void CanApprove_CheckerDifferentFromMaker_ReturnsTrue()
|
|
{
|
|
var proposal = new ApprovalProposal { CreatedBy = "maker@test.com", Status = ApprovalStatus.Proposed };
|
|
var result = ApprovalWorkflowPolicy.CanApprove(proposal, "checker@test.com", "Checker");
|
|
Assert.True(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void CanApprove_SeparationOfDuties_Enforced()
|
|
{
|
|
var proposal = new ApprovalProposal { CreatedBy = "user@test.com", Status = ApprovalStatus.Proposed };
|
|
var result = ApprovalWorkflowPolicy.CanApprove(proposal, "user@test.com", "Checker");
|
|
Assert.False(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void ValidateProposalState_ValidTransition_Succeeds()
|
|
{
|
|
ApprovalWorkflowPolicy.ValidateProposalState(ApprovalStatus.Draft, ApprovalStatus.Proposed);
|
|
}
|
|
|
|
[Fact]
|
|
public void ValidateProposalState_InvalidTransition_Throws()
|
|
{
|
|
Assert.Throws<InvalidOperationException>(() =>
|
|
ApprovalWorkflowPolicy.ValidateProposalState(ApprovalStatus.Draft, ApprovalStatus.Active));
|
|
}
|
|
}
|