Adding tests for SSE transport #413
This commit is contained in:
parent
bcefbae00c
commit
2854e868ec
|
|
@ -1,6 +1,6 @@
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26606.0
|
VisualStudioVersion = 15.0.26706.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DA69F624-5398-4884-87E4-B816698CDE65}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DA69F624-5398-4884-87E4-B816698CDE65}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -53,6 +53,7 @@ EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{6CEC3DC2-5B01-45A8-8F0D-8531315DA90B}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{6CEC3DC2-5B01-45A8-8F0D-8531315DA90B}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
test\Common\ChannelExtensions.cs = test\Common\ChannelExtensions.cs
|
test\Common\ChannelExtensions.cs = test\Common\ChannelExtensions.cs
|
||||||
|
test\Common\ServerFixture.cs = test\Common\ServerFixture.cs
|
||||||
test\Common\TaskExtensions.cs = test\Common\TaskExtensions.cs
|
test\Common\TaskExtensions.cs = test\Common\TaskExtensions.cs
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -203,4 +204,7 @@ Global
|
||||||
{B0243F99-2D3F-4CC6-AD71-E3F891B64724} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
{B0243F99-2D3F-4CC6-AD71-E3F891B64724} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
||||||
{E081EE41-D95F-4AD2-BC0B-4B562C0A2A47} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
{E081EE41-D95F-4AD2-BC0B-4B562C0A2A47} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {7945A4E4-ACDB-4F6E-95CA-6AC6E7C2CD59}
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
// Nothing should be writing to the HubConnectionContext
|
// Nothing should be writing to the HubConnectionContext
|
||||||
output.Out.TryComplete();
|
output.Out.TryComplete();
|
||||||
|
|
||||||
// This should unwind once we complete the output
|
// This should unwind once we complete the output
|
||||||
await writingOutputTask;
|
await writingOutputTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
||||||
case ServerSentEventsMessageParser.ParseResult.Incomplete:
|
case ServerSentEventsMessageParser.ParseResult.Incomplete:
|
||||||
if (result.IsCompleted)
|
if (result.IsCompleted)
|
||||||
{
|
{
|
||||||
throw new FormatException("Incomplete message");
|
throw new FormatException("Incomplete message.");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,18 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Xunit.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.SignalR.Tests
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR.Tests.Common
|
||||||
{
|
{
|
||||||
public class ServerFixture : IDisposable
|
public class ServerFixture<TStartup> : IDisposable
|
||||||
|
where TStartup : class
|
||||||
{
|
{
|
||||||
private ILoggerFactory _loggerFactory;
|
private ILoggerFactory _loggerFactory;
|
||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
|
|
@ -28,37 +27,21 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
|
|
||||||
public ServerFixture()
|
public ServerFixture()
|
||||||
{
|
{
|
||||||
var testLog = AssemblyTestLog.ForAssembly(typeof(ServerFixture).Assembly);
|
var testLog = AssemblyTestLog.ForAssembly(typeof(ServerFixture<TStartup>).Assembly);
|
||||||
_logToken = testLog.StartTestLog(null, typeof(ServerFixture).FullName, out _loggerFactory, "ServerFixture");
|
_logToken = testLog.StartTestLog(null, typeof(ServerFixture<TStartup>).FullName, out _loggerFactory, "ServerFixture");
|
||||||
_logger = _loggerFactory.CreateLogger<ServerFixture>();
|
_logger = _loggerFactory.CreateLogger<ServerFixture<TStartup>>();
|
||||||
|
|
||||||
StartServer();
|
StartServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Startup
|
|
||||||
{
|
|
||||||
public void ConfigureServices(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddSockets();
|
|
||||||
services.AddSignalR();
|
|
||||||
services.AddEndPoint<EchoEndPoint>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
|
||||||
{
|
|
||||||
app.UseSockets(options => options.MapEndPoint<EchoEndPoint>("echo"));
|
|
||||||
app.UseSignalR(options => options.MapHub<UncreatableHub>("uncreatable"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartServer()
|
private void StartServer()
|
||||||
{
|
{
|
||||||
host = new WebHostBuilder()
|
host = new WebHostBuilder()
|
||||||
.ConfigureLogging(builder => builder.AddProvider(new ForwardingLoggerProvider(_loggerFactory)))
|
.ConfigureLogging(builder => builder.AddProvider(new ForwardingLoggerProvider(_loggerFactory)))
|
||||||
|
.UseStartup(typeof(TStartup))
|
||||||
.UseKestrel()
|
.UseKestrel()
|
||||||
.UseUrls(BaseUrl)
|
.UseUrls(BaseUrl)
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
.UseStartup<Startup>()
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var t = Task.Run(() => host.Start());
|
var t = Task.Run(() => host.Start());
|
||||||
|
|
@ -86,6 +69,26 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Shutting down test server");
|
_logger.LogInformation("Shutting down test server");
|
||||||
host.Dispose();
|
host.Dispose();
|
||||||
|
_loggerFactory.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ForwardingLoggerProvider : ILoggerProvider
|
||||||
|
{
|
||||||
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
|
|
||||||
|
public ForwardingLoggerProvider(ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
_loggerFactory = loggerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILogger CreateLogger(string categoryName)
|
||||||
|
{
|
||||||
|
return _loggerFactory.CreateLogger(categoryName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,240 +3,264 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reactive.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Threading.Tasks.Channels;
|
using System.Threading.Tasks.Channels;
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
||||||
using Microsoft.AspNetCore.SignalR.Tests.Common;
|
using Microsoft.AspNetCore.SignalR.Tests.Common;
|
||||||
using Microsoft.AspNetCore.Sockets;
|
using Microsoft.AspNetCore.Sockets;
|
||||||
using Microsoft.AspNetCore.Sockets.Client;
|
using Microsoft.AspNetCore.Sockets.Client;
|
||||||
using Microsoft.AspNetCore.TestHost;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Console;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
||||||
{
|
{
|
||||||
public class HubConnectionTests : IDisposable
|
[CollectionDefinition(Name)]
|
||||||
|
public class HubConnectionTestsCollection : ICollectionFixture<ServerFixture<Startup>>
|
||||||
{
|
{
|
||||||
private readonly TestServer _testServer;
|
public const string Name = "EndToEndTests";
|
||||||
private static readonly bool _verbose = string.Equals(Environment.GetEnvironmentVariable("SIGNALR_TEST_VERBOSE"), "1");
|
}
|
||||||
|
|
||||||
public HubConnectionTests()
|
[Collection(HubConnectionTestsCollection.Name)]
|
||||||
|
public class HubConnectionTests : LoggedTest
|
||||||
|
{
|
||||||
|
private readonly ServerFixture<Startup> _serverFixture;
|
||||||
|
public HubConnectionTests(ServerFixture<Startup> serverFixture, ITestOutputHelper output)
|
||||||
|
: base(output)
|
||||||
{
|
{
|
||||||
var webHostBuilder = new WebHostBuilder().
|
if (serverFixture == null)
|
||||||
ConfigureServices(services =>
|
{
|
||||||
|
throw new ArgumentNullException(nameof(serverFixture));
|
||||||
|
}
|
||||||
|
|
||||||
|
_serverFixture = serverFixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(HubProtocolsXTransports))]
|
||||||
|
public async Task CheckFixedMessage(IHubProtocol protocol, TransportType transport)
|
||||||
|
{
|
||||||
|
using (StartLog(out var loggerFactory))
|
||||||
|
{
|
||||||
|
var httpConnection = new HttpConnection(new Uri(_serverFixture.BaseUrl + "/hubs"), transport, loggerFactory);
|
||||||
|
var connection = new HubConnection(httpConnection, protocol, loggerFactory);
|
||||||
|
try
|
||||||
{
|
{
|
||||||
services.AddSignalR();
|
await connection.StartAsync().OrTimeout();
|
||||||
})
|
|
||||||
.ConfigureLogging(loggerFactory =>
|
var result = await connection.InvokeAsync<string>(nameof(TestHub.HelloWorld)).OrTimeout();
|
||||||
|
|
||||||
|
Assert.Equal("Hello World!", result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (_verbose)
|
loggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "Exception from test");
|
||||||
{
|
throw;
|
||||||
loggerFactory.AddConsole();
|
}
|
||||||
}
|
finally
|
||||||
})
|
|
||||||
.Configure(app =>
|
|
||||||
{
|
{
|
||||||
app.UseSignalR(routes =>
|
await connection.DisposeAsync().OrTimeout();
|
||||||
{
|
}
|
||||||
routes.MapHub<TestHub>("hubs");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
_testServer = new TestServer(webHostBuilder);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[MemberData(nameof(HubProtocols))]
|
|
||||||
public async Task CheckFixedMessage(IHubProtocol protocol)
|
|
||||||
{
|
|
||||||
var loggerFactory = CreateLogger();
|
|
||||||
|
|
||||||
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
|
|
||||||
var connection = new HubConnection(httpConnection, protocol, loggerFactory);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await connection.StartAsync();
|
|
||||||
|
|
||||||
var result = await connection.InvokeAsync<string>(nameof(TestHub.HelloWorld));
|
|
||||||
|
|
||||||
Assert.Equal("Hello World!", result);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
await connection.DisposeAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(HubProtocols))]
|
[MemberData(nameof(HubProtocolsXTransports))]
|
||||||
public async Task CanSendAndReceiveMessage(IHubProtocol protocol)
|
public async Task CanSendAndReceiveMessage(IHubProtocol protocol, TransportType transport)
|
||||||
{
|
{
|
||||||
var loggerFactory = CreateLogger();
|
using (StartLog(out var loggerFactory))
|
||||||
const string originalMessage = "SignalR";
|
|
||||||
|
|
||||||
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
|
|
||||||
var connection = new HubConnection(httpConnection, protocol, loggerFactory);
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
await connection.StartAsync();
|
const string originalMessage = "SignalR";
|
||||||
|
|
||||||
var result = await connection.InvokeAsync<string>(nameof(TestHub.Echo), originalMessage);
|
var httpConnection = new HttpConnection(new Uri(_serverFixture.BaseUrl + "/hubs"), transport, loggerFactory);
|
||||||
|
var connection = new HubConnection(httpConnection, protocol, loggerFactory);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await connection.StartAsync().OrTimeout();
|
||||||
|
|
||||||
Assert.Equal(originalMessage, result);
|
var result = await connection.InvokeAsync<string>(nameof(TestHub.Echo), originalMessage).OrTimeout();
|
||||||
}
|
|
||||||
finally
|
Assert.Equal(originalMessage, result);
|
||||||
{
|
}
|
||||||
await connection.DisposeAsync();
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
loggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "Exception from test");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await connection.DisposeAsync().OrTimeout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(HubProtocols))]
|
[MemberData(nameof(HubProtocolsXTransports))]
|
||||||
public async Task MethodsAreCaseInsensitive(IHubProtocol protocol)
|
public async Task MethodsAreCaseInsensitive(IHubProtocol protocol, TransportType transport)
|
||||||
{
|
{
|
||||||
var loggerFactory = CreateLogger();
|
using (StartLog(out var loggerFactory))
|
||||||
const string originalMessage = "SignalR";
|
|
||||||
|
|
||||||
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
|
|
||||||
var connection = new HubConnection(httpConnection, protocol, loggerFactory);
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
await connection.StartAsync();
|
const string originalMessage = "SignalR";
|
||||||
|
|
||||||
var result = await connection.InvokeAsync<string>(nameof(TestHub.Echo).ToLowerInvariant(), originalMessage);
|
var httpConnection = new HttpConnection(new Uri(_serverFixture.BaseUrl + "/hubs"), transport, loggerFactory);
|
||||||
|
var connection = new HubConnection(httpConnection, protocol, loggerFactory);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await connection.StartAsync().OrTimeout();
|
||||||
|
|
||||||
Assert.Equal(originalMessage, result);
|
var result = await connection.InvokeAsync<string>(nameof(TestHub.Echo).ToLowerInvariant(), originalMessage).OrTimeout();
|
||||||
}
|
|
||||||
finally
|
Assert.Equal(originalMessage, result);
|
||||||
{
|
}
|
||||||
await connection.DisposeAsync();
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
loggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "Exception from test");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await connection.DisposeAsync().OrTimeout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(HubProtocols))]
|
[MemberData(nameof(HubProtocolsXTransports))]
|
||||||
public async Task CanInvokeClientMethodFromServer(IHubProtocol protocol)
|
public async Task CanInvokeClientMethodFromServer(IHubProtocol protocol, TransportType transport)
|
||||||
{
|
{
|
||||||
var loggerFactory = CreateLogger();
|
using (StartLog(out var loggerFactory))
|
||||||
const string originalMessage = "SignalR";
|
|
||||||
|
|
||||||
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
|
|
||||||
var connection = new HubConnection(httpConnection, protocol, loggerFactory);
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
await connection.StartAsync();
|
const string originalMessage = "SignalR";
|
||||||
|
|
||||||
var tcs = new TaskCompletionSource<string>();
|
var httpConnection = new HttpConnection(new Uri(_serverFixture.BaseUrl + "/hubs"), transport, loggerFactory);
|
||||||
connection.On<string>("Echo", tcs.SetResult);
|
var connection = new HubConnection(httpConnection, protocol, loggerFactory);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await connection.StartAsync().OrTimeout();
|
||||||
|
|
||||||
await connection.InvokeAsync(nameof(TestHub.CallEcho), originalMessage).OrTimeout();
|
var tcs = new TaskCompletionSource<string>();
|
||||||
|
connection.On<string>("Echo", tcs.SetResult);
|
||||||
|
|
||||||
Assert.Equal(originalMessage, await tcs.Task.OrTimeout());
|
await connection.InvokeAsync(nameof(TestHub.CallEcho), originalMessage).OrTimeout();
|
||||||
}
|
|
||||||
finally
|
Assert.Equal(originalMessage, await tcs.Task.OrTimeout());
|
||||||
{
|
}
|
||||||
await connection.DisposeAsync().OrTimeout();
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
loggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "Exception from test");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await connection.DisposeAsync().OrTimeout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(HubProtocols))]
|
[MemberData(nameof(HubProtocolsXTransports))]
|
||||||
public async Task CanStreamClientMethodFromServer(IHubProtocol protocol)
|
public async Task CanStreamClientMethodFromServer(IHubProtocol protocol, TransportType transport)
|
||||||
{
|
{
|
||||||
var loggerFactory = CreateLogger();
|
using (StartLog(out var loggerFactory))
|
||||||
|
|
||||||
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
|
|
||||||
var connection = new HubConnection(httpConnection, protocol, loggerFactory);
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
await connection.StartAsync();
|
var httpConnection = new HttpConnection(new Uri(_serverFixture.BaseUrl + "/hubs"), transport, loggerFactory);
|
||||||
|
var connection = new HubConnection(httpConnection, protocol, loggerFactory);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await connection.StartAsync().OrTimeout();
|
||||||
|
|
||||||
var tcs = new TaskCompletionSource<string>();
|
var tcs = new TaskCompletionSource<string>();
|
||||||
|
|
||||||
var results = await connection.Stream<string>(nameof(TestHub.Stream)).ReadAllAsync().OrTimeout();
|
var results = await connection.Stream<string>(nameof(TestHub.Stream)).ReadAllAsync().OrTimeout();
|
||||||
|
|
||||||
Assert.Equal(new[] { "a", "b", "c" }, results.ToArray());
|
Assert.Equal(new[] { "a", "b", "c" }, results.ToArray());
|
||||||
}
|
}
|
||||||
finally
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await connection.DisposeAsync().OrTimeout();
|
loggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "Exception from test");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await connection.DisposeAsync().OrTimeout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(HubProtocols))]
|
[MemberData(nameof(HubProtocolsXTransports))]
|
||||||
public async Task ServerClosesConnectionIfHubMethodCannotBeResolved(IHubProtocol hubProtocol)
|
public async Task ServerClosesConnectionIfHubMethodCannotBeResolved(IHubProtocol hubProtocol, TransportType transport)
|
||||||
{
|
{
|
||||||
var loggerFactory = CreateLogger();
|
using (StartLog(out var loggerFactory))
|
||||||
|
|
||||||
var httpConnection = new HttpConnection(new Uri("http://test/hubs"), TransportType.LongPolling, loggerFactory, _testServer.CreateHandler());
|
|
||||||
var connection = new HubConnection(httpConnection, hubProtocol, loggerFactory);
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
await connection.StartAsync();
|
var httpConnection = new HttpConnection(new Uri(_serverFixture.BaseUrl + "/hubs"), transport, loggerFactory);
|
||||||
|
var connection = new HubConnection(httpConnection, hubProtocol, loggerFactory);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await connection.StartAsync().OrTimeout();
|
||||||
|
|
||||||
var ex = await Assert.ThrowsAnyAsync<Exception>(
|
var ex = await Assert.ThrowsAnyAsync<Exception>(
|
||||||
async () => await connection.InvokeAsync("!@#$%"));
|
async () => await connection.InvokeAsync("!@#$%")).OrTimeout();
|
||||||
|
|
||||||
Assert.Equal("Unknown hub method '!@#$%'", ex.Message);
|
Assert.Equal("Unknown hub method '!@#$%'", ex.Message);
|
||||||
}
|
}
|
||||||
finally
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await connection.DisposeAsync();
|
loggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "Exception from test");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await connection.DisposeAsync().OrTimeout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<object[]> HubProtocols() =>
|
public static IEnumerable<object []> HubProtocolsXTransports()
|
||||||
new[]
|
{
|
||||||
|
foreach (var protocol in HubProtocols)
|
||||||
{
|
{
|
||||||
new object[] { new JsonHubProtocol(new JsonSerializer()) },
|
foreach (var transport in TransportTypes())
|
||||||
new object[] { new MessagePackHubProtocol() },
|
{
|
||||||
|
yield return new object[] { protocol, transport };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<IHubProtocol> HubProtocols =>
|
||||||
|
new IHubProtocol[]
|
||||||
|
{
|
||||||
|
new JsonHubProtocol(new JsonSerializer()),
|
||||||
|
new MessagePackHubProtocol(),
|
||||||
};
|
};
|
||||||
|
|
||||||
public void Dispose()
|
public static IEnumerable<TransportType> TransportTypes()
|
||||||
{
|
{
|
||||||
_testServer.Dispose();
|
if (WebsocketsSupported())
|
||||||
}
|
|
||||||
|
|
||||||
private static ILoggerFactory CreateLogger()
|
|
||||||
{
|
|
||||||
var serviceCollection = new ServiceCollection();
|
|
||||||
|
|
||||||
serviceCollection.AddLogging(builder =>
|
|
||||||
{
|
{
|
||||||
builder.AddConsole();
|
// TODO: Currently we are always sending Text messages over websockets which does not work
|
||||||
builder.AddFilter<ConsoleLoggerProvider>(level => level >= (_verbose ? LogLevel.Trace : LogLevel.Error));
|
// with binary protocols. It is getting fixed separately.
|
||||||
builder.AddDebug();
|
// The tests are also failing on full framework when using WebSockets transport
|
||||||
});
|
// due to: https://github.com/aspnet/SignalR/issues/568
|
||||||
|
// yield return TransportType.WebSockets;
|
||||||
return serviceCollection.BuildServiceProvider().GetRequiredService<ILoggerFactory>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TestHub : Hub
|
|
||||||
{
|
|
||||||
public string HelloWorld()
|
|
||||||
{
|
|
||||||
return "Hello World!";
|
|
||||||
}
|
}
|
||||||
|
yield return TransportType.ServerSentEvents;
|
||||||
|
yield return TransportType.LongPolling;
|
||||||
|
|
||||||
public string Echo(string message)
|
bool WebsocketsSupported()
|
||||||
{
|
{
|
||||||
return message;
|
try
|
||||||
}
|
{
|
||||||
|
new System.Net.WebSockets.ClientWebSocket();
|
||||||
|
}
|
||||||
|
catch (PlatformNotSupportedException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task CallEcho(string message)
|
return true;
|
||||||
{
|
|
||||||
await Clients.Client(Context.ConnectionId).InvokeAsync("Echo", message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IObservable<string> Stream()
|
|
||||||
{
|
|
||||||
return new[] { "a", "b", "c" }.ToObservable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
||||||
|
{
|
||||||
|
public class TestHub : Hub
|
||||||
|
{
|
||||||
|
public string HelloWorld()
|
||||||
|
{
|
||||||
|
return "Hello World!";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Echo(string message)
|
||||||
|
{
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CallEcho(string message)
|
||||||
|
{
|
||||||
|
await Clients.Client(Context.ConnectionId).InvokeAsync("Echo", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IObservable<string> Stream()
|
||||||
|
{
|
||||||
|
return new[] { "a", "b", "c" }.ToObservable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,10 +4,13 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||||
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT'">netcoreapp2.0</TargetFrameworks>
|
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT'">netcoreapp2.0</TargetFrameworks>
|
||||||
|
|
||||||
|
<RuntimeIdentifier Condition="'$(TargetFramework)' != 'netcoreapp2.0'">win7-x64</RuntimeIdentifier>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="..\Common\ServerFixture.cs" Link="ServerFixture.cs" />
|
||||||
<Compile Include="..\Common\TaskExtensions.cs" Link="TaskExtensions.cs" />
|
<Compile Include="..\Common\TaskExtensions.cs" Link="TaskExtensions.cs" />
|
||||||
<Compile Include="..\Common\ChannelExtensions.cs" Link="ChannelExtensions.cs" />
|
<Compile Include="..\Common\ChannelExtensions.cs" Link="ChannelExtensions.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
@ -22,8 +25,7 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="$(AspNetCoreVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Http" Version="$(AspNetCoreVersion)" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(AspNetCoreVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(AspNetCoreVersion)" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="$(AspNetCoreVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="$(AspNetCoreVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(AspNetCoreVersion)" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(AspNetCoreVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(AspNetCoreVersion)" />
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
|
||||||
<PackageReference Include="xunit" Version="$(XunitVersion)" />
|
<PackageReference Include="xunit" Version="$(XunitVersion)" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSignalR();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
app.UseSignalR(routes =>
|
||||||
|
{
|
||||||
|
routes.MapHub<TestHub>("hubs");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,6 @@ using System.Threading.Tasks.Channels;
|
||||||
using Microsoft.AspNetCore.SignalR.Tests.Common;
|
using Microsoft.AspNetCore.SignalR.Tests.Common;
|
||||||
using Microsoft.AspNetCore.Sockets.Client;
|
using Microsoft.AspNetCore.Sockets.Client;
|
||||||
using Microsoft.AspNetCore.Sockets.Internal;
|
using Microsoft.AspNetCore.Sockets.Internal;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Moq.Protected;
|
using Moq.Protected;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Threading.Tasks.Channels;
|
using System.Threading.Tasks.Channels;
|
||||||
|
using Microsoft.AspNetCore.Client.Tests;
|
||||||
using Microsoft.AspNetCore.SignalR.Tests.Common;
|
using Microsoft.AspNetCore.SignalR.Tests.Common;
|
||||||
using Microsoft.AspNetCore.Sockets.Client;
|
using Microsoft.AspNetCore.Sockets.Client;
|
||||||
using Microsoft.AspNetCore.Sockets.Internal;
|
using Microsoft.AspNetCore.Sockets.Internal;
|
||||||
|
|
@ -61,5 +64,219 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
||||||
copyToAsyncTcs.SetResult(0);
|
copyToAsyncTcs.SetResult(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SSETransportStopsSendAndReceiveLoopsWhenTransportStopped()
|
||||||
|
{
|
||||||
|
var eventStreamCts = new CancellationTokenSource();
|
||||||
|
var mockHttpHandler = new Mock<HttpMessageHandler>();
|
||||||
|
mockHttpHandler.Protected()
|
||||||
|
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
|
||||||
|
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
|
||||||
|
var mockStream = new Mock<Stream>();
|
||||||
|
mockStream
|
||||||
|
.Setup(s => s.CopyToAsync(It.IsAny<Stream>(), It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Returns<Stream, int, CancellationToken>(async (stream, bufferSize, t) =>
|
||||||
|
{
|
||||||
|
var buffer = Encoding.ASCII.GetBytes("data: 3:abc\r\n\r\n");
|
||||||
|
while (!eventStreamCts.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
await stream.WriteAsync(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new HttpResponseMessage { Content = new StreamContent(mockStream.Object) };
|
||||||
|
});
|
||||||
|
|
||||||
|
Task transportActiveTask;
|
||||||
|
|
||||||
|
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||||
|
{
|
||||||
|
var sseTransport = new ServerSentEventsTransport(httpClient);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||||
|
var transportToConnection = Channel.CreateUnbounded<byte[]>();
|
||||||
|
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
|
||||||
|
await sseTransport.StartAsync(
|
||||||
|
new Uri("http://fakeuri.org"), channelConnection, connectionId: string.Empty).OrTimeout();
|
||||||
|
|
||||||
|
transportActiveTask = sseTransport.Running;
|
||||||
|
Assert.False(transportActiveTask.IsCompleted);
|
||||||
|
var message = await transportToConnection.In.ReadAsync().AsTask().OrTimeout();
|
||||||
|
Assert.Equal("3:abc", Encoding.ASCII.GetString(message));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await sseTransport.StopAsync().OrTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
await transportActiveTask.OrTimeout();
|
||||||
|
eventStreamCts.Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SSETransportStopsWithErrorIfServerSendsIncompleteResults()
|
||||||
|
{
|
||||||
|
var mockHttpHandler = new Mock<HttpMessageHandler>();
|
||||||
|
mockHttpHandler.Protected()
|
||||||
|
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
|
||||||
|
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
|
||||||
|
var mockStream = new Mock<Stream>();
|
||||||
|
mockStream
|
||||||
|
.Setup(s => s.CopyToAsync(It.IsAny<Stream>(), It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Returns<Stream, int, CancellationToken>(async (stream, bufferSize, t) =>
|
||||||
|
{
|
||||||
|
var buffer = Encoding.ASCII.GetBytes("data: 3:a");
|
||||||
|
await stream.WriteAsync(buffer, 0, buffer.Length);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new HttpResponseMessage { Content = new StreamContent(mockStream.Object) };
|
||||||
|
});
|
||||||
|
|
||||||
|
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||||
|
{
|
||||||
|
var sseTransport = new ServerSentEventsTransport(httpClient);
|
||||||
|
|
||||||
|
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||||
|
var transportToConnection = Channel.CreateUnbounded<byte[]>();
|
||||||
|
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
|
||||||
|
await sseTransport.StartAsync(
|
||||||
|
new Uri("http://fakeuri.org"), channelConnection, connectionId: string.Empty).OrTimeout();
|
||||||
|
|
||||||
|
var exception = await Assert.ThrowsAsync<FormatException>(() => sseTransport.Running.OrTimeout());
|
||||||
|
Assert.Equal("Incomplete message.", exception.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SSETransportStopsWithErrorIfSendingMessageFails()
|
||||||
|
{
|
||||||
|
var eventStreamTcs = new TaskCompletionSource<object>();
|
||||||
|
var copyToAsyncTcs = new TaskCompletionSource<int>();
|
||||||
|
|
||||||
|
var mockHttpHandler = new Mock<HttpMessageHandler>();
|
||||||
|
mockHttpHandler.Protected()
|
||||||
|
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
|
||||||
|
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
|
||||||
|
if (request.Headers.Accept?.Contains(new MediaTypeWithQualityHeaderValue("text/event-stream")) == true)
|
||||||
|
{
|
||||||
|
// Receive loop started - allow stopping the transport
|
||||||
|
eventStreamTcs.SetResult(null);
|
||||||
|
|
||||||
|
// returns unfinished task to block pipelines
|
||||||
|
var mockStream = new Mock<Stream>();
|
||||||
|
mockStream
|
||||||
|
.Setup(s => s.CopyToAsync(It.IsAny<Stream>(), It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Returns(copyToAsyncTcs.Task);
|
||||||
|
return new HttpResponseMessage { Content = new StreamContent(mockStream.Object) };
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseUtils.CreateResponse(System.Net.HttpStatusCode.InternalServerError);
|
||||||
|
});
|
||||||
|
|
||||||
|
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||||
|
{
|
||||||
|
var sseTransport = new ServerSentEventsTransport(httpClient);
|
||||||
|
|
||||||
|
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||||
|
var transportToConnection = Channel.CreateUnbounded<byte[]>();
|
||||||
|
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
|
||||||
|
|
||||||
|
await sseTransport.StartAsync(
|
||||||
|
new Uri("http://fakeuri.org"), channelConnection, connectionId: string.Empty).OrTimeout();
|
||||||
|
await eventStreamTcs.Task;
|
||||||
|
|
||||||
|
var sendTcs = new TaskCompletionSource<object>();
|
||||||
|
Assert.True(connectionToTransport.Out.TryWrite(new SendMessage(new byte[] { 0x42 }, sendTcs)));
|
||||||
|
|
||||||
|
var exception = await Assert.ThrowsAsync<HttpRequestException>(() => sendTcs.Task.OrTimeout());
|
||||||
|
Assert.Contains("500", exception.Message);
|
||||||
|
|
||||||
|
Assert.Same(exception, await Assert.ThrowsAsync<HttpRequestException>(() => sseTransport.Running.OrTimeout()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SSETransportStopsIfChannelClosed()
|
||||||
|
{
|
||||||
|
var eventStreamTcs = new TaskCompletionSource<object>();
|
||||||
|
var copyToAsyncTcs = new TaskCompletionSource<int>();
|
||||||
|
|
||||||
|
var mockHttpHandler = new Mock<HttpMessageHandler>();
|
||||||
|
mockHttpHandler.Protected()
|
||||||
|
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
|
||||||
|
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
|
||||||
|
// Receive loop started - allow stopping the transport
|
||||||
|
eventStreamTcs.SetResult(null);
|
||||||
|
|
||||||
|
// returns unfinished task to block pipelines
|
||||||
|
var mockStream = new Mock<Stream>();
|
||||||
|
mockStream
|
||||||
|
.Setup(s => s.CopyToAsync(It.IsAny<Stream>(), It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||||
|
.Returns(copyToAsyncTcs.Task);
|
||||||
|
return new HttpResponseMessage { Content = new StreamContent(mockStream.Object) };
|
||||||
|
});
|
||||||
|
|
||||||
|
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||||
|
{
|
||||||
|
var sseTransport = new ServerSentEventsTransport(httpClient);
|
||||||
|
|
||||||
|
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||||
|
var transportToConnection = Channel.CreateUnbounded<byte[]>();
|
||||||
|
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
|
||||||
|
|
||||||
|
await sseTransport.StartAsync(
|
||||||
|
new Uri("http://fakeuri.org"), channelConnection, connectionId: string.Empty).OrTimeout();
|
||||||
|
await eventStreamTcs.Task.OrTimeout();
|
||||||
|
|
||||||
|
connectionToTransport.Out.TryComplete(null);
|
||||||
|
|
||||||
|
await sseTransport.Running.OrTimeout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SSETransportStopsIfTheServerClosesTheStream()
|
||||||
|
{
|
||||||
|
var mockHttpHandler = new Mock<HttpMessageHandler>();
|
||||||
|
mockHttpHandler.Protected()
|
||||||
|
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
|
||||||
|
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
return new HttpResponseMessage { Content = new StringContent("data: 3:abc\r\n\r\n") };
|
||||||
|
});
|
||||||
|
|
||||||
|
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||||
|
{
|
||||||
|
var sseTransport = new ServerSentEventsTransport(httpClient);
|
||||||
|
|
||||||
|
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||||
|
var transportToConnection = Channel.CreateUnbounded<byte[]>();
|
||||||
|
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
|
||||||
|
await sseTransport.StartAsync(
|
||||||
|
new Uri("http://fakeuri.org"), channelConnection, connectionId: string.Empty).OrTimeout();
|
||||||
|
|
||||||
|
var message = await transportToConnection.In.ReadAsync().AsTask().OrTimeout();
|
||||||
|
Assert.Equal("3:abc", Encoding.ASCII.GetString(message));
|
||||||
|
|
||||||
|
await sseTransport.Running.OrTimeout();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ using Xunit.Abstractions;
|
||||||
namespace Microsoft.AspNetCore.SignalR.Tests
|
namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
{
|
{
|
||||||
[CollectionDefinition(Name)]
|
[CollectionDefinition(Name)]
|
||||||
public class EndToEndTestsCollection : ICollectionFixture<ServerFixture>
|
public class EndToEndTestsCollection : ICollectionFixture<ServerFixture<Startup>>
|
||||||
{
|
{
|
||||||
public const string Name = "EndToEndTests";
|
public const string Name = "EndToEndTests";
|
||||||
}
|
}
|
||||||
|
|
@ -29,9 +29,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
[Collection(EndToEndTestsCollection.Name)]
|
[Collection(EndToEndTestsCollection.Name)]
|
||||||
public class EndToEndTests : LoggedTest
|
public class EndToEndTests : LoggedTest
|
||||||
{
|
{
|
||||||
private readonly ServerFixture _serverFixture;
|
private readonly ServerFixture<Startup> _serverFixture;
|
||||||
|
|
||||||
public EndToEndTests(ServerFixture serverFixture, ITestOutputHelper output) : base(output)
|
public EndToEndTests(ServerFixture<Startup> serverFixture, ITestOutputHelper output) : base(output)
|
||||||
{
|
{
|
||||||
if (serverFixture == null)
|
if (serverFixture == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.SignalR.Tests
|
|
||||||
{
|
|
||||||
internal class ForwardingLoggerProvider : ILoggerProvider
|
|
||||||
{
|
|
||||||
private readonly ILoggerFactory _loggerFactory;
|
|
||||||
|
|
||||||
public ForwardingLoggerProvider(ILoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
_loggerFactory = loggerFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ILogger CreateLogger(string categoryName)
|
|
||||||
{
|
|
||||||
return _loggerFactory.CreateLogger(categoryName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -9,7 +9,6 @@ using System.Threading.Tasks.Channels;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
||||||
using Microsoft.AspNetCore.SignalR.Tests.Common;
|
using Microsoft.AspNetCore.SignalR.Tests.Common;
|
||||||
using Microsoft.AspNetCore.Sockets;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,11 @@
|
||||||
Remove when fixed.
|
Remove when fixed.
|
||||||
-->
|
-->
|
||||||
<HasRuntimeOutput>true</HasRuntimeOutput>
|
<HasRuntimeOutput>true</HasRuntimeOutput>
|
||||||
<RuntimeIdentifier Condition="'$(TargetFramework)' != 'netcoreapp2.0'">win7-x64</RuntimeIdentifier>
|
<RuntimeIdentifier Condition="'$(TargetFramework)' != 'netcoreapp2.0'">win7-x64</RuntimeIdentifier>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="..\Common\ServerFixture.cs" Link="ServerFixture.cs" />
|
||||||
<Compile Include="..\Common\TaskExtensions.cs" Link="TaskExtensions.cs" />
|
<Compile Include="..\Common\TaskExtensions.cs" Link="TaskExtensions.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSockets();
|
||||||
|
services.AddSignalR();
|
||||||
|
services.AddEndPoint<EchoEndPoint>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||||
|
{
|
||||||
|
app.UseSockets(options => options.MapEndPoint<EchoEndPoint>("echo"));
|
||||||
|
app.UseSignalR(options => options.MapHub<UncreatableHub>("uncreatable"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,9 +17,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
[Collection(EndToEndTestsCollection.Name)]
|
[Collection(EndToEndTestsCollection.Name)]
|
||||||
public class WebSocketsTransportTests : LoggedTest
|
public class WebSocketsTransportTests : LoggedTest
|
||||||
{
|
{
|
||||||
private readonly ServerFixture _serverFixture;
|
private readonly ServerFixture<Startup> _serverFixture;
|
||||||
|
|
||||||
public WebSocketsTransportTests(ServerFixture serverFixture, ITestOutputHelper output) : base(output)
|
public WebSocketsTransportTests(ServerFixture<Startup> serverFixture, ITestOutputHelper output) : base(output)
|
||||||
{
|
{
|
||||||
if (serverFixture == null)
|
if (serverFixture == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue