11using ModularityKit . Mutator . Abstractions . Context ;
2+ using ModularityKit . Mutator . Governance . Abstractions . Exceptions ;
23using ModularityKit . Mutator . Governance . Abstractions . Lifecycle ;
34using ModularityKit . Mutator . Governance . Abstractions . Requests ;
45using ModularityKit . Mutator . Governance . Runtime . Storage ;
@@ -10,32 +11,61 @@ namespace ModularityKit.Mutator.Governance.Tests.Lifecycle;
1011public sealed class MutationRequestStoreContractTests
1112{
1213 [ Fact ]
13- public async Task Store_contract_allows_blind_overwrite_without_expected_revision_or_status ( )
14+ public async Task Create_contract_rejects_duplicate_request_ids ( )
1415 {
1516 var store = new InMemoryMutationRequestStore ( ) ;
1617 var request = MutationRequestTestFactory . CreatePendingRequest ( ) ;
1718
18- await store . Store ( request ) ;
19+ var created = await store . Create ( request ) ;
1920
20- var overwritten = request with
21+ var exception = await Assert . ThrowsAsync < MutationRequestAlreadyExistsException > ( ( ) =>
22+ store . Create ( created ) ) ;
23+
24+ Assert . Equal ( request . RequestId , exception . RequestId ) ;
25+ }
26+
27+ [ Fact ]
28+ public async Task TryStore_rejects_stale_revision_and_preserves_current_state ( )
29+ {
30+ var store = new InMemoryMutationRequestStore ( ) ;
31+ var request = MutationRequestTestFactory . CreatePendingRequest ( ) ;
32+ var created = await store . Create ( request ) ;
33+
34+ var firstUpdate = created with
35+ {
36+ Status = MutationRequestStatus . Approved ,
37+ PendingReason = null ,
38+ Decisions =
39+ [
40+ .. created . Decisions ,
41+ MutationRequestDecision . Create (
42+ MutationRequestDecisionType . Approved ,
43+ MutationContext . User ( "approver" , "Approver" , "Approve request" ) )
44+ ]
45+ } ;
46+
47+ var persisted = await store . TryStore ( firstUpdate , created . Revision ) ;
48+ Assert . NotNull ( persisted ) ;
49+
50+ var staleUpdate = created with
2151 {
2252 Status = MutationRequestStatus . Canceled ,
2353 PendingReason = null ,
2454 Decisions =
2555 [
26- .. request . Decisions ,
56+ .. created . Decisions ,
2757 MutationRequestDecision . Create (
2858 MutationRequestDecisionType . Canceled ,
29- MutationContext . User ( "operator" , "Operator" , "Canceled without guard " ) )
59+ MutationContext . User ( "operator" , "Operator" , "Cancel request " ) )
3060 ]
3161 } ;
3262
33- await store . Store ( overwritten ) ;
34-
63+ var rejected = await store . TryStore ( staleUpdate , created . Revision ) ;
3564 var loaded = await store . Get ( request . RequestId ) ;
3665
66+ Assert . Null ( rejected ) ;
3767 Assert . NotNull ( loaded ) ;
38- Assert . Equal ( MutationRequestStatus . Canceled , loaded . Status ) ;
39- Assert . Equal ( overwritten . Decisions . Count , loaded . Decisions . Count ) ;
68+ Assert . Equal ( MutationRequestStatus . Approved , loaded . Status ) ;
69+ Assert . Equal ( 1 , loaded . Revision ) ;
4070 }
4171}
0 commit comments