diff --git a/GraphQL.Client.sln b/GraphQL.Client.sln
index ab95f2ec..d6faf815 100644
--- a/GraphQL.Client.sln
+++ b/GraphQL.Client.sln
@@ -65,6 +65,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{89
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.Client.Example", "examples\GraphQL.Client.Example\GraphQL.Client.Example.csproj", "{6B13B87D-1EF4-485F-BC5D-891E2F4DA6CD}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphQL.Client.TestHost", "src\GraphQL.Client.TestHost\GraphQL.Client.TestHost.csproj", "{01AE8466-3E48-4988-81F1-7F93F1531302}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -127,6 +129,10 @@ Global
{6B13B87D-1EF4-485F-BC5D-891E2F4DA6CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B13B87D-1EF4-485F-BC5D-891E2F4DA6CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B13B87D-1EF4-485F-BC5D-891E2F4DA6CD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {01AE8466-3E48-4988-81F1-7F93F1531302}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {01AE8466-3E48-4988-81F1-7F93F1531302}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {01AE8466-3E48-4988-81F1-7F93F1531302}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {01AE8466-3E48-4988-81F1-7F93F1531302}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -146,6 +152,7 @@ Global
{0D307BAD-27AE-4A5D-8764-4AA2620B01E9} = {0B0EDB0F-FF67-4B78-A8DB-B5C23E1FEE8C}
{7FFFEC00-D751-4FFC-9FD4-E91858F9A1C5} = {47C98B55-08F1-4428-863E-2C5C876DEEFE}
{6B13B87D-1EF4-485F-BC5D-891E2F4DA6CD} = {89AD33AB-64F6-4F82-822F-21DF7A10CEC0}
+ {01AE8466-3E48-4988-81F1-7F93F1531302} = {47C98B55-08F1-4428-863E-2C5C876DEEFE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {387AC1AC-F90C-4EF8-955A-04D495C75AF4}
diff --git a/src/GraphQL.Client.TestHost/GraphQL.Client.TestHost.csproj b/src/GraphQL.Client.TestHost/GraphQL.Client.TestHost.csproj
new file mode 100644
index 00000000..c8658076
--- /dev/null
+++ b/src/GraphQL.Client.TestHost/GraphQL.Client.TestHost.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net461;netstandard2.1
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/GraphQL.Client.TestHost/TestServerExtensions.cs b/src/GraphQL.Client.TestHost/TestServerExtensions.cs
new file mode 100644
index 00000000..10054f1b
--- /dev/null
+++ b/src/GraphQL.Client.TestHost/TestServerExtensions.cs
@@ -0,0 +1,21 @@
+using System;
+using GraphQL.Client.Abstractions.Websocket;
+using GraphQL.Client.Http;
+using Microsoft.AspNetCore.TestHost;
+
+namespace GraphQL.Client.TestHost
+{
+ public static class TestServerExtensions
+ {
+ public static GraphQLHttpClient CreateGraphQLHttpClient(this TestServer server, GraphQLHttpClientOptions options, IGraphQLWebsocketJsonSerializer serializer)
+ {
+ var testWebSocketClient = server.CreateWebSocketClient();
+ testWebSocketClient.ConfigureRequest = r =>
+ {
+ r.Headers["Sec-WebSocket-Protocol"] = "graphql-ws";
+ };
+
+ return new GraphQLHttpClient(options, serializer, server.CreateClient(), (uri, token) => testWebSocketClient.ConnectAsync(uri, token));
+ }
+ }
+}
diff --git a/src/GraphQL.Client/GraphQLHttpClient.cs b/src/GraphQL.Client/GraphQLHttpClient.cs
index 9d2aac47..ada1e7f8 100644
--- a/src/GraphQL.Client/GraphQLHttpClient.cs
+++ b/src/GraphQL.Client/GraphQLHttpClient.cs
@@ -5,12 +5,15 @@
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
+using System.Net.WebSockets;
+using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using GraphQL.Client.Abstractions;
using GraphQL.Client.Abstractions.Websocket;
using GraphQL.Client.Http.Websocket;
-
+[assembly:InternalsVisibleTo("GraphQL.Client.TestHost")]
+[assembly:InternalsVisibleTo("GraphQL.Integration.Tests")]
namespace GraphQL.Client.Http
{
public class GraphQLHttpClient : IGraphQLClient
@@ -63,6 +66,11 @@ public GraphQLHttpClient(GraphQLHttpClientOptions options, IGraphQLWebsocketJson
_disposeHttpClient = true;
}
+ internal GraphQLHttpClient(GraphQLHttpClientOptions options, IGraphQLWebsocketJsonSerializer serializer, HttpClient httpClient, Func> connectedWebSocketFactory):this(options,serializer,httpClient)
+ {
+ _lazyHttpWebSocket = new Lazy(()=>CreateGraphQLHttpWebSocket(connectedWebSocketFactory));
+ }
+
public GraphQLHttpClient(GraphQLHttpClientOptions options, IGraphQLWebsocketJsonSerializer serializer, HttpClient httpClient)
{
Options = options ?? throw new ArgumentNullException(nameof(options));
@@ -72,7 +80,7 @@ public GraphQLHttpClient(GraphQLHttpClientOptions options, IGraphQLWebsocketJson
if (!HttpClient.DefaultRequestHeaders.UserAgent.Any())
HttpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(GetType().Assembly.GetName().Name, GetType().Assembly.GetName().Version.ToString()));
- _lazyHttpWebSocket = new Lazy(CreateGraphQLHttpWebSocket);
+ _lazyHttpWebSocket = new Lazy(()=>CreateGraphQLHttpWebSocket());
}
#endregion
@@ -162,7 +170,7 @@ private async Task> SendHttpRequestAsync>? connectedSocketFactory=null)
{
if(Options.WebSocketEndPoint is null && Options.EndPoint is null)
throw new InvalidOperationException("no endpoint configured");
@@ -171,7 +179,7 @@ private GraphQLHttpWebSocket CreateGraphQLHttpWebSocket()
if (!webSocketEndpoint.HasWebSocketScheme())
throw new InvalidOperationException($"uri \"{webSocketEndpoint}\" is not a websocket endpoint");
- return new GraphQLHttpWebSocket(webSocketEndpoint, this);
+ return new GraphQLHttpWebSocket(webSocketEndpoint, this,connectedSocketFactory);
}
#endregion
diff --git a/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs b/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs
index ec4ac4b7..47d8cb48 100644
--- a/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs
+++ b/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs
@@ -39,11 +39,7 @@ internal class GraphQLHttpWebSocket : IDisposable
private Task _initializeWebSocketTask = Task.CompletedTask;
private readonly object _initializeLock = new object();
-#if NETFRAMEWORK
- private WebSocket _clientWebSocket = null;
-#else
- private ClientWebSocket _clientWebSocket = null;
-#endif
+ private WebSocket _clientWebSocket = null;
#endregion
@@ -83,6 +79,25 @@ public GraphQLHttpWebSocket(Uri webSocketUri, GraphQLHttpClient client)
.Select(request => Observable.FromAsync(() => SendWebSocketRequestAsync(request)))
.Concat()
.Subscribe();
+
+ _connectedWebSocketFactory = async (uri, token) =>
+ {
+#if NETFRAMEWORK
+ var socket = InitializeNetClientWebSocket();
+#else
+ var socket = InitializeNetCoreClientWebSocket();
+#endif
+ Debug.WriteLine($"opening websocket {socket.GetHashCode()} (thread {Thread.CurrentThread.ManagedThreadId})");
+ await socket.ConnectAsync(uri, token);
+ return socket;
+
+ };
+
+ }
+ internal GraphQLHttpWebSocket(Uri webSocketUri, GraphQLHttpClient client, Func>? connectedWebSocketFactory):this(webSocketUri, client)
+ {
+ if(connectedWebSocketFactory!=null)
+ _connectedWebSocketFactory = connectedWebSocketFactory;
}
#region Send requests
@@ -379,71 +394,77 @@ public Task InitializeWebSocket()
// else (re-)create websocket and connect
_clientWebSocket?.Dispose();
-
+ return _initializeWebSocketTask = ConnectAsync(_internalCancellationToken);
+ }
+ }
#if NETFRAMEWORK
- // fix websocket not supported on win 7 using
- // https://github.com/PingmanTools/System.Net.WebSockets.Client.Managed
- _clientWebSocket = SystemClientWebSocket.CreateClientWebSocket();
- switch (_clientWebSocket) {
- case ClientWebSocket nativeWebSocket:
- nativeWebSocket.Options.AddSubProtocol("graphql-ws");
- nativeWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates;
- nativeWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials;
- Options.ConfigureWebsocketOptions(nativeWebSocket.Options);
- break;
- case System.Net.WebSockets.Managed.ClientWebSocket managedWebSocket:
- managedWebSocket.Options.AddSubProtocol("graphql-ws");
- managedWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates;
- managedWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials;
- break;
- default:
- throw new NotSupportedException($"unknown websocket type {_clientWebSocket.GetType().Name}");
- }
+ private WebSocket InitializeNetClientWebSocket()
+ {
+ // fix websocket not supported on win 7 using
+ // https://github.com/PingmanTools/System.Net.WebSockets.Client.Managed
+ var socket = SystemClientWebSocket.CreateClientWebSocket();
+ switch (socket) {
+ case ClientWebSocket nativeWebSocket:
+ nativeWebSocket.Options.AddSubProtocol("graphql-ws");
+ nativeWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates;
+ nativeWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials;
+ Options.ConfigureWebsocketOptions(nativeWebSocket.Options);
+ break;
+ case System.Net.WebSockets.Managed.ClientWebSocket managedWebSocket:
+ managedWebSocket.Options.AddSubProtocol("graphql-ws");
+ managedWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates;
+ managedWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials;
+ break;
+ default:
+ throw new NotSupportedException($"unknown websocket type {socket.GetType().Name}");
+ }
+ return socket;
+ }
#else
- _clientWebSocket = new ClientWebSocket();
- _clientWebSocket.Options.AddSubProtocol("graphql-ws");
-
- // the following properties are not supported in Blazor WebAssembly and throw a PlatformNotSupportedException error when accessed
- try
- {
- _clientWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates;
- }
- catch (NotImplementedException)
- {
- Debug.WriteLine("property 'ClientWebSocketOptions.ClientCertificates' not implemented by current platform");
- }
- catch (PlatformNotSupportedException)
- {
- Debug.WriteLine("property 'ClientWebSocketOptions.ClientCertificates' not supported by current platform");
- }
+ private ClientWebSocket InitializeNetCoreClientWebSocket()
+ {
+ var webSocket = new ClientWebSocket();
+ webSocket.Options.AddSubProtocol("graphql-ws");
- try
- {
- _clientWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials;
- }
- catch (NotImplementedException)
- {
- Debug.WriteLine("property 'ClientWebSocketOptions.UseDefaultCredentials' not implemented by current platform");
- }
- catch (PlatformNotSupportedException)
- {
- Debug.WriteLine("Property 'ClientWebSocketOptions.UseDefaultCredentials' not supported by current platform");
- }
+ // the following properties are not supported in Blazor WebAssembly and throw a PlatformNotSupportedException error when accessed
+ try
+ {
+ webSocket.Options.ClientCertificates = ((HttpClientHandler) Options.HttpMessageHandler).ClientCertificates;
+ }
+ catch (NotImplementedException)
+ {
+ Debug.WriteLine("property 'ClientWebSocketOptions.ClientCertificates' not implemented by current platform");
+ }
+ catch (PlatformNotSupportedException)
+ {
+ Debug.WriteLine("property 'ClientWebSocketOptions.ClientCertificates' not supported by current platform");
+ }
- Options.ConfigureWebsocketOptions(_clientWebSocket.Options);
-#endif
- return _initializeWebSocketTask = ConnectAsync(_internalCancellationToken);
+ try
+ {
+ webSocket.Options.UseDefaultCredentials =
+ ((HttpClientHandler) Options.HttpMessageHandler).UseDefaultCredentials;
+ }
+ catch (NotImplementedException)
+ {
+ Debug.WriteLine("property 'ClientWebSocketOptions.UseDefaultCredentials' not implemented by current platform");
+ }
+ catch (PlatformNotSupportedException)
+ {
+ Debug.WriteLine("Property 'ClientWebSocketOptions.UseDefaultCredentials' not supported by current platform");
}
- }
+ Options.ConfigureWebsocketOptions(webSocket.Options);
+ return webSocket;
+ }
+#endif
private async Task ConnectAsync(CancellationToken token)
{
try
{
await BackOff();
_stateSubject.OnNext(GraphQLWebsocketConnectionState.Connecting);
- Debug.WriteLine($"opening websocket {_clientWebSocket.GetHashCode()} (thread {Thread.CurrentThread.ManagedThreadId})");
- await _clientWebSocket.ConnectAsync(_webSocketUri, token);
+ _clientWebSocket = await _connectedWebSocketFactory(_webSocketUri, token);
_stateSubject.OnNext(GraphQLWebsocketConnectionState.Connected);
Debug.WriteLine($"connection established on websocket {_clientWebSocket.GetHashCode()}, invoking Options.OnWebsocketConnected()");
await (Options.OnWebsocketConnected?.Invoke(_client) ?? Task.CompletedTask);
@@ -608,8 +629,6 @@ private async Task ReceiveWebsocketMessagesAsync()
return response;
case WebSocketMessageType.Close:
- var closeResponse = await _client.JsonSerializer.DeserializeToWebsocketResponseWrapperAsync(ms);
- closeResponse.MessageBytes = ms.ToArray();
Debug.WriteLine($"Connection closed by the server.");
throw new Exception("Connection closed by the server.");
@@ -670,6 +689,7 @@ public void Complete()
public Task? Completion { get; private set; }
private readonly object _completedLocker = new object();
+ private readonly Func> _connectedWebSocketFactory;
private async Task CompleteAsync()
{
Debug.WriteLine("disposing GraphQLHttpWebSocket...");
diff --git a/tests/GraphQL.Integration.Tests/GraphQL.Integration.Tests.csproj b/tests/GraphQL.Integration.Tests/GraphQL.Integration.Tests.csproj
index 6aca8a5b..facb750c 100644
--- a/tests/GraphQL.Integration.Tests/GraphQL.Integration.Tests.csproj
+++ b/tests/GraphQL.Integration.Tests/GraphQL.Integration.Tests.csproj
@@ -7,6 +7,7 @@
+
@@ -14,6 +15,7 @@
+
diff --git a/tests/GraphQL.Integration.Tests/Helpers/IntegrationServerTestFixture.cs b/tests/GraphQL.Integration.Tests/Helpers/IntegrationServerTestFixture.cs
index 25773b47..f13c67cc 100644
--- a/tests/GraphQL.Integration.Tests/Helpers/IntegrationServerTestFixture.cs
+++ b/tests/GraphQL.Integration.Tests/Helpers/IntegrationServerTestFixture.cs
@@ -14,7 +14,7 @@ public abstract class IntegrationServerTestFixture
{
public int Port { get; private set; }
- public IWebHost Server { get; private set; }
+ public IWebHost Server { get; protected set; }
public abstract IGraphQLWebsocketJsonSerializer Serializer { get; }
@@ -23,7 +23,7 @@ public IntegrationServerTestFixture()
Port = NetworkHelpers.GetFreeTcpPortNumber();
}
- public async Task CreateServer()
+ public virtual async Task CreateServer()
{
if (Server != null)
return;
@@ -46,21 +46,11 @@ public GraphQLHttpClient GetStarWarsClient(bool requestsViaWebsocket = false)
public GraphQLHttpClient GetChatClient(bool requestsViaWebsocket = false)
=> GetGraphQLClient(Common.CHAT_ENDPOINT, requestsViaWebsocket);
- private GraphQLHttpClient GetGraphQLClient(string endpoint, bool requestsViaWebsocket = false)
+ protected virtual GraphQLHttpClient GetGraphQLClient(string endpoint, bool requestsViaWebsocket = false)
{
if (Serializer == null)
throw new InvalidOperationException("JSON serializer not configured");
return WebHostHelpers.GetGraphQLClient(Port, endpoint, requestsViaWebsocket, Serializer);
}
}
-
- public class NewtonsoftIntegrationServerTestFixture : IntegrationServerTestFixture
- {
- public override IGraphQLWebsocketJsonSerializer Serializer { get; } = new NewtonsoftJsonSerializer();
- }
-
- public class SystemTextJsonIntegrationServerTestFixture : IntegrationServerTestFixture
- {
- public override IGraphQLWebsocketJsonSerializer Serializer { get; } = new SystemTextJsonSerializer();
- }
}
diff --git a/tests/GraphQL.Integration.Tests/Helpers/NewtonsoftIntegrationServerTestFixture.cs b/tests/GraphQL.Integration.Tests/Helpers/NewtonsoftIntegrationServerTestFixture.cs
new file mode 100644
index 00000000..317a295f
--- /dev/null
+++ b/tests/GraphQL.Integration.Tests/Helpers/NewtonsoftIntegrationServerTestFixture.cs
@@ -0,0 +1,10 @@
+using GraphQL.Client.Abstractions.Websocket;
+using GraphQL.Client.Serializer.Newtonsoft;
+
+namespace GraphQL.Integration.Tests.Helpers
+{
+ public class NewtonsoftIntegrationServerTestFixture : IntegrationServerTestFixture
+ {
+ public override IGraphQLWebsocketJsonSerializer Serializer { get; } = new NewtonsoftJsonSerializer();
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphQL.Integration.Tests/Helpers/SystemTextJsonIntegrationServerTestFixture.cs b/tests/GraphQL.Integration.Tests/Helpers/SystemTextJsonIntegrationServerTestFixture.cs
new file mode 100644
index 00000000..a971825c
--- /dev/null
+++ b/tests/GraphQL.Integration.Tests/Helpers/SystemTextJsonIntegrationServerTestFixture.cs
@@ -0,0 +1,10 @@
+using GraphQL.Client.Abstractions.Websocket;
+using GraphQL.Client.Serializer.SystemTextJson;
+
+namespace GraphQL.Integration.Tests.Helpers
+{
+ public class SystemTextJsonIntegrationServerTestFixture : IntegrationServerTestFixture
+ {
+ public override IGraphQLWebsocketJsonSerializer Serializer { get; } = new SystemTextJsonSerializer();
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphQL.Integration.Tests/Helpers/TestServerTestFixture.cs b/tests/GraphQL.Integration.Tests/Helpers/TestServerTestFixture.cs
new file mode 100644
index 00000000..dac5b37f
--- /dev/null
+++ b/tests/GraphQL.Integration.Tests/Helpers/TestServerTestFixture.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+using GraphQL.Client.Http;
+using GraphQL.Client.TestHost;
+using IntegrationTestServer;
+using MartinCostello.Logging.XUnit;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.TestHost;
+using Microsoft.Extensions.Logging;
+using Xunit.Abstractions;
+
+namespace GraphQL.Integration.Tests.Helpers
+{
+ public abstract class TestServerTestFixture : IntegrationServerTestFixture
+ {
+ private TestServer _testServer;
+ public ITestOutputHelper Output { get; set; }
+ public override async Task CreateServer()
+ {
+ var host =
+ new WebHostBuilder()
+ .UseStartup()
+ .ConfigureLogging((ctx, logging) =>
+ {
+ logging.AddProvider(new XUnitLoggerProvider(Output, new XUnitLoggerOptions()));
+ logging.SetMinimumLevel(LogLevel.Trace);
+ });
+
+ _testServer = new TestServer(host);
+ Server = _testServer.Host;
+ await _testServer.Host.StartAsync();
+ }
+
+ protected override GraphQLHttpClient GetGraphQLClient(string endpoint, bool requestsViaWebsocket = false)
+ {
+ if (Serializer == null)
+ throw new InvalidOperationException("JSON serializer not configured");
+
+ return _testServer.CreateGraphQLHttpClient(new GraphQLHttpClientOptions
+ {
+ EndPoint = new Uri($"http://localhost:{Port}{endpoint}"),
+ UseWebSocketForQueriesAndMutations = requestsViaWebsocket
+ },
+ Serializer);
+ }
+ }
+}
diff --git a/tests/GraphQL.Integration.Tests/Helpers/TestServerTestNewtonsoftFixture.cs b/tests/GraphQL.Integration.Tests/Helpers/TestServerTestNewtonsoftFixture.cs
new file mode 100644
index 00000000..aee9df82
--- /dev/null
+++ b/tests/GraphQL.Integration.Tests/Helpers/TestServerTestNewtonsoftFixture.cs
@@ -0,0 +1,10 @@
+using GraphQL.Client.Abstractions.Websocket;
+using GraphQL.Client.Serializer.Newtonsoft;
+
+namespace GraphQL.Integration.Tests.Helpers
+{
+ public class TestServerTestNewtonsoftFixture : TestServerTestFixture
+ {
+ public override IGraphQLWebsocketJsonSerializer Serializer { get; } = new NewtonsoftJsonSerializer();
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphQL.Integration.Tests/Helpers/TestServerTestSystemTextFixture.cs b/tests/GraphQL.Integration.Tests/Helpers/TestServerTestSystemTextFixture.cs
new file mode 100644
index 00000000..6a208b9c
--- /dev/null
+++ b/tests/GraphQL.Integration.Tests/Helpers/TestServerTestSystemTextFixture.cs
@@ -0,0 +1,10 @@
+using GraphQL.Client.Abstractions.Websocket;
+using GraphQL.Client.Serializer.SystemTextJson;
+
+namespace GraphQL.Integration.Tests.Helpers
+{
+ public class TestServerTestSystemTextFixture : TestServerTestFixture
+ {
+ public override IGraphQLWebsocketJsonSerializer Serializer { get; } = new SystemTextJsonSerializer();
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphQL.Integration.Tests/WebsocketTests/Base.cs b/tests/GraphQL.Integration.Tests/WebsocketTests/Base.cs
index 4bedde89..71cc610a 100644
--- a/tests/GraphQL.Integration.Tests/WebsocketTests/Base.cs
+++ b/tests/GraphQL.Integration.Tests/WebsocketTests/Base.cs
@@ -1,16 +1,12 @@
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
-using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using FluentAssertions.Execution;
-using FluentAssertions.Extensions;
using GraphQL.Client.Abstractions;
-using GraphQL.Client.Abstractions.Websocket;
using GraphQL.Client.Http;
using GraphQL.Client.Tests.Common.Chat;
using GraphQL.Client.Tests.Common.Chat.Schema;
@@ -81,7 +77,7 @@ public async void CanUseWebSocketScheme()
response.Errors.Should().BeNullOrEmpty();
response.Data.AddMessage.Content.Should().Be(message);
}
-
+
[Fact]
public async void CanUseDedicatedWebSocketEndpoint()
{
@@ -94,7 +90,7 @@ public async void CanUseDedicatedWebSocketEndpoint()
response.Errors.Should().BeNullOrEmpty();
response.Data.AddMessage.Content.Should().Be(message);
}
-
+
[Fact]
public async void CanUseDedicatedWebSocketEndpointWithoutHttpEndpoint()
{
@@ -161,7 +157,7 @@ public async void CanHandleRequestErrorViaWebsocket()
}
}";
- private readonly GraphQLRequest _subscriptionRequest = new GraphQLRequest(SUBSCRIPTION_QUERY);
+ protected readonly GraphQLRequest _subscriptionRequest = new GraphQLRequest(SUBSCRIPTION_QUERY);
[Fact]
@@ -360,79 +356,6 @@ public async void CanConnectTwoSubscriptionsSimultaneously()
}
- [Fact]
- public async void CanHandleConnectionTimeout()
- {
- var errorMonitor = new CallbackMonitor();
- var reconnectBlocker = new ManualResetEventSlim(false);
-
- var callbackMonitor = ChatClient.ConfigureMonitorForOnWebsocketConnected();
- // configure back-off strategy to allow it to be controlled from within the unit test
- ChatClient.Options.BackOffStrategy = i =>
- {
- Debug.WriteLine("back-off strategy: waiting on reconnect blocker");
- reconnectBlocker.Wait();
- Debug.WriteLine("back-off strategy: reconnecting...");
- return TimeSpan.Zero;
- };
-
- var websocketStates = new ConcurrentQueue();
-
- using (ChatClient.WebsocketConnectionState.Subscribe(websocketStates.Enqueue))
- {
- websocketStates.Should().ContainSingle(state => state == GraphQLWebsocketConnectionState.Disconnected);
-
- Debug.WriteLine($"Test method thread id: {Thread.CurrentThread.ManagedThreadId}");
- Debug.WriteLine("creating subscription stream");
- var observable = ChatClient.CreateSubscriptionStream(_subscriptionRequest, errorMonitor.Invoke);
-
- Debug.WriteLine("subscribing...");
- var observer = observable.Observe();
- callbackMonitor.Should().HaveBeenInvokedWithPayload();
-
- websocketStates.Should().ContainInOrder(
- GraphQLWebsocketConnectionState.Disconnected,
- GraphQLWebsocketConnectionState.Connecting,
- GraphQLWebsocketConnectionState.Connected);
- // clear the collection so the next tests on the collection work as expected
- websocketStates.Clear();
-
- await observer.Should().PushAsync(1);
- observer.RecordedMessages.Last().Data.MessageAdded.Content.Should().Be(InitialMessage.Content);
-
- const string message1 = "Hello World";
- var response = await ChatClient.AddMessageAsync(message1);
- response.Data.AddMessage.Content.Should().Be(message1);
- await observer.Should().PushAsync(2);
- observer.RecordedMessages.Last().Data.MessageAdded.Content.Should().Be(message1);
-
- Debug.WriteLine("stopping web host...");
- await Fixture.ShutdownServer();
- Debug.WriteLine("web host stopped");
-
- errorMonitor.Should().HaveBeenInvokedWithPayload(10.Seconds())
- .Which.Should().BeOfType();
- websocketStates.Should().Contain(GraphQLWebsocketConnectionState.Disconnected);
-
- Debug.WriteLine("restarting web host...");
- await InitializeAsync();
- Debug.WriteLine("web host started");
- reconnectBlocker.Set();
- callbackMonitor.Should().HaveBeenInvokedWithPayload(3.Seconds());
- await observer.Should().PushAsync(3);
- observer.RecordedMessages.Last().Data.MessageAdded.Content.Should().Be(InitialMessage.Content);
-
- websocketStates.Should().ContainInOrder(
- GraphQLWebsocketConnectionState.Disconnected,
- GraphQLWebsocketConnectionState.Connecting,
- GraphQLWebsocketConnectionState.Connected);
-
- // disposing the client should complete the subscription
- ChatClient.Dispose();
- await observer.Should().CompleteAsync(5.Seconds());
- }
- }
-
[Fact]
public async void CanHandleSubscriptionError()
{
diff --git a/tests/GraphQL.Integration.Tests/WebsocketTests/BaseWithTimeout.cs b/tests/GraphQL.Integration.Tests/WebsocketTests/BaseWithTimeout.cs
new file mode 100644
index 00000000..37b70d0d
--- /dev/null
+++ b/tests/GraphQL.Integration.Tests/WebsocketTests/BaseWithTimeout.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.Linq;
+using System.Net.WebSockets;
+using System.Threading;
+using FluentAssertions;
+using FluentAssertions.Extensions;
+using GraphQL.Client.Abstractions.Websocket;
+using GraphQL.Client.Tests.Common.Chat;
+using GraphQL.Client.Tests.Common.FluentAssertions.Reactive;
+using GraphQL.Client.Tests.Common.Helpers;
+using GraphQL.Integration.Tests.Helpers;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace GraphQL.Integration.Tests.WebsocketTests
+{
+ public abstract class BaseWithTimeout:Base
+ {
+
+ protected BaseWithTimeout(ITestOutputHelper output, IntegrationServerTestFixture fixture) : base(output, fixture)
+ {
+ }
+
+ [Fact]
+ public async void CanHandleConnectionTimeout()
+ {
+ var errorMonitor = new CallbackMonitor();
+ var reconnectBlocker = new ManualResetEventSlim(false);
+
+ var callbackMonitor = ChatClient.ConfigureMonitorForOnWebsocketConnected();
+ // configure back-off strategy to allow it to be controlled from within the unit test
+ ChatClient.Options.BackOffStrategy = i =>
+ {
+ Debug.WriteLine("back-off strategy: waiting on reconnect blocker");
+ reconnectBlocker.Wait();
+ Debug.WriteLine("back-off strategy: reconnecting...");
+ return TimeSpan.Zero;
+ };
+
+ var websocketStates = new ConcurrentQueue();
+
+ using (ChatClient.WebsocketConnectionState.Subscribe(websocketStates.Enqueue))
+ {
+ websocketStates.Should().ContainSingle(state => state == GraphQLWebsocketConnectionState.Disconnected);
+
+ Debug.WriteLine($"Test method thread id: {Thread.CurrentThread.ManagedThreadId}");
+ Debug.WriteLine("creating subscription stream");
+ var observable = ChatClient.CreateSubscriptionStream(_subscriptionRequest, errorMonitor.Invoke);
+
+ Debug.WriteLine("subscribing...");
+ var observer = observable.Observe();
+ callbackMonitor.Should().HaveBeenInvokedWithPayload();
+
+ websocketStates.Should().ContainInOrder(
+ GraphQLWebsocketConnectionState.Disconnected,
+ GraphQLWebsocketConnectionState.Connecting,
+ GraphQLWebsocketConnectionState.Connected);
+ // clear the collection so the next tests on the collection work as expected
+ websocketStates.Clear();
+
+ await observer.Should().PushAsync(1);
+ observer.RecordedMessages.Last().Data.MessageAdded.Content.Should().Be(InitialMessage.Content);
+
+ const string message1 = "Hello World";
+ var response = await ChatClient.AddMessageAsync(message1);
+ response.Data.AddMessage.Content.Should().Be(message1);
+ await observer.Should().PushAsync(2);
+ observer.RecordedMessages.Last().Data.MessageAdded.Content.Should().Be(message1);
+
+ Debug.WriteLine("stopping web host...");
+ await Fixture.ShutdownServer();
+ Debug.WriteLine("web host stopped");
+
+ errorMonitor.Should().HaveBeenInvokedWithPayload(100.Seconds())
+ .Which.Should().BeOfType();
+ websocketStates.Should().Contain(GraphQLWebsocketConnectionState.Disconnected);
+
+ Debug.WriteLine("restarting web host...");
+ await InitializeAsync();
+ Debug.WriteLine("web host started");
+ reconnectBlocker.Set();
+ callbackMonitor.Should().HaveBeenInvokedWithPayload(3.Seconds());
+ await observer.Should().PushAsync(3);
+ observer.RecordedMessages.Last().Data.MessageAdded.Content.Should().Be(InitialMessage.Content);
+
+ websocketStates.Should().ContainInOrder(
+ GraphQLWebsocketConnectionState.Disconnected,
+ GraphQLWebsocketConnectionState.Connecting,
+ GraphQLWebsocketConnectionState.Connected);
+
+ // disposing the client should complete the subscription
+ ChatClient.Dispose();
+ await observer.Should().CompleteAsync(5.Seconds());
+ }
+ }
+ }
+}
diff --git a/tests/GraphQL.Integration.Tests/WebsocketTests/Newtonsoft.cs b/tests/GraphQL.Integration.Tests/WebsocketTests/Newtonsoft.cs
index d77ca14c..9fb7a5f8 100644
--- a/tests/GraphQL.Integration.Tests/WebsocketTests/Newtonsoft.cs
+++ b/tests/GraphQL.Integration.Tests/WebsocketTests/Newtonsoft.cs
@@ -4,7 +4,7 @@
namespace GraphQL.Integration.Tests.WebsocketTests
{
- public class Newtonsoft : Base, IClassFixture
+ public class Newtonsoft : BaseWithTimeout, IClassFixture
{
public Newtonsoft(ITestOutputHelper output, NewtonsoftIntegrationServerTestFixture fixture) : base(output, fixture)
{
diff --git a/tests/GraphQL.Integration.Tests/WebsocketTests/SystemTextJson.cs b/tests/GraphQL.Integration.Tests/WebsocketTests/SystemTextJson.cs
index ab4659a4..1cf9a44d 100644
--- a/tests/GraphQL.Integration.Tests/WebsocketTests/SystemTextJson.cs
+++ b/tests/GraphQL.Integration.Tests/WebsocketTests/SystemTextJson.cs
@@ -4,7 +4,7 @@
namespace GraphQL.Integration.Tests.WebsocketTests
{
- public class SystemTextJson : Base, IClassFixture
+ public class SystemTextJson : BaseWithTimeout, IClassFixture
{
public SystemTextJson(ITestOutputHelper output, SystemTextJsonIntegrationServerTestFixture fixture) : base(output, fixture)
{
diff --git a/tests/GraphQL.Integration.Tests/WebsocketTests/TestServerNewtonsoft.cs b/tests/GraphQL.Integration.Tests/WebsocketTests/TestServerNewtonsoft.cs
new file mode 100644
index 00000000..c694d559
--- /dev/null
+++ b/tests/GraphQL.Integration.Tests/WebsocketTests/TestServerNewtonsoft.cs
@@ -0,0 +1,14 @@
+using GraphQL.Integration.Tests.Helpers;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace GraphQL.Integration.Tests.WebsocketTests
+{
+ public class TestServerNewtonsoft : Base, IClassFixture
+ {
+ public TestServerNewtonsoft(ITestOutputHelper output, TestServerTestNewtonsoftFixture fixture) : base(output, fixture)
+ {
+ fixture.Output = output;
+ }
+ }
+}
diff --git a/tests/GraphQL.Integration.Tests/WebsocketTests/TestServerSystemTextJson.cs b/tests/GraphQL.Integration.Tests/WebsocketTests/TestServerSystemTextJson.cs
new file mode 100644
index 00000000..b6cd8395
--- /dev/null
+++ b/tests/GraphQL.Integration.Tests/WebsocketTests/TestServerSystemTextJson.cs
@@ -0,0 +1,14 @@
+using GraphQL.Integration.Tests.Helpers;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace GraphQL.Integration.Tests.WebsocketTests
+{
+ public class TestServerSystemTextJson : Base, IClassFixture
+ {
+ public TestServerSystemTextJson(ITestOutputHelper output, TestServerTestSystemTextFixture fixture) : base(output, fixture)
+ {
+ fixture.Output = output;
+ }
+ }
+}