summaryrefslogtreecommitdiff
path: root/tests/FundLab.Api.Tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests/FundLab.Api.Tests')
-rw-r--r--tests/FundLab.Api.Tests/OrderTests.fs130
1 files changed, 130 insertions, 0 deletions
diff --git a/tests/FundLab.Api.Tests/OrderTests.fs b/tests/FundLab.Api.Tests/OrderTests.fs
index 4fc1da0..1ab8fb8 100644
--- a/tests/FundLab.Api.Tests/OrderTests.fs
+++ b/tests/FundLab.Api.Tests/OrderTests.fs
@@ -1880,3 +1880,133 @@ type RedemptionTests(fixture: PostgresFixture) =
Assert.Contains("\"instrumentCode\":\"" + code + "\"", listResponse)
Assert.Contains("\"status\":\"confirmed\"", listResponse)
Assert.Contains("\"confirmedProceeds\":\"99.60\"", listResponse)
+
+[<Collection("postgres")>]
+type CapitalDepositTests(fixture: PostgresFixture) =
+ let sharedRepository =
+ lazy
+ let value = FundRepository(fixture.ConnectionString)
+ value.EnsureSchema()
+ value
+
+ let repository () = sharedRepository.Value
+
+ let createFund (initialCash: decimal) =
+ let command =
+ {
+ Name = "追加资金测试 FOF"
+ InitialCash = initialCash
+ InitialUnitNav = 1.00000000m
+ IsSynthetic = true
+ }
+
+ let key = fixture.Key(sprintf "capital-fund-%s" (Guid.NewGuid().ToString("N")))
+
+ match repository().CreateFund(key, command) with
+ | FundWriteResult.Created fund -> fund.Id
+ | other -> failwithf "unexpected fund creation result: %A" other
+
+ let app () = App.createApplication (repository ())
+
+ let postDeposit (fundId: Guid) (idempotencyKey: string) (amount: string) (note: string) =
+ let body = sprintf "{\"amount\":\"%s\",\"note\":\"%s\"}" amount note
+
+ PersistenceTestHelpers.invoke
+ (app ())
+ "POST"
+ (sprintf "/api/funds/%O/capital/deposit" fundId)
+ [
+ "Authorization", "Bearer test-token"
+ "Idempotency-Key", idempotencyKey
+ ]
+ body
+
+ let availableCash fundId =
+ use connection = new NpgsqlConnection(fixture.ConnectionString)
+ connection.Open()
+ use command = connection.CreateCommand()
+ command.CommandText <- "SELECT available_cash FROM funds WHERE id = @fund_id"
+ let parameter = command.Parameters.Add("fund_id", NpgsqlTypes.NpgsqlDbType.Uuid)
+ parameter.Value <- box fundId
+ command.ExecuteScalar() :?> decimal
+
+ let depositCount fundId =
+ use connection = new NpgsqlConnection(fixture.ConnectionString)
+ connection.Open()
+ use command = connection.CreateCommand()
+ command.CommandText <- "SELECT count(*) FROM fund_capital_deposits WHERE fund_id = @fund_id"
+ let parameter = command.Parameters.Add("fund_id", NpgsqlTypes.NpgsqlDbType.Uuid)
+ parameter.Value <- box fundId
+ command.ExecuteScalar() :?> int64
+
+ [<Fact>]
+ member _.``capital deposit credits available cash and records the deposit``() =
+ let fundId = createFund 10000.00m
+ let key = fixture.Key(sprintf "cap-%s" (Guid.NewGuid().ToString("N")))
+
+ let status, response = postDeposit fundId key "500.00" "首次追加"
+
+ Assert.Equal(201, status)
+ Assert.Contains("\"amount\":\"500.00\"", response)
+ Assert.Equal(10500.00m, availableCash fundId)
+ Assert.Equal(1L, depositCount fundId)
+
+ [<Fact>]
+ member _.``capital deposit replay with the same key credits cash exactly once``() =
+ let fundId = createFund 10000.00m
+ let key = fixture.Key(sprintf "cap-%s" (Guid.NewGuid().ToString("N")))
+
+ let firstStatus, firstResponse = postDeposit fundId key "300.00" "重复追加"
+ let secondStatus, secondResponse = postDeposit fundId key "300.00" "重复追加"
+
+ Assert.Equal(201, firstStatus)
+ Assert.Equal(200, secondStatus)
+ Assert.Equal(firstResponse, secondResponse)
+ Assert.Equal(10300.00m, availableCash fundId)
+ Assert.Equal(1L, depositCount fundId)
+
+ let conflictingStatus, conflictingResponse = postDeposit fundId key "100.00" "不同金额"
+
+ Assert.Equal(409, conflictingStatus)
+ Assert.Contains("IDEMPOTENCY_CONFLICT", conflictingResponse)
+ Assert.Equal(10300.00m, availableCash fundId)
+
+ [<Fact>]
+ member _.``invalid deposit amounts are rejected without any cash movement``() =
+ let fundId = createFund 10000.00m
+
+ for amount in [ "0.00"; "-5.00"; "1.234" ] do
+ let key = fixture.Key(sprintf "cap-%s" (Guid.NewGuid().ToString("N")))
+ let status, response = postDeposit fundId key amount "非法"
+ Assert.Equal(400, status)
+ Assert.Contains("INVALID_CAPITAL_REQUEST", response)
+
+ Assert.Equal(10000.00m, availableCash fundId)
+ Assert.Equal(0L, depositCount fundId)
+
+ [<Fact>]
+ member _.``deposit for an unknown fund returns 404``() =
+ let key = fixture.Key(sprintf "cap-%s" (Guid.NewGuid().ToString("N")))
+ let status, response = postDeposit (Guid.NewGuid()) key "100.00" "无基金"
+
+ Assert.Equal(404, status)
+ Assert.Contains("FUND_NOT_FOUND", response)
+
+ [<Fact>]
+ member _.``deposit history is exposed via GET``() =
+ let fundId = createFund 10000.00m
+ let _, _ = postDeposit fundId (fixture.Key(sprintf "cap-%s" (Guid.NewGuid().ToString("N")))) "111.00" "第一笔"
+ let _, _ = postDeposit fundId (fixture.Key(sprintf "cap-%s" (Guid.NewGuid().ToString("N")))) "222.00" "第二笔"
+
+ let status, response =
+ PersistenceTestHelpers.invoke
+ (app ())
+ "GET"
+ (sprintf "/api/funds/%O/capital/deposits" fundId)
+ [ "Authorization", "Bearer test-token" ]
+ ""
+
+ Assert.Equal(200, status)
+ Assert.Contains("\"amount\":\"111.00\"", response)
+ Assert.Contains("\"amount\":\"222.00\"", response)
+ Assert.Contains("第一笔", response)