|
2 | 2 |
|
3 | 3 | open System
|
4 | 4 |
|
| 5 | +open FSharp.AWS.DynamoDB.Tests |
5 | 6 | open Swensen.Unquote
|
6 | 7 | open Xunit
|
7 | 8 |
|
@@ -125,22 +126,102 @@ type ``Simple Table Operation Tests`` (fixture : TableFixture) =
|
125 | 126 | test <@ None = deletedItem @>
|
126 | 127 | test <@ not (table.ContainsKey key) @>
|
127 | 128 |
|
| 129 | + interface IClassFixture<TableFixture> |
| 130 | + |
| 131 | +type TransactWriteItems(fixture : TableFixture) = |
| 132 | + |
| 133 | + let rand = let r = Random() in fun () -> int64 <| r.Next() |
| 134 | + let mkItem() = |
| 135 | + { |
| 136 | + HashKey = guid() ; RangeKey = guid() ; |
| 137 | + Value = rand() ; Tuple = rand(), rand() ; |
| 138 | + Map = seq { for _ in 0L .. rand() % 5L -> "K" + guid(), rand() } |> Map.ofSeq |
| 139 | + Unions = [Choice1Of3 (guid()) ; Choice2Of3(rand()) ; Choice3Of3(Guid.NewGuid().ToByteArray())] |
| 140 | + } |
| 141 | + |
| 142 | + let table = fixture.CreateEmpty<SimpleRecord>() |
| 143 | + let compile = table.Template.PrecomputeConditionalExpr |
| 144 | + let compileUpdate (e : Quotations.Expr<SimpleRecord -> SimpleRecord>) = table.Template.PrecomputeUpdateExpr e |
| 145 | + let doesntExistCondition = compile <@ fun t -> NOT_EXISTS t.Value @> |
| 146 | + let existsCondition = compile <@ fun t -> EXISTS t.Value @> |
| 147 | + |
| 148 | + let [<Fact>] ``Minimal happy path`` () = async { |
| 149 | + let item = mkItem () |
| 150 | + |
| 151 | + let requests = [TransactWrite.Put (item, Some doesntExistCondition) ] |
| 152 | + |
| 153 | + do! table.TransactWriteItems requests |
| 154 | + |
| 155 | + let! itemFound = table.ContainsKeyAsync (table.Template.ExtractKey item) |
| 156 | + true =! itemFound } |
| 157 | + |
| 158 | + let [<Fact>] ``Minimal Canceled path`` () = async { |
| 159 | + let item = mkItem () |
| 160 | + |
| 161 | + let requests = [TransactWrite.Put (item, Some existsCondition) ] |
| 162 | + |
| 163 | + let mutable failed = false |
| 164 | + try do! table.TransactWriteItems requests |
| 165 | + with TransactWriteItemsRequest.TransactionCanceledConditionalCheckFailed -> failed <- true |
| 166 | + |
| 167 | + true =! failed |
| 168 | + |
| 169 | + let! itemFound = table.ContainsKeyAsync (table.Template.ExtractKey item) |
| 170 | + false =! itemFound } |
| 171 | + |
128 | 172 | let [<Theory; InlineData true; InlineData false>]
|
129 | 173 | ``Condition Check outcome should affect sibling TransactWrite`` shouldFail = async {
|
130 | 174 | let item, item2 = mkItem (), mkItem ()
|
131 |
| - let key = table.PutItem item |
| 175 | + let! key = table.PutItemAsync item |
132 | 176 |
|
133 | 177 | let requests = [
|
134 |
| - if shouldFail then TransactWrite.Check (key, table.Template.PrecomputeConditionalExpr <@ fun t -> NOT_EXISTS t.Value @>) |
135 |
| - else TransactWrite.Check (key, table.Template.PrecomputeConditionalExpr <@ fun t -> EXISTS t.Value @>) |
| 178 | + if shouldFail then TransactWrite.Check (key, doesntExistCondition) |
| 179 | + else TransactWrite.Check (key, existsCondition) |
136 | 180 | TransactWrite.Put (item2, None) ]
|
137 | 181 | let mutable failed = false
|
138 | 182 | try do! table.TransactWriteItems requests
|
139 | 183 | with TransactWriteItemsRequest.TransactionCanceledConditionalCheckFailed -> failed <- true
|
140 | 184 |
|
141 |
| - let failed = failed |
142 |
| - test <@ failed = shouldFail @> |
143 |
| - let item2Found = table.ContainsKey (table.Template.ExtractKey item2) |
144 |
| - test <@ not shouldFail = item2Found @> } |
| 185 | + failed =! shouldFail |
| 186 | + |
| 187 | + let! item2Found = table.ContainsKeyAsync (table.Template.ExtractKey item2) |
| 188 | + failed =! not item2Found } |
| 189 | + |
| 190 | + let [<Theory; InlineData true; InlineData false>] |
| 191 | + ``All paths`` shouldFail = async { |
| 192 | + let item, item2, item3, item4, item5, item6, item7 = mkItem (), mkItem (), mkItem (), mkItem (), mkItem (), mkItem (), mkItem () |
| 193 | + let! key = table.PutItemAsync item |
| 194 | + |
| 195 | + let requests = [ TransactWrite.Update (key, Some existsCondition, compileUpdate <@ fun t -> { t with Value = 42 } @>) |
| 196 | + TransactWrite.Put (item2, None) |
| 197 | + TransactWrite.Put (item3, Some doesntExistCondition) |
| 198 | + TransactWrite.Delete (table.Template.ExtractKey item4, Some doesntExistCondition) |
| 199 | + TransactWrite.Delete (table.Template.ExtractKey item5, None) |
| 200 | + TransactWrite.Check (table.Template.ExtractKey item6, if shouldFail then existsCondition else doesntExistCondition) |
| 201 | + TransactWrite.Update (TableKey.Combined(item7.HashKey, item7.RangeKey), None, compileUpdate <@ fun t -> { t with Tuple = (42, 42)} @>) ] |
| 202 | + let mutable failed = false |
| 203 | + try do! table.TransactWriteItems requests |
| 204 | + with TransactWriteItemsRequest.TransactionCanceledConditionalCheckFailed -> failed <- true |
| 205 | + failed =! shouldFail |
| 206 | + |
| 207 | + let! maybeItem = table.TryGetItemAsync key |
| 208 | + test <@ shouldFail <> (maybeItem |> Option.contains { item with Value = 42 }) @> |
| 209 | + |
| 210 | + let! maybeItem2 = table.TryGetItemAsync(table.Template.ExtractKey item2) |
| 211 | + test <@ shouldFail <> (maybeItem2 |> Option.contains item2) @> |
| 212 | + |
| 213 | + let! maybeItem3 = table.TryGetItemAsync(table.Template.ExtractKey item3) |
| 214 | + test <@ shouldFail <> (maybeItem3 |> Option.contains item3) @> |
| 215 | + |
| 216 | + let! maybeItem7 = table.TryGetItemAsync(table.Template.ExtractKey item7) |
| 217 | + test <@ shouldFail <> (maybeItem7 |> Option.map (fun x -> x.Tuple) |> Option.contains (42, 42)) @> } |
| 218 | + |
| 219 | + let [<Fact>] ``Empty is rejected`` () = async { |
| 220 | + |
| 221 | + let! e = Async.Catch (table.TransactWriteItems []) |
| 222 | + |
| 223 | + test <@ match e with |
| 224 | + | Choice1Of2 () -> false |
| 225 | + | Choice2Of2 e -> e :? ArgumentOutOfRangeException @> } |
145 | 226 |
|
146 | 227 | interface IClassFixture<TableFixture>
|
0 commit comments