Added tests
This commit is contained in:
parent
e5e8d1bee3
commit
3032909f3c
|
|
@ -19,6 +19,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Socket
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ClientSample", "samples\ClientSample\ClientSample.xproj", "{BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{6A35B453-52EC-48AF-89CA-D4A69800F131}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Sockets.Tests", "test\Microsoft.AspNetCore.Sockets.Tests\Microsoft.AspNetCore.Sockets.Tests.xproj", "{AAD719D5-5E31-4ED1-A60F-6EB92EFA66D9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -37,6 +41,10 @@ Global
|
|||
{BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AAD719D5-5E31-4ED1-A60F-6EB92EFA66D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AAD719D5-5E31-4ED1-A60F-6EB92EFA66D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AAD719D5-5E31-4ED1-A60F-6EB92EFA66D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AAD719D5-5E31-4ED1-A60F-6EB92EFA66D9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -45,5 +53,6 @@ Global
|
|||
{C4AEAB04-F341-4539-B6C0-52368FB4BF9E} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
|
||||
{1715EA8D-8E13-4ACF-8BCA-57D048E55ED8} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
||||
{BA99C2A1-48F9-4FA5-B95A-9687A73B7CC9} = {C4BC9889-B49F-41B6-806B-F84941B2549B}
|
||||
{AAD719D5-5E31-4ED1-A60F-6EB92EFA66D9} = {6A35B453-52EC-48AF-89CA-D4A69800F131}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Sockets
|
|||
/// <summary>
|
||||
/// Represents an end point that multiple connections connect to. For HTTP, endpoints are URLs, for non HTTP it can be a TCP listener (or similar)
|
||||
/// </summary>
|
||||
public class EndPoint
|
||||
public abstract class EndPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// Live list of connections for this <see cref="EndPoint"/>
|
||||
|
|
@ -17,9 +17,6 @@ namespace Microsoft.AspNetCore.Sockets
|
|||
/// </summary>
|
||||
/// <param name="connection">The new <see cref="Connection"/></param>
|
||||
/// <returns>A <see cref="Task"/> that represents the connection lifetime. When the task completes, the connection is complete.</returns>
|
||||
public virtual Task OnConnected(Connection connection)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public abstract Task OnConnected(Connection connection);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,14 @@ namespace Microsoft.AspNetCore.Sockets
|
|||
{
|
||||
public class HttpConnectionDispatcher
|
||||
{
|
||||
private readonly ConnectionManager _manager = new ConnectionManager();
|
||||
private readonly ChannelFactory _channelFactory = new ChannelFactory();
|
||||
private readonly ConnectionManager _manager;
|
||||
private readonly ChannelFactory _channelFactory;
|
||||
|
||||
public HttpConnectionDispatcher(ConnectionManager manager, ChannelFactory factory)
|
||||
{
|
||||
_manager = manager;
|
||||
_channelFactory = factory;
|
||||
}
|
||||
|
||||
public async Task Execute<TEndPoint>(string path, HttpContext context) where TEndPoint : EndPoint
|
||||
{
|
||||
|
|
@ -201,7 +207,7 @@ namespace Microsoft.AspNetCore.Sockets
|
|||
return context.Request.Body.CopyToAsync(httpChannel.Input);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
throw new InvalidOperationException("Unknown connection id");
|
||||
}
|
||||
|
||||
private ConnectionState GetOrCreateConnection(HttpContext context)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Channels;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Sockets;
|
||||
using Microsoft.AspNetCore.Sockets.Routing;
|
||||
|
|
@ -9,7 +10,9 @@ namespace Microsoft.AspNetCore.Builder
|
|||
{
|
||||
public static IApplicationBuilder UseSockets(this IApplicationBuilder app, Action<SocketRouteBuilder> callback)
|
||||
{
|
||||
var dispatcher = new HttpConnectionDispatcher();
|
||||
var manager = new ConnectionManager();
|
||||
var factory = new ChannelFactory();
|
||||
var dispatcher = new HttpConnectionDispatcher(manager, factory);
|
||||
var routes = new RouteBuilder(app);
|
||||
|
||||
callback(new SocketRouteBuilder(routes, dispatcher));
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
},
|
||||
"frameworks": {
|
||||
"netstandard1.3": {
|
||||
}
|
||||
},
|
||||
"net46": { }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Channels;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Sockets.Tests
|
||||
{
|
||||
public class ConnectionManagerTests
|
||||
{
|
||||
[Fact]
|
||||
public void ReservedConnectionsHaveConnectionId()
|
||||
{
|
||||
var connectionManager = new ConnectionManager();
|
||||
var state = connectionManager.ReserveConnection();
|
||||
|
||||
Assert.NotNull(state.Connection);
|
||||
Assert.NotNull(state.Connection.ConnectionId);
|
||||
Assert.True(state.Active);
|
||||
Assert.Null(state.Close);
|
||||
Assert.Null(state.Connection.Channel);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReservedConnectionsCanBeRetrieved()
|
||||
{
|
||||
var connectionManager = new ConnectionManager();
|
||||
var state = connectionManager.ReserveConnection();
|
||||
|
||||
Assert.NotNull(state.Connection);
|
||||
Assert.NotNull(state.Connection.ConnectionId);
|
||||
|
||||
ConnectionState newState;
|
||||
Assert.True(connectionManager.TryGetConnection(state.Connection.ConnectionId, out newState));
|
||||
Assert.Same(newState, state);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddNewConnection()
|
||||
{
|
||||
using (var factory = new ChannelFactory())
|
||||
using (var channel = new HttpChannel(factory))
|
||||
{
|
||||
var connectionManager = new ConnectionManager();
|
||||
var state = connectionManager.AddNewConnection(channel);
|
||||
|
||||
Assert.NotNull(state.Connection);
|
||||
Assert.NotNull(state.Connection.ConnectionId);
|
||||
Assert.NotNull(state.Connection.Channel);
|
||||
|
||||
ConnectionState newState;
|
||||
Assert.True(connectionManager.TryGetConnection(state.Connection.ConnectionId, out newState));
|
||||
Assert.Same(newState, state);
|
||||
Assert.Same(channel, newState.Connection.Channel);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveConnection()
|
||||
{
|
||||
using (var factory = new ChannelFactory())
|
||||
using (var channel = new HttpChannel(factory))
|
||||
{
|
||||
var connectionManager = new ConnectionManager();
|
||||
var state = connectionManager.AddNewConnection(channel);
|
||||
|
||||
Assert.NotNull(state.Connection);
|
||||
Assert.NotNull(state.Connection.ConnectionId);
|
||||
Assert.NotNull(state.Connection.Channel);
|
||||
|
||||
ConnectionState newState;
|
||||
Assert.True(connectionManager.TryGetConnection(state.Connection.ConnectionId, out newState));
|
||||
Assert.Same(newState, state);
|
||||
Assert.Same(channel, newState.Connection.Channel);
|
||||
|
||||
connectionManager.RemoveConnection(state.Connection.ConnectionId);
|
||||
Assert.False(connectionManager.TryGetConnection(state.Connection.ConnectionId, out newState));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Channels;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Internal;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Sockets.Tests
|
||||
{
|
||||
public class HttpConnectionDispatcherTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task GetIdReservesConnectionIdAndReturnsIt()
|
||||
{
|
||||
var manager = new ConnectionManager();
|
||||
using (var factory = new ChannelFactory())
|
||||
{
|
||||
var dispatcher = new HttpConnectionDispatcher(manager, factory);
|
||||
var context = new DefaultHttpContext();
|
||||
var ms = new MemoryStream();
|
||||
context.Request.Path = "/getid";
|
||||
context.Response.Body = ms;
|
||||
await dispatcher.Execute<TestEndPoint>("", context);
|
||||
|
||||
var id = Encoding.UTF8.GetString(ms.ToArray());
|
||||
|
||||
ConnectionState state;
|
||||
Assert.True(manager.TryGetConnection(id, out state));
|
||||
Assert.Equal(id, state.Connection.ConnectionId);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendingToReservedConnectionsThatHaveNotConnectedThrows()
|
||||
{
|
||||
var manager = new ConnectionManager();
|
||||
var state = manager.ReserveConnection();
|
||||
|
||||
using (var factory = new ChannelFactory())
|
||||
{
|
||||
var dispatcher = new HttpConnectionDispatcher(manager, factory);
|
||||
var context = new DefaultHttpContext();
|
||||
context.Request.Path = "/send";
|
||||
var values = new Dictionary<string, StringValues>();
|
||||
values["id"] = state.Connection.ConnectionId;
|
||||
var qs = new QueryCollection(values);
|
||||
context.Request.Query = qs;
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
{
|
||||
await dispatcher.Execute<TestEndPoint>("", context);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendingToUnknownConnectionIdThrows()
|
||||
{
|
||||
var manager = new ConnectionManager();
|
||||
using (var factory = new ChannelFactory())
|
||||
{
|
||||
var dispatcher = new HttpConnectionDispatcher(manager, factory);
|
||||
var context = new DefaultHttpContext();
|
||||
context.Request.Path = "/send";
|
||||
var values = new Dictionary<string, StringValues>();
|
||||
values["id"] = "unknown";
|
||||
var qs = new QueryCollection(values);
|
||||
context.Request.Query = qs;
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
{
|
||||
await dispatcher.Execute<TestEndPoint>("", context);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendingWithoutConnectionIdThrows()
|
||||
{
|
||||
var manager = new ConnectionManager();
|
||||
using (var factory = new ChannelFactory())
|
||||
{
|
||||
var dispatcher = new HttpConnectionDispatcher(manager, factory);
|
||||
var context = new DefaultHttpContext();
|
||||
context.Request.Path = "/send";
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
{
|
||||
await dispatcher.Execute<TestEndPoint>("", context);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TestEndPoint : EndPoint
|
||||
{
|
||||
public override Task OnConnected(Connection connection)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Channels;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Sockets.Tests
|
||||
{
|
||||
public class LongPollingTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Set204StatusCodeWhenChannelComplete()
|
||||
{
|
||||
using (var factory = new ChannelFactory())
|
||||
{
|
||||
var connection = new Connection();
|
||||
connection.ConnectionId = Guid.NewGuid().ToString();
|
||||
var channel = new HttpChannel(factory);
|
||||
connection.Channel = channel;
|
||||
var context = new DefaultHttpContext();
|
||||
var poll = new LongPolling(connection);
|
||||
|
||||
channel.Output.CompleteWriter();
|
||||
|
||||
await poll.ProcessRequest(context);
|
||||
|
||||
Assert.Equal(204, context.Response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NoFramingAddedWhenDataSent()
|
||||
{
|
||||
using (var factory = new ChannelFactory())
|
||||
{
|
||||
var connection = new Connection();
|
||||
connection.ConnectionId = Guid.NewGuid().ToString();
|
||||
var channel = new HttpChannel(factory);
|
||||
connection.Channel = channel;
|
||||
var context = new DefaultHttpContext();
|
||||
var ms = new MemoryStream();
|
||||
context.Response.Body = ms;
|
||||
var poll = new LongPolling(connection);
|
||||
|
||||
await channel.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello World"));
|
||||
|
||||
channel.Output.CompleteWriter();
|
||||
|
||||
await poll.ProcessRequest(context);
|
||||
|
||||
Assert.Equal("Hello World", Encoding.UTF8.GetString(ms.ToArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>aad719d5-5e31-4ed1-a60f-6eb92efa66d9</ProjectGuid>
|
||||
<RootNamespace>Microsoft.AspNetCore.Sockets.Tests</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Microsoft.AspNetCore.Sockets.Tests")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("aad719d5-5e31-4ed1-a60f-6eb92efa66d9")]
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Channels;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Sockets.Tests
|
||||
{
|
||||
public class ServerSentEventsTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task SSESetsContentType()
|
||||
{
|
||||
using (var factory = new ChannelFactory())
|
||||
{
|
||||
var connection = new Connection();
|
||||
connection.ConnectionId = Guid.NewGuid().ToString();
|
||||
var channel = new HttpChannel(factory);
|
||||
connection.Channel = channel;
|
||||
var sse = new ServerSentEvents(connection);
|
||||
var context = new DefaultHttpContext();
|
||||
|
||||
channel.Output.CompleteWriter();
|
||||
|
||||
await sse.ProcessRequest(context);
|
||||
|
||||
Assert.Equal("text/event-stream", context.Response.ContentType);
|
||||
Assert.Equal("no-cache", context.Response.Headers["Cache-Control"]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SSEAddsAppropriateFraming()
|
||||
{
|
||||
using (var factory = new ChannelFactory())
|
||||
{
|
||||
var connection = new Connection();
|
||||
connection.ConnectionId = Guid.NewGuid().ToString();
|
||||
var channel = new HttpChannel(factory);
|
||||
connection.Channel = channel;
|
||||
var sse = new ServerSentEvents(connection);
|
||||
var context = new DefaultHttpContext();
|
||||
var ms = new MemoryStream();
|
||||
context.Response.Body = ms;
|
||||
|
||||
await channel.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello World"));
|
||||
|
||||
channel.Output.CompleteWriter();
|
||||
|
||||
await sse.ProcessRequest(context);
|
||||
|
||||
var expected = "data: Hello World\n\n";
|
||||
Assert.Equal(expected, Encoding.UTF8.GetString(ms.ToArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"buildOptions": {
|
||||
"warningsAsErrors": true
|
||||
},
|
||||
"dependencies": {
|
||||
"dotnet-test-xunit": "2.2.0-*",
|
||||
"Microsoft.AspNetCore.Http": "1.1.0-*",
|
||||
"Microsoft.AspNetCore.Sockets": {
|
||||
"target": "project"
|
||||
},
|
||||
"xunit": "2.2.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net46": {}
|
||||
},
|
||||
"testRunner": "xunit"
|
||||
}
|
||||
Loading…
Reference in New Issue