summaryrefslogtreecommitdiff
path: root/tests/FundLab.Api.Tests/OrderTests.fs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/FundLab.Api.Tests/OrderTests.fs')
-rw-r--r--tests/FundLab.Api.Tests/OrderTests.fs85
1 files changed, 80 insertions, 5 deletions
diff --git a/tests/FundLab.Api.Tests/OrderTests.fs b/tests/FundLab.Api.Tests/OrderTests.fs
index 5e6771c..d1f57df 100644
--- a/tests/FundLab.Api.Tests/OrderTests.fs
+++ b/tests/FundLab.Api.Tests/OrderTests.fs
@@ -6,6 +6,7 @@ open System.Net.Http
open System.Text.Json
open System.Threading.Tasks
open FundLab.Api
+open Npgsql
open Xunit
[<Collection("postgres")>]
@@ -167,7 +168,7 @@ type OrderTests(fixture: PostgresFixture) =
orderBody code "0.00" "1.00"
orderBody code "-5.00" "1.00"
orderBody code "10.005" "1.00"
- orderBody code "10.00" "0.00"
+ orderBody code "10.00" "-0.01"
orderBody code "10.00" "1.005"
"{\"amount\":\"10.00\",\"feeAmount\":\"1.00\"}"
"{\"fundCode\":123,\"amount\":\"10.00\",\"feeAmount\":\"1.00\"}"
@@ -189,14 +190,14 @@ type OrderTests(fixture: PostgresFixture) =
Assert.Equal(0, orderCount listBody)
let boundaryStatus, boundaryBody =
- postOrder api fundId key (orderBody code "0.01" "0.01")
+ postOrder api fundId key (orderBody code "0.01" "0.00")
Assert.Equal(201, boundaryStatus)
- Assert.Contains("\"reservedTotal\":\"0.02\"", boundaryBody)
+ Assert.Contains("\"reservedTotal\":\"0.01\"", boundaryBody)
let _, fundAfterBoundary = getFund api fundId
- Assert.Contains("\"availableCash\":\"999.98\"", fundAfterBoundary)
- Assert.Contains("\"reservedCash\":\"0.02\"", fundAfterBoundary)
+ Assert.Contains("\"availableCash\":\"999.99\"", fundAfterBoundary)
+ Assert.Contains("\"reservedCash\":\"0.01\"", fundAfterBoundary)
[<Fact>]
member _.``subscription order requires authentication and an idempotency key``() =
@@ -398,3 +399,77 @@ type OrderTests(fixture: PostgresFixture) =
Assert.Equal(200, replayStatus)
Assert.Equal(orderId, PersistenceTestHelpers.responseId replayResponse)
+
+ [<Fact>]
+ member _.``zero fee subscription order is accepted and replays``() =
+ let code = seedInstrument ()
+ let fundId = createFund 200.00m
+ let api = app ()
+ let key = fixture.Key("order-zero-fee")
+
+ let status, body =
+ postOrder api fundId key (orderBody code "50.00" "0.00")
+
+ Assert.Equal(201, status)
+ Assert.Contains("\"amount\":\"50.00\"", body)
+ Assert.Contains("\"feeAmount\":\"0.00\"", body)
+ Assert.Contains("\"reservedTotal\":\"50.00\"", body)
+ Assert.Contains("\"status\":\"submitted\"", body)
+ let orderId = PersistenceTestHelpers.responseId body
+
+ let replayStatus, replayBody = postOrder api fundId key (orderBody code "50.00" "0.00")
+ Assert.Equal(200, replayStatus)
+ Assert.Equal(orderId, PersistenceTestHelpers.responseId replayBody)
+
+ let _, fundBody = getFund api fundId
+ Assert.Contains("\"availableCash\":\"150.00\"", fundBody)
+ Assert.Contains("\"reservedCash\":\"50.00\"", fundBody)
+
+ let _, listBody = getOrderList api fundId
+ Assert.Equal(1, orderCount listBody)
+
+ [<Fact>]
+ member _.``database constraint rejects negative fee but allows exact zero fee``() =
+ let code = seedInstrument ()
+ let fundId = createFund 100.00m
+ repository () |> ignore
+
+ use connection = new NpgsqlConnection(fixture.ConnectionString)
+ connection.Open()
+
+ let insertOrder (fee: decimal) (reservedTotal: decimal) =
+ use command = connection.CreateCommand()
+ command.CommandText <-
+ """
+ INSERT INTO subscription_orders
+ (id, fund_id, fund_code, amount, fee_amount, reserved_total, status, is_synthetic)
+ VALUES
+ (@id, @fund_id, @fund_code, @amount, @fee_amount, @reserved_total, 'submitted', true)
+ """
+
+ command.Parameters.Add("id", NpgsqlTypes.NpgsqlDbType.Uuid).Value <- box (Guid.NewGuid())
+ command.Parameters.Add("fund_id", NpgsqlTypes.NpgsqlDbType.Uuid).Value <- box fundId
+ command.Parameters.Add("fund_code", NpgsqlTypes.NpgsqlDbType.Text).Value <- box code
+ command.Parameters.Add("amount", NpgsqlTypes.NpgsqlDbType.Numeric).Value <- box 10.00m
+ command.Parameters.Add("fee_amount", NpgsqlTypes.NpgsqlDbType.Numeric).Value <- box fee
+ command.Parameters.Add("reserved_total", NpgsqlTypes.NpgsqlDbType.Numeric).Value <- box reservedTotal
+ command.ExecuteNonQuery() |> ignore
+
+ Assert.Throws<Npgsql.PostgresException>(fun () -> insertOrder -1.00m 9.00m) |> ignore
+
+ insertOrder 0.00m 10.00m
+
+ let negativeCount =
+ PersistenceTestHelpers.queryCount
+ fixture.ConnectionString
+ "SELECT count(*) FROM subscription_orders WHERE fund_id = @fund_id AND fee_amount < 0"
+ [ "fund_id", box fundId, NpgsqlTypes.NpgsqlDbType.Uuid ]
+
+ let zeroCount =
+ PersistenceTestHelpers.queryCount
+ fixture.ConnectionString
+ "SELECT count(*) FROM subscription_orders WHERE fund_id = @fund_id AND fee_amount = 0"
+ [ "fund_id", box fundId, NpgsqlTypes.NpgsqlDbType.Uuid ]
+
+ Assert.Equal(0L, negativeCount)
+ Assert.Equal(1L, zeroCount)