From b0f80b82cf5a7f99a53aaa29a86f0eaafdc986e2 Mon Sep 17 00:00:00 2001 From: Ismael Carlos Velten Date: Fri, 1 Feb 2019 10:31:36 -0200 Subject: [PATCH 1/6] Adjusting tests for machines with less processor cores --- build.fsx | 1 + .../DeferredTests.fs | 116 ++++++++++++++---- .../MiddlewaresTests.fs | 21 +--- .../ObservableExtensionsTests.fs | 25 ++-- tests/FSharp.Data.GraphQL.Tests/Program.fs | 2 +- .../Relay/NodeTests.fs | 13 +- .../SubscriptionTests.fs | 44 +++---- 7 files changed, 137 insertions(+), 85 deletions(-) diff --git a/build.fsx b/build.fsx index 57d3819cb..443ef13ce 100644 --- a/build.fsx +++ b/build.fsx @@ -205,6 +205,7 @@ Target "Build" (fun _ -> ) Target "RunTests" (fun _ -> + Console.WriteLine("Number of processors: {0}", Environment.ProcessorCount) DotNetCli.Test (fun p -> { p with #if MONO Framework = "netcoreapp2.0" diff --git a/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs b/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs index 884b932fb..af303ee72 100644 --- a/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs @@ -13,6 +13,18 @@ open FSharp.Data.GraphQL.Types #nowarn "40" +let ms x = + let factor = + match Environment.ProcessorCount with + | x when x >= 8 -> 1 + | x when x >= 4 -> 4 + | _ -> 6 + x * factor + +let delay time x = async { + do! Async.Sleep(ms time) + return x } + type TestSubject = { id: string a: string @@ -157,11 +169,6 @@ let DataType = Define.Field("bufferedList", ListOf AsyncDataType, (fun _ d -> d.bufferedList)) ]) -let delay ms x = async { - do! Async.Sleep(ms) - return x -} - let data = { id = "1" a = "Apple" @@ -629,9 +636,9 @@ let ``Each live result should be sent as soon as it is computed`` () = // The second result is a delayed async field, which is set to compute the value for 5 seconds. // The first result should come as soon as the live value is updated, which sould be almost instantly. // Therefore, let's assume that if it does not come in at least 3 seconds, test has failed. - if TimeSpan.FromSeconds(float 3) |> mre1.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 3)) |> mre1.WaitOne |> not then fail "Timeout while waiting for first deferred result" - if TimeSpan.FromSeconds(float 30) |> mre2.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second deferred result" sub.Received |> Seq.cast @@ -1282,13 +1289,16 @@ let ``Should buffer stream list correctly by timing information``() = ] "path", upcast [box "testData"; upcast "bufferedList"; upcast [0]] ] - let query = parse """{ - testData { - bufferedList @stream(interval : 3000) { - value + let query = + ms 3000 + |> sprintf """{ + testData { + bufferedList @stream(interval : %i) { + value + } } - } - }""" + }""" + |> parse use mre1 = new ManualResetEvent(false) use mre2 = new ManualResetEvent(false) let result = query |> executor.AsyncExecute |> sync @@ -1306,9 +1316,9 @@ let ``Should buffer stream list correctly by timing information``() = // to buffer results 3 and 2 (in this order), as together they take less than 3 seconds to compute, // and send them together on the first batch. // First result should come in a second batch, as it takes 5 seconds to compute, more than the time limit of the buffer. - if TimeSpan.FromSeconds(float 4) |> mre1.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 4)) |> mre1.WaitOne |> not then fail "Timeout while waiting for first Deferred GQLResponse" - if TimeSpan.FromSeconds(float 30) |> mre2.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second Deferred GQLResponse" sub.WaitCompleted() sub.Received @@ -1372,9 +1382,9 @@ let ``Should buffer stream list correctly by count information``() = // and send them together on the first batch. // First result should come in a second batch, as it takes 5 seconds to compute, which should be enough // to put the two other results in a batch with the preferred size. - if TimeSpan.FromSeconds(float 4) |> mre1.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 4)) |> mre1.WaitOne |> not then fail "Timeout while waiting for first Deferred GQLResponse" - if TimeSpan.FromSeconds(float 30) |> mre2.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second Deferred GQLResponse" sub.WaitCompleted() sub.Received @@ -1469,9 +1479,9 @@ let ``Each deferred result should be sent as soon as it is computed``() = // The second result is a delayed async field, which is set to compute the value for 5 seconds. // The first result should come almost instantly, as it is not a delayed computed field. // Therefore, let's assume that if it does not come in at least 3 seconds, test has failed. - if TimeSpan.FromSeconds(float 3) |> mre1.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 3)) |> mre1.WaitOne |> not then fail "Timeout while waiting for first deferred result" - if TimeSpan.FromSeconds(float 30) |> mre2.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second deferred result" sub.WaitCompleted() sub.Received @@ -1526,9 +1536,67 @@ let ``Each deferred result of a list should be sent as soon as it is computed`` // The first result is a delayed async field, which is set to compute the value for 5 seconds. // The second result should come first, almost instantly, as it is not a delayed computed field. // Therefore, let's assume that if it does not come in at least 4 seconds, test has failed. - if TimeSpan.FromSeconds(float 4) |> mre1.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 4)) |> mre1.WaitOne |> not + then fail "Timeout while waiting for first deferred result" + if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not + then fail "Timeout while waiting for second deferred result" + sub.WaitCompleted() + sub.Received + |> Seq.cast + |> itemEquals 0 expectedDeferred1 + |> itemEquals 1 expectedDeferred2 + |> ignore + | _ -> fail "Expected Deferred GQLRespnse" + +[] +let ``Each streamed result should be sent as soon as it is computed - normal seq`` () = + let expectedDirect = + NameValueLookup.ofList [ + "testData", upcast NameValueLookup.ofList [ + "syncSeq", upcast [] + ] + ] + let expectedDeferred1 = + NameValueLookup.ofList [ + "data", upcast [ + box <| NameValueLookup.ofList [ + "value", upcast "Sync 2" + ] + ] + "path", upcast [box "testData"; upcast "syncSeq"; upcast 0] + ] + let expectedDeferred2 = + NameValueLookup.ofList [ + "data", upcast [ + box <| NameValueLookup.ofList [ + "value", upcast "Sync 1" + ] + ] + "path", upcast [box "testData"; upcast "syncSeq"; upcast 1] + ] + let query = parse """{ + testData { + syncSeq @stream { + value + } + } + }""" + use mre1 = new ManualResetEvent(false) + use mre2 = new ManualResetEvent(false) + let result = query |> executor.AsyncExecute |> sync + match result with + | Deferred(data, errors, deferred) -> + empty errors + data.["data"] |> equals (upcast expectedDirect) + use sub = deferred |> Observer.createWithCallback (fun sub _ -> + if Seq.length sub.Received = 1 then mre1.Set() |> ignore + elif Seq.length sub.Received = 2 then mre2.Set() |> ignore) + // The first result is a delayed async field exposed through the sequence, which is set to compute the value for 5 seconds. + // The second result should come first, as its computation time is set for 1 second. + // Therefore, let's assume that if it does not come in at least 4 seconds, test has failed. + if TimeSpan.FromSeconds(float (ms 4)) |> mre1.WaitOne |> not then fail "Timeout while waiting for first deferred result" - if TimeSpan.FromSeconds(float 30) |> mre2.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second deferred result" sub.WaitCompleted() sub.Received @@ -1539,7 +1607,7 @@ let ``Each deferred result of a list should be sent as soon as it is computed`` | _ -> fail "Expected Deferred GQLRespnse" [] -let ``Each streamed result should be sent as soon as it is computed``() = +let ``Each streamed result should be sent as soon as it is computed - async seq``() = let expectedDirect = NameValueLookup.ofList [ "testData", upcast NameValueLookup.ofList [ @@ -1584,9 +1652,9 @@ let ``Each streamed result should be sent as soon as it is computed``() = // The first result is a delayed async field, which is set to compute the value for 5 seconds. // The second result should come first, almost instantly, as it is not a delayed computed field. // Therefore, let's assume that if it does not come in at least 4 seconds, test has failed. - if TimeSpan.FromSeconds(float 4) |> mre1.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 4)) |> mre1.WaitOne |> not then fail "Timeout while waiting for first deferred result" - if TimeSpan.FromSeconds(float 30) |> mre2.WaitOne |> not + if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second deferred result" sub.WaitCompleted() sub.Received diff --git a/tests/FSharp.Data.GraphQL.Tests/MiddlewaresTests.fs b/tests/FSharp.Data.GraphQL.Tests/MiddlewaresTests.fs index 00d854032..ab910c559 100644 --- a/tests/FSharp.Data.GraphQL.Tests/MiddlewaresTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/MiddlewaresTests.fs @@ -194,16 +194,13 @@ let ``Deferred queries : Should pass when below threshold``() = "path", upcast [ "A" :> obj; "subjects" :> obj ] ] let result = execute query - use mre = new ManualResetEvent(false) - let actualDeferred = ConcurrentBag() match result with | Deferred(data, errors, deferred) -> empty errors data.["data"] |> equals (upcast expected) - deferred |> Observable.add (fun x -> actualDeferred.Add(x); mre.Set() |> ignore) - if TimeSpan.FromSeconds(float 30) |> mre.WaitOne |> not - then fail "Timeout while waiting for Deferred GQLResponse" - actualDeferred |> single |> equals (upcast expectedDeferred) + let sub = Observer.create deferred + sub.WaitCompleted() + sub.Received |> single |> equals (upcast expectedDeferred) | _ -> fail "Expected Deferred GQLResponse" result.Metadata.TryFind("queryWeightThreshold") |> equals (Some 2.0) result.Metadata.TryFind("queryWeight") |> equals (Some 2.0) @@ -250,19 +247,13 @@ let ``Streamed queries : Should pass when below threshold``() = "path", upcast [ "A" :> obj; "subjects" :> obj; 1 :> obj ] ] let result = execute query - use mre = new ManualResetEvent(false) - let actualDeferred = ConcurrentBag() match result with | Deferred(data, errors, deferred) -> empty errors data.["data"] |> equals (upcast expected) - deferred - |> Observable.add (fun x -> - actualDeferred.Add(x) - if actualDeferred.Count = 2 then mre.Set() |> ignore) - if TimeSpan.FromSeconds(float 30) |> mre.WaitOne |> not - then fail "Timeout while waiting for Deferred GQLResponse" - actualDeferred + let sub = Observer.create deferred + sub.WaitCompleted(2) + sub.Received |> Seq.cast |> contains expectedDeferred1 |> contains expectedDeferred2 diff --git a/tests/FSharp.Data.GraphQL.Tests/ObservableExtensionsTests.fs b/tests/FSharp.Data.GraphQL.Tests/ObservableExtensionsTests.fs index 526b4708e..3d931e166 100644 --- a/tests/FSharp.Data.GraphQL.Tests/ObservableExtensionsTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/ObservableExtensionsTests.fs @@ -6,6 +6,19 @@ module FSharp.Data.GraphQL.Tests.ObservableExtensionsTests open Xunit open FSharp.Data.GraphQL open Helpers +open System + +let ms x = + let factor = + match Environment.ProcessorCount with + | x when x >= 8 -> 1 + | x when x >= 4 -> 5 + | _ -> 20 + x * factor + +let delay time x = async { + do! Async.Sleep(ms time) + return x } [] let ``ofSeq should call OnComplete and return items in expected order`` () = @@ -55,10 +68,6 @@ let ``ofSeq on an empty sequence should call OnComplete and return items in expe sub.WaitCompleted() sub.Received |> seqEquals source -let delay ms x = async { - do! Async.Sleep(ms) - return x } - [] let ``ofAsyncSeq should call OnComplete and return items in expected order`` () = let source = seq { @@ -84,10 +93,10 @@ let ``ofAsyncValSeq should call OnComplete and return items in expected order`` [] let ``bufferByTiming should call OnComplete and return items in expected order`` () = let source = seq { - yield delay 500 2 + yield delay 400 2 yield delay 100 1 yield delay 200 3 } - let obs = Observable.ofAsyncSeq source |> Observable.bufferByTiming 300 + let obs = Observable.ofAsyncSeq source |> Observable.bufferByTiming (ms 300) use sub = Observer.create obs sub.WaitCompleted() sub.Received |> seqEquals [ [1; 3]; [2] ] @@ -95,7 +104,7 @@ let ``bufferByTiming should call OnComplete and return items in expected order`` [] let ``bufferByElementCount should call OnComplete and return items in expected order`` () = let source = seq { - yield delay 500 2 + yield delay 400 2 yield delay 100 1 yield delay 200 3 } let obs = Observable.ofAsyncSeq source |> Observable.bufferByElementCount 2 @@ -110,7 +119,7 @@ let ``bufferByTimingAndElementCount should call OnComplete and return items in e yield delay 50 1 yield delay 100 3 yield delay 150 4 } - let obs = Observable.ofAsyncSeq source |> Observable.bufferByTimingAndElementCount 300 2 + let obs = Observable.ofAsyncSeq source |> Observable.bufferByTimingAndElementCount (ms 300) 2 use sub = Observer.create obs sub.WaitCompleted() sub.Received |> seqEquals [ [1; 3]; [4]; [2] ] diff --git a/tests/FSharp.Data.GraphQL.Tests/Program.fs b/tests/FSharp.Data.GraphQL.Tests/Program.fs index 4f18e7f3a..52113d02c 100644 --- a/tests/FSharp.Data.GraphQL.Tests/Program.fs +++ b/tests/FSharp.Data.GraphQL.Tests/Program.fs @@ -1,4 +1,4 @@ module Program [] -let main args = 0 \ No newline at end of file +let main _ = 0 \ No newline at end of file diff --git a/tests/FSharp.Data.GraphQL.Tests/Relay/NodeTests.fs b/tests/FSharp.Data.GraphQL.Tests/Relay/NodeTests.fs index 6f86d30d8..c4873a687 100644 --- a/tests/FSharp.Data.GraphQL.Tests/Relay/NodeTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/Relay/NodeTests.fs @@ -60,17 +60,12 @@ let execAndValidateNode (query: string) expectedDirect expectedDeferred = | Some expectedDeferred -> match result with | Deferred(data, errors, deferred) -> - use mre = new ManualResetEvent(false) - let actualDeferred = ConcurrentBag() - let expectedItems = Seq.length expectedDeferred + let expectedItemCount = Seq.length expectedDeferred empty errors data.["data"] |> equals (upcast NameValueLookup.ofList ["node", upcast expectedDirect]) - deferred - |> Observable.add (fun x -> - actualDeferred.Add(x) - if actualDeferred.Count = expectedItems then set mre) - wait mre "Timeout while waiting for Deferred GQLResponse" - actualDeferred + let sub = Observer.create deferred + sub.WaitCompleted(expectedItemCount) + sub.Received |> Seq.cast |> Seq.iter (fun ad -> expectedDeferred |> contains ad |> ignore) | _ -> fail "Expected a deferred GQLResponse" diff --git a/tests/FSharp.Data.GraphQL.Tests/SubscriptionTests.fs b/tests/FSharp.Data.GraphQL.Tests/SubscriptionTests.fs index 0fa7e36ce..fab784ac9 100644 --- a/tests/FSharp.Data.GraphQL.Tests/SubscriptionTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/SubscriptionTests.fs @@ -119,15 +119,13 @@ let ``Should be able to subscribe to sync field and get results``() = data } }""" - use mre = new ManualResetEvent(false) - let actual = ConcurrentBag() let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - data |> Observable.add (fun x -> actual.Add(x); set mre) + let sub = Observer.create data updateValue 1 "Updated value 1" - wait mre "Timeout while waiting for Stream GQLResponse" - actual + sub.WaitForItem() + sub.Received |> Seq.cast |> contains expected |> ignore @@ -149,15 +147,13 @@ let ``Should be able to subscribe to tagged sync field and get results with expe data } }""" - use mre = new ManualResetEvent(false) - let actual = ConcurrentBag() let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - data |> Observable.add (fun x -> actual.Add(x); set mre) + let sub = Observer.create data updateValue 1 "Updated value 1" - wait mre "Timeout while waiting for Stream GQLResponse" - actual + sub.WaitForItem() + sub.Received |> Seq.cast |> contains expected |> ignore @@ -171,14 +167,12 @@ let ``Should be able to subscribe to tagged sync field and do not get results wi data } }""" - use mre = new ManualResetEvent(false) - let actual = ConcurrentBag() let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - data |> Observable.add (fun x -> actual.Add(x); set mre) + let sub = Observer.create data updateValue 1 "Updated value 1" - ensureThat (fun () -> actual.IsEmpty) 10 "Should not get results with given tag" + ensureThat (fun () -> Seq.isEmpty sub.Received) 50 "Should not get results with given tag" | _ -> failwith "Expected Stream GQLResponse" [] @@ -197,15 +191,13 @@ let ``Should be able to subscribe to async field and get results``() = data } }""" - let mre = new ManualResetEvent(false) - let actual = ConcurrentBag() let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - data |> Observable.add (fun x -> actual.Add(x); set mre) + let sub = Observer.create data updateValue 1 "Updated value 1" - wait mre "Timeout while waiting for Stream GQLResponse" - actual + sub.WaitForItem() + sub.Received |> Seq.cast |> contains expected |> ignore @@ -227,15 +219,13 @@ let ``Should be able to subscribe to tagged async field and get results with exp data } }""" - use mre = new ManualResetEvent(false) - let actual = ConcurrentBag() let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - data |> Observable.add (fun x -> actual.Add(x); set mre) + let sub = Observer.create data updateValue 1 "Updated value 1" - wait mre "Timeout while waiting for Stream GQLResponse" - actual + sub.WaitForItem() + sub.Received |> Seq.cast |> contains expected |> ignore @@ -249,12 +239,10 @@ let ``Should be able to subscribe to tagged async field and do not get results w data } }""" - use mre = new ManualResetEvent(false) - let actual = ConcurrentBag() let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - data |> Observable.add (fun x -> actual.Add(x); set mre) + let sub = Observer.create data updateValue 1 "Updated value 1" - ensureThat (fun () -> actual.IsEmpty) 10 "Should not get results with given tag" + ensureThat (fun () -> Seq.isEmpty sub.Received) 50 "Should not get results with given tag" | _ -> failwith "Expected Stream GQLResponse" \ No newline at end of file From c1cf5a4db518376f338272d7bdc222c14f28405d Mon Sep 17 00:00:00 2001 From: Ismael Carlos Velten Date: Fri, 1 Feb 2019 10:59:09 -0200 Subject: [PATCH 2/6] Removing test from other branch --- .../DeferredTests.fs | 58 ------------------- 1 file changed, 58 deletions(-) diff --git a/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs b/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs index af303ee72..f1001b2f7 100644 --- a/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs @@ -1548,64 +1548,6 @@ let ``Each deferred result of a list should be sent as soon as it is computed`` |> ignore | _ -> fail "Expected Deferred GQLRespnse" -[] -let ``Each streamed result should be sent as soon as it is computed - normal seq`` () = - let expectedDirect = - NameValueLookup.ofList [ - "testData", upcast NameValueLookup.ofList [ - "syncSeq", upcast [] - ] - ] - let expectedDeferred1 = - NameValueLookup.ofList [ - "data", upcast [ - box <| NameValueLookup.ofList [ - "value", upcast "Sync 2" - ] - ] - "path", upcast [box "testData"; upcast "syncSeq"; upcast 0] - ] - let expectedDeferred2 = - NameValueLookup.ofList [ - "data", upcast [ - box <| NameValueLookup.ofList [ - "value", upcast "Sync 1" - ] - ] - "path", upcast [box "testData"; upcast "syncSeq"; upcast 1] - ] - let query = parse """{ - testData { - syncSeq @stream { - value - } - } - }""" - use mre1 = new ManualResetEvent(false) - use mre2 = new ManualResetEvent(false) - let result = query |> executor.AsyncExecute |> sync - match result with - | Deferred(data, errors, deferred) -> - empty errors - data.["data"] |> equals (upcast expectedDirect) - use sub = deferred |> Observer.createWithCallback (fun sub _ -> - if Seq.length sub.Received = 1 then mre1.Set() |> ignore - elif Seq.length sub.Received = 2 then mre2.Set() |> ignore) - // The first result is a delayed async field exposed through the sequence, which is set to compute the value for 5 seconds. - // The second result should come first, as its computation time is set for 1 second. - // Therefore, let's assume that if it does not come in at least 4 seconds, test has failed. - if TimeSpan.FromSeconds(float (ms 4)) |> mre1.WaitOne |> not - then fail "Timeout while waiting for first deferred result" - if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not - then fail "Timeout while waiting for second deferred result" - sub.WaitCompleted() - sub.Received - |> Seq.cast - |> itemEquals 0 expectedDeferred1 - |> itemEquals 1 expectedDeferred2 - |> ignore - | _ -> fail "Expected Deferred GQLRespnse" - [] let ``Each streamed result should be sent as soon as it is computed - async seq``() = let expectedDirect = From f8c09594b8030ad4cab59b756648162616c59a79 Mon Sep 17 00:00:00 2001 From: Ismael Carlos Velten Date: Fri, 1 Feb 2019 11:04:52 -0200 Subject: [PATCH 3/6] Merge from test-fixes-2 --- .paket/Paket.Restore.targets | 10 ++++- src/FSharp.Data.GraphQL.Server/Execution.fs | 49 ++++++++++----------- src/FSharp.Data.GraphQL.Shared/AsyncVal.fs | 12 +++-- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/.paket/Paket.Restore.targets b/.paket/Paket.Restore.targets index b4f593eb8..52f41c608 100644 --- a/.paket/Paket.Restore.targets +++ b/.paket/Paket.Restore.targets @@ -62,6 +62,9 @@ true true + + + True @@ -102,7 +105,11 @@ true - + + true @@ -183,6 +190,7 @@ runtime runtime true + true diff --git a/src/FSharp.Data.GraphQL.Server/Execution.fs b/src/FSharp.Data.GraphQL.Server/Execution.fs index c52e3ebc3..efb3230ff 100644 --- a/src/FSharp.Data.GraphQL.Server/Execution.fs +++ b/src/FSharp.Data.GraphQL.Server/Execution.fs @@ -259,7 +259,7 @@ type ResolverTree = | ResolverListNode l -> l.Value and ResolverLeaf = { Name: string; Value: obj option } and ResolverError = { Name: string; Message: string; PathToOrigin: obj list } -and ResolverNode = { Name: string; Value: obj option; Children: AsyncVal [] } +and ResolverNode = { Name: string; Value: obj option; Children: AsyncVal seq } module ResolverTree = let rec pathFold leafOp errorOp nodeOp listOp = @@ -279,7 +279,7 @@ module ResolverTree = let! c' = c return helper path' c' } - let ts = node.Children |> Array.map mapper + let ts = node.Children |> Seq.map mapper nodeOp path' node.Name node.Value ts | ResolverListNode node -> let path' = (node.Name :> obj)::path @@ -287,13 +287,13 @@ module ResolverTree = let! c' = c return helper ((box i)::path') c' } - let ts = node.Children |> Array.mapi mapper + let ts = node.Children |> Seq.mapi mapper listOp path' node.Name node.Value ts helper [] -let private foldChildren (children : AsyncVal * Error list>> []) = +let private foldChildren (children : AsyncVal * Error list>> seq) = children - |> Array.fold (fun (kvpsErrs : AsyncVal list * Error list>) child -> asyncVal { + |> Seq.fold (fun (kvpsErrs : AsyncVal list * Error list>) child -> asyncVal { let! kvps, errs = kvpsErrs let! c = child let! c, e = c @@ -345,7 +345,7 @@ let private treeToStream (streamOptions : BufferedStreamOptions) tree = function | ResolverListNode list -> list.Children - |> Array.mapi (fun i x -> + |> Seq.mapi (fun i x -> asyncVal { let! x' = x return i, x' @@ -404,7 +404,7 @@ let rec private buildResolverTree (returnDef: OutputDef) (ctx: ResolveFieldConte | Some v -> buildObjectFields fields objdef ctx fieldExecuteMap name v | None -> if ctx.ExecutionInfo.IsNullable - then asyncVal { return ResolverObjectNode { Name = name; Value = None; Children = [| |] } } + then asyncVal { return ResolverObjectNode { Name = name; Value = None; Children = [||] } } else nullResolverError name | kind -> failwithf "Unexpected value of ctx.ExecutionPlan.Kind: %A" kind | Scalar scalardef -> @@ -424,28 +424,25 @@ let rec private buildResolverTree (returnDef: OutputDef) (ctx: ResolveFieldConte match kind with | ResolveCollection innerPlan -> { ctx with ExecutionInfo = innerPlan } | kind -> failwithf "Unexpected value of ctx.ExecutionPlan.Kind: %A" kind - let rec build acc (items: obj list) = - match items with - | value::xs -> - if not innerCtx.ExecutionInfo.IsNullable && isNull value - then nullResolverError innerCtx.ExecutionInfo.Identifier + let build (items : seq) = + let children = seq { + for item in items do + if not innerCtx.ExecutionInfo.IsNullable && isNull item + then yield nullResolverError innerCtx.ExecutionInfo.Identifier else - let t = asyncVal { - let! res = buildResolverTree innerdef innerCtx fieldExecuteMap (toOption value) + yield asyncVal { + let! res = buildResolverTree innerdef innerCtx fieldExecuteMap (toOption item) match res with | ResolverError e when not innerCtx.ExecutionInfo.IsNullable -> return! propagateError name e - | _ -> return res - } - build (t::acc) xs - | [] -> asyncVal { return ResolverListNode { Name = name; Value = value; Children = acc |> List.map (AsyncVal.map (fun x -> x)) |> List.rev |> List.toArray } } + | _ -> return res } } + asyncVal { return ResolverListNode { Name = name; Value = value; Children = children } } match value with | None when not ctx.ExecutionInfo.IsNullable -> nullResolverError name - | None -> asyncVal { return ResolverListNode { Name = name; Value = None; Children = [| |] } } + | None -> asyncVal { return ResolverListNode { Name = name; Value = None; Children = [||] } } | ObjectOption (:? System.Collections.IEnumerable as enumerable) -> enumerable |> Seq.cast - |> Seq.toList - |> build [] + |> build | _ -> raise <| GraphQLException (sprintf "Expected to have enumerable value in field '%s' but got '%O'" ctx.ExecutionInfo.Identifier (value.GetType())) | Nullable (Output innerdef) -> // Stop propagation of null values @@ -465,7 +462,7 @@ let rec private buildResolverTree (returnDef: OutputDef) (ctx: ResolveFieldConte | None -> asyncVal { return ResolverError { Name = name; Message = ctx.Schema.ParseError (GraphQLException (sprintf "GraphQL Interface '%s' is not implemented by the type '%s'" idef.Name resolvedDef.Name)); PathToOrigin = [] } } | None -> if ctx.ExecutionInfo.IsNullable - then asyncVal { return ResolverObjectNode { Name = name; Value = None; Children = [| |] } } + then asyncVal { return ResolverObjectNode { Name = name; Value = None; Children = [||] } } else nullResolverError name | Union udef -> let possibleTypesFn = ctx.Schema.GetPossibleTypes @@ -488,13 +485,13 @@ let rec private buildResolverTree (returnDef: OutputDef) (ctx: ResolveFieldConte | None -> asyncVal { return ResolverError { Name = name; Message = ctx.Schema.ParseError (GraphQLException (sprintf "GraphQL Union '%s' is not implemented by the type '%s'" udef.Name resolvedDef.Name)); PathToOrigin = [] } } | None -> if ctx.ExecutionInfo.IsNullable - then asyncVal { return ResolverObjectNode { Name = name; Value = None; Children = [| |] } } + then asyncVal { return ResolverObjectNode { Name = name; Value = None; Children = [||] } } else nullResolverError name | _ -> failwithf "Unexpected value of returnDef: %O" returnDef match ctx.ExecutionInfo.Kind, returnDef, ctx.ExecutionInfo.IsDeferred with | ResolveDeferred _, (Scalar _ | Enum _ | Nullable _), false -> asyncVal { return ResolverLeaf { Name = name; Value = None } } - | ResolveDeferred _, (Object _ | Interface _ | Union _), false -> asyncVal { return ResolverObjectNode { Name = name; Value = None; Children = [| |] } } - | ResolveDeferred _, List _, false -> asyncVal { return ResolverListNode { Name = name; Value = Some (upcast [ ]); Children = [| |] } } + | ResolveDeferred _, (Object _ | Interface _ | Union _), false -> asyncVal { return ResolverObjectNode { Name = name; Value = None; Children = [||] } } + | ResolveDeferred _, List _, false -> asyncVal { return ResolverListNode { Name = name; Value = Some (upcast [ ]); Children = [||] } } | _ -> resolveDirect ctx.ExecutionInfo.Kind and buildObjectFields (fields: ExecutionInfo list) (objdef: ObjectDef) (ctx: ResolveFieldContext) (fieldExecuteMap: FieldExecuteMap) (name: string) (value: obj): AsyncVal = @@ -680,7 +677,7 @@ let private executeQueryOrMutation (resultSet: (string * ExecutionInfo) []) (ctx let mapLive (tree : ResolverTree) (path : obj list) (d : DeferredExecutionInfo) (fieldCtx : ResolveFieldContext) = asyncVal { let getFieldName (node : ResolverNode) = asyncVal { - match node.Children |> Array.tryHead with + match node.Children |> Seq.tryHead with | Some c -> let! res = c return res.Name diff --git a/src/FSharp.Data.GraphQL.Shared/AsyncVal.fs b/src/FSharp.Data.GraphQL.Shared/AsyncVal.fs index d3da2aff0..dabfeeba0 100644 --- a/src/FSharp.Data.GraphQL.Shared/AsyncVal.fs +++ b/src/FSharp.Data.GraphQL.Shared/AsyncVal.fs @@ -115,6 +115,10 @@ module AsyncVal = /// Returned array maintain order of values. /// If the array contains a Failure, then the entire array will not resolve let collectSequential (values: AsyncVal<'T> []) : AsyncVal<'T []> = + let mapper = + function + | Value v -> v + | other -> failwithf "Expected a synchronous value, but got %O" other if values.Length = 0 then Value [||] elif values |> Array.exists isAsync then Async(async { @@ -129,7 +133,7 @@ module AsyncVal = | Failure f -> results.[i] <- raise f return results }) - else Value (values |> Array.map (fun (Value v) -> v)) + else Value (values |> Array.map mapper) @@ -197,12 +201,6 @@ module AsyncExtensions = /// Computation expression for working on AsyncVals. let asyncVal = AsyncValBuilder () - - /// Active pattern used for checking if AsyncVal contains immediate value. - let (|Immediate|_|) (x: AsyncVal<'T>) = match x with | Value v -> Some v | _ -> None - - /// Active patter used for checking if AsyncVal wraps an Async computation. - let (|Async|_|) (x: AsyncVal<'T>) = match x with | Async a -> Some a | _ -> None type Microsoft.FSharp.Control.AsyncBuilder with From fd6532738f73fb75ea75c5807dc71a8ca888a3a7 Mon Sep 17 00:00:00 2001 From: Ismael Carlos Velten Date: Fri, 1 Feb 2019 12:46:14 -0200 Subject: [PATCH 4/6] Increasing tolerance in WaitCompleted --- .../DeferredTests.fs | 12 +++---- tests/FSharp.Data.GraphQL.Tests/Helpers.fs | 15 ++++---- .../ObservableExtensionsTests.fs | 36 +++++++++---------- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs b/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs index f1001b2f7..4d23de4d3 100644 --- a/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs @@ -7,8 +7,6 @@ open FSharp.Data.GraphQL open FSharp.Data.GraphQL.Parser open FSharp.Data.GraphQL.Execution open System.Threading -open System.Collections.Generic -open System.Collections.Concurrent open FSharp.Data.GraphQL.Types #nowarn "40" @@ -1320,7 +1318,7 @@ let ``Should buffer stream list correctly by timing information``() = then fail "Timeout while waiting for first Deferred GQLResponse" if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second Deferred GQLResponse" - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> Seq.cast |> itemEquals 0 expectedDeferred1 @@ -1386,7 +1384,7 @@ let ``Should buffer stream list correctly by count information``() = then fail "Timeout while waiting for first Deferred GQLResponse" if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second Deferred GQLResponse" - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> Seq.cast |> itemEquals 0 expectedDeferred1 @@ -1483,7 +1481,7 @@ let ``Each deferred result should be sent as soon as it is computed``() = then fail "Timeout while waiting for first deferred result" if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second deferred result" - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> Seq.cast |> itemEquals 0 expectedDeferred1 @@ -1540,7 +1538,7 @@ let ``Each deferred result of a list should be sent as soon as it is computed`` then fail "Timeout while waiting for first deferred result" if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second deferred result" - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> Seq.cast |> itemEquals 0 expectedDeferred1 @@ -1598,7 +1596,7 @@ let ``Each streamed result should be sent as soon as it is computed - async seq` then fail "Timeout while waiting for first deferred result" if TimeSpan.FromSeconds(float (ms 10)) |> mre2.WaitOne |> not then fail "Timeout while waiting for second deferred result" - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> Seq.cast |> itemEquals 0 expectedDeferred1 diff --git a/tests/FSharp.Data.GraphQL.Tests/Helpers.fs b/tests/FSharp.Data.GraphQL.Tests/Helpers.fs index 8141d4a0b..367634541 100644 --- a/tests/FSharp.Data.GraphQL.Tests/Helpers.fs +++ b/tests/FSharp.Data.GraphQL.Tests/Helpers.fs @@ -129,12 +129,15 @@ type TestObserver<'T>(obs : IObservable<'T>, ?onReceived : TestObserver<'T> -> ' do subscription <- obs.Subscribe(this) member __.Received with get() = received.AsEnumerable() - member __.WaitCompleted() = - wait mre "Timeout waiting for OnCompleted" - member x.WaitCompleted(expectedItemCount) = - x.WaitCompleted() - if received.Count < expectedItemCount - then failwithf "Expected to receive %i items, but received %i" expectedItemCount received.Count + member __.WaitCompleted(?expectedItemCount, ?timeout) = + let ms = defaultArg timeout 30 + if TimeSpan.FromSeconds(float ms) |> mre.WaitOne |> not + then fail "Timeout waiting for OnCompleted" + match expectedItemCount with + | Some x -> + if received.Count < x + then failwithf "Expected to receive %i items, but received %i" x received.Count + | None -> () member __.WaitForItems(expectedItemCount) = let errorMsg = sprintf "Expected to receive least %i items, but received %i" expectedItemCount received.Count waitFor (fun () -> received.Count = expectedItemCount) (expectedItemCount * 100) errorMsg diff --git a/tests/FSharp.Data.GraphQL.Tests/ObservableExtensionsTests.fs b/tests/FSharp.Data.GraphQL.Tests/ObservableExtensionsTests.fs index 3d931e166..bc9c39149 100644 --- a/tests/FSharp.Data.GraphQL.Tests/ObservableExtensionsTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/ObservableExtensionsTests.fs @@ -25,7 +25,7 @@ let ``ofSeq should call OnComplete and return items in expected order`` () = let source = seq { for x in 1 .. 5 do yield x } let obs = Observable.ofSeq source use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals source [] @@ -33,7 +33,7 @@ let `` bind should call OnComplete and return items in expected order`` () = let source = seq { for x in 1 .. 5 do yield x } let obs = Observable.ofSeq source |> Observable.bind (fun x -> Observable.ofSeq [x; x]) use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ 1; 1; 2; 2; 3; 3; 4; 4; 5; 5 ] [] @@ -41,7 +41,7 @@ let `` ofAsync should call OnComplete and return items in expected order`` () = let source = async { return "test" } let obs = Observable.ofAsync source use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ "test" ] @@ -50,7 +50,7 @@ let `` ofAsyncVal should call OnComplete and return items in expected order`` () let source = async { return "test" } |> AsyncVal.ofAsync let obs = Observable.ofAsyncVal source use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ "test" ] [] @@ -65,7 +65,7 @@ let ``ofSeq on an empty sequence should call OnComplete and return items in expe let source = Seq.empty let obs = Observable.ofSeq source use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals source [] @@ -76,7 +76,7 @@ let ``ofAsyncSeq should call OnComplete and return items in expected order`` () yield delay 200 3 } let obs = Observable.ofAsyncSeq source use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ 1; 3; 2 ] [] @@ -87,7 +87,7 @@ let ``ofAsyncValSeq should call OnComplete and return items in expected order`` yield delay 200 3 |> AsyncVal.ofAsync } let obs = Observable.ofAsyncValSeq source use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ 1; 3; 2 ] [] @@ -98,7 +98,7 @@ let ``bufferByTiming should call OnComplete and return items in expected order`` yield delay 200 3 } let obs = Observable.ofAsyncSeq source |> Observable.bufferByTiming (ms 300) use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ [1; 3]; [2] ] [] @@ -109,7 +109,7 @@ let ``bufferByElementCount should call OnComplete and return items in expected o yield delay 200 3 } let obs = Observable.ofAsyncSeq source |> Observable.bufferByElementCount 2 use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ [1; 3]; [2] ] [] @@ -121,7 +121,7 @@ let ``bufferByTimingAndElementCount should call OnComplete and return items in e yield delay 150 4 } let obs = Observable.ofAsyncSeq source |> Observable.bufferByTimingAndElementCount (ms 300) 2 use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ [1; 3]; [4]; [2] ] type IndexException(index : int) = @@ -135,7 +135,7 @@ let ``catch should call OnComplete and return items in expected order`` () = Observable.ofSeq source |> Observable.catch (fun (ex : IndexException) -> ex.Index |> Observable.singleton) use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ 1 ] [] @@ -145,7 +145,7 @@ let ``choose should cal OnComplete`` () = Observable.ofSeq source |> Observable.choose (fun x -> match x % 2 with | 0 -> Some x | _ -> None) use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ 2; 4 ] [] @@ -163,7 +163,7 @@ let ``concat should call OnComplete and return items in expected order`` () = |> Observable.map Observable.ofAsyncSeq |> Observable.concat use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ 1; 3; 2; 5; 4 ] [] @@ -179,7 +179,7 @@ let ``concat2 should call OnComplete and return items in expected order`` () = Observable.ofAsyncSeq source2 |> Observable.concat2 (Observable.ofAsyncSeq source1) use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ 1; 3; 2; 5; 4 ] [] @@ -197,7 +197,7 @@ let ``merge should call OnComplete and return items in expected order`` () = |> Observable.map Observable.ofAsyncSeq |> Observable.merge use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ 1; 3; 5; 4; 2 ] [] @@ -213,7 +213,7 @@ let ``merge2 should call OnComplete and return items in expected order`` () = Observable.ofAsyncSeq source2 |> Observable.merge2 (Observable.ofAsyncSeq source1) use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals [ 1; 3; 5; 4; 2 ] [] @@ -221,7 +221,7 @@ let ``concatSeq should call OnComplete and return items in expected order`` () = let source = seq { for x in 1 .. 5 do yield x } let obs = Observable.singleton source |> Observable.concatSeq use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals source [] @@ -229,5 +229,5 @@ let ``mapAsync should call OnComplete and return items in expected order`` () = let source = seq { for x in 1 .. 5 do yield x } let obs = Observable.ofSeq source |> Observable.mapAsync (fun x -> async { return x }) use sub = Observer.create obs - sub.WaitCompleted() + sub.WaitCompleted(timeout = ms 10) sub.Received |> seqEquals source \ No newline at end of file From 83cef858d89b8e2ed37dd5f9c73c20202b53f080 Mon Sep 17 00:00:00 2001 From: Ismael Carlos Velten Date: Mon, 4 Feb 2019 16:01:48 -0200 Subject: [PATCH 5/6] Disposing test observer after usage --- tests/FSharp.Data.GraphQL.Tests/MiddlewaresTests.fs | 4 ++-- tests/FSharp.Data.GraphQL.Tests/Relay/NodeTests.fs | 2 +- tests/FSharp.Data.GraphQL.Tests/SubscriptionTests.fs | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/FSharp.Data.GraphQL.Tests/MiddlewaresTests.fs b/tests/FSharp.Data.GraphQL.Tests/MiddlewaresTests.fs index ab910c559..bdaebe915 100644 --- a/tests/FSharp.Data.GraphQL.Tests/MiddlewaresTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/MiddlewaresTests.fs @@ -198,7 +198,7 @@ let ``Deferred queries : Should pass when below threshold``() = | Deferred(data, errors, deferred) -> empty errors data.["data"] |> equals (upcast expected) - let sub = Observer.create deferred + use sub = Observer.create deferred sub.WaitCompleted() sub.Received |> single |> equals (upcast expectedDeferred) | _ -> fail "Expected Deferred GQLResponse" @@ -251,7 +251,7 @@ let ``Streamed queries : Should pass when below threshold``() = | Deferred(data, errors, deferred) -> empty errors data.["data"] |> equals (upcast expected) - let sub = Observer.create deferred + use sub = Observer.create deferred sub.WaitCompleted(2) sub.Received |> Seq.cast diff --git a/tests/FSharp.Data.GraphQL.Tests/Relay/NodeTests.fs b/tests/FSharp.Data.GraphQL.Tests/Relay/NodeTests.fs index c4873a687..496c43b7c 100644 --- a/tests/FSharp.Data.GraphQL.Tests/Relay/NodeTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/Relay/NodeTests.fs @@ -63,7 +63,7 @@ let execAndValidateNode (query: string) expectedDirect expectedDeferred = let expectedItemCount = Seq.length expectedDeferred empty errors data.["data"] |> equals (upcast NameValueLookup.ofList ["node", upcast expectedDirect]) - let sub = Observer.create deferred + use sub = Observer.create deferred sub.WaitCompleted(expectedItemCount) sub.Received |> Seq.cast diff --git a/tests/FSharp.Data.GraphQL.Tests/SubscriptionTests.fs b/tests/FSharp.Data.GraphQL.Tests/SubscriptionTests.fs index fab784ac9..979676639 100644 --- a/tests/FSharp.Data.GraphQL.Tests/SubscriptionTests.fs +++ b/tests/FSharp.Data.GraphQL.Tests/SubscriptionTests.fs @@ -122,7 +122,7 @@ let ``Should be able to subscribe to sync field and get results``() = let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - let sub = Observer.create data + use sub = Observer.create data updateValue 1 "Updated value 1" sub.WaitForItem() sub.Received @@ -150,7 +150,7 @@ let ``Should be able to subscribe to tagged sync field and get results with expe let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - let sub = Observer.create data + use sub = Observer.create data updateValue 1 "Updated value 1" sub.WaitForItem() sub.Received @@ -170,7 +170,7 @@ let ``Should be able to subscribe to tagged sync field and do not get results wi let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - let sub = Observer.create data + use sub = Observer.create data updateValue 1 "Updated value 1" ensureThat (fun () -> Seq.isEmpty sub.Received) 50 "Should not get results with given tag" | _ -> failwith "Expected Stream GQLResponse" @@ -194,7 +194,7 @@ let ``Should be able to subscribe to async field and get results``() = let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - let sub = Observer.create data + use sub = Observer.create data updateValue 1 "Updated value 1" sub.WaitForItem() sub.Received @@ -222,7 +222,7 @@ let ``Should be able to subscribe to tagged async field and get results with exp let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - let sub = Observer.create data + use sub = Observer.create data updateValue 1 "Updated value 1" sub.WaitForItem() sub.Received @@ -242,7 +242,7 @@ let ``Should be able to subscribe to tagged async field and do not get results w let result = executor.AsyncExecute(query) |> sync match result with | Stream data -> - let sub = Observer.create data + use sub = Observer.create data updateValue 1 "Updated value 1" ensureThat (fun () -> Seq.isEmpty sub.Received) 50 "Should not get results with given tag" | _ -> failwith "Expected Stream GQLResponse" \ No newline at end of file From c6a6108f30da34790804509b212652e0bc40a8a6 Mon Sep 17 00:00:00 2001 From: Ismael Carlos Velten Date: Mon, 4 Feb 2019 16:51:32 -0200 Subject: [PATCH 6/6] Changing the build script to show result of each ran unit test --- build.fsx | 1 + 1 file changed, 1 insertion(+) diff --git a/build.fsx b/build.fsx index 443ef13ce..3f1e42214 100644 --- a/build.fsx +++ b/build.fsx @@ -210,6 +210,7 @@ Target "RunTests" (fun _ -> #if MONO Framework = "netcoreapp2.0" #endif + AdditionalArgs = [ "--no-build"; "-v=normal" ] Configuration = "Release" Project = "tests/FSharp.Data.GraphQL.Tests/FSharp.Data.GraphQL.Tests.fsproj" }) )