diff --git a/WebSockets.sln b/WebSockets.sln index 9101a12f9ea8..6b9df02739e1 100644 --- a/WebSockets.sln +++ b/WebSockets.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22013.1 +VisualStudioVersion = 14.0.22216.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestServer", "test\TestServer\TestServer.csproj", "{4E5F5FCC-172C-44D9-BEA0-39098A79CD0B}" EndProject @@ -28,6 +28,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution global.json = global.json EndProjectSection EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AutobahnTestServer", "test\AutobahnTestServer\AutobahnTestServer.kproj", "{C03C43FE-9201-48A6-B434-AD67EF627D67}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AutobahnTestClient", "test\AutobahnTestClient\AutobahnTestClient.kproj", "{BC4D2BB1-05A8-4816-8BC1-3A664F09EE32}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -62,6 +66,14 @@ Global {78A097D0-C0A4-4AED-93E2-84A65392FB52}.Debug|Any CPU.Build.0 = Debug|Any CPU {78A097D0-C0A4-4AED-93E2-84A65392FB52}.Release|Any CPU.ActiveCfg = Release|Any CPU {78A097D0-C0A4-4AED-93E2-84A65392FB52}.Release|Any CPU.Build.0 = Release|Any CPU + {C03C43FE-9201-48A6-B434-AD67EF627D67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C03C43FE-9201-48A6-B434-AD67EF627D67}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C03C43FE-9201-48A6-B434-AD67EF627D67}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C03C43FE-9201-48A6-B434-AD67EF627D67}.Release|Any CPU.Build.0 = Release|Any CPU + {BC4D2BB1-05A8-4816-8BC1-3A664F09EE32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC4D2BB1-05A8-4816-8BC1-3A664F09EE32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC4D2BB1-05A8-4816-8BC1-3A664F09EE32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC4D2BB1-05A8-4816-8BC1-3A664F09EE32}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -74,5 +86,7 @@ Global {4A1C4875-AE21-4A78-979A-F0E4DF5EB518} = {2C7947A5-9FBD-4267-97C1-2D726D7B3BAF} {6604D154-817F-4BC5-BE95-FF7E851179D9} = {C45106D0-76C8-4776-A140-F7DD83CA2958} {78A097D0-C0A4-4AED-93E2-84A65392FB52} = {2C7947A5-9FBD-4267-97C1-2D726D7B3BAF} + {C03C43FE-9201-48A6-B434-AD67EF627D67} = {C45106D0-76C8-4776-A140-F7DD83CA2958} + {BC4D2BB1-05A8-4816-8BC1-3A664F09EE32} = {C45106D0-76C8-4776-A140-F7DD83CA2958} EndGlobalSection EndGlobal diff --git a/test/AutobahnTestClient/AutobahnTestClient.kproj b/test/AutobahnTestClient/AutobahnTestClient.kproj new file mode 100644 index 000000000000..46b1cb9752ce --- /dev/null +++ b/test/AutobahnTestClient/AutobahnTestClient.kproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + bc4d2bb1-05a8-4816-8bc1-3a664f09ee32 + AutobahnTestClient + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + \ No newline at end of file diff --git a/test/AutobahnTestClient/Program.cs b/test/AutobahnTestClient/Program.cs new file mode 100644 index 000000000000..15300f825b06 --- /dev/null +++ b/test/AutobahnTestClient/Program.cs @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Open Technologies, Inc. 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.Net.WebSockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.WebSockets.Client; + +namespace AutobahnTestClient +{ + public class Program + { + public async Task Main(string[] args) + { + try + { + string serverAddress = "ws://localhost:9001"; + string agent = + "ManagedWebSockets"; + // "NativeWebSockets"; + + Console.WriteLine("Getting case count."); + var caseCount = await GetCaseCountAsync(serverAddress, agent); + Console.WriteLine(caseCount + " case(s)."); + + for (int i = 1; i <= caseCount; i++) + { + await RunCaseAsync(serverAddress, i, agent); + } + + await UpdateReportsAsync(serverAddress, agent); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + + Console.WriteLine("Done"); + Console.ReadLine(); + } + + private async Task ConnectAsync(string address, string agent) + { + if (string.Equals(agent, "NativeWebSockets")) + { + var client = new ClientWebSocket(); + await client.ConnectAsync(new Uri(address), CancellationToken.None); + return client; + } + else + { + // TODO: BUG: Require ws or wss schemes + var client = new WebSocketClient(); + return await client.ConnectAsync(new Uri(address), CancellationToken.None); + } + } + + private async Task GetCaseCountAsync(string serverAddress, string agent) + { + var webSocket = await ConnectAsync(serverAddress + "/getCaseCount", agent); + byte[] buffer = new byte[1024 * 4]; + var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); + var caseCountText = Encoding.UTF8.GetString(buffer, 0, result.Count); + return int.Parse(caseCountText); + } + + private async Task RunCaseAsync(string serverAddress, int caseId, string agent) + { + try + { + Console.WriteLine("Running case " + caseId); + var webSocket = await ConnectAsync(serverAddress + "/runCase?case=" + caseId + "&agent=" + agent, agent); + await Echo(webSocket); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + + private async Task Echo(WebSocket webSocket) + { + byte[] buffer = new byte[1024 * 4]; + var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + while (!result.CloseStatus.HasValue) + { + await webSocket.SendAsync(new ArraySegment(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); + result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + } + await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + } + + private async Task UpdateReportsAsync(string serverAddress, string agent) + { + var webSocket = await ConnectAsync(serverAddress + "/updateReports?agent=" + agent, agent); + await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); + } + } +} diff --git a/test/AutobahnTestClient/Project.json b/test/AutobahnTestClient/Project.json new file mode 100644 index 000000000000..ecb3dd00df3a --- /dev/null +++ b/test/AutobahnTestClient/Project.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "Microsoft.AspNet.WebSockets.Client": "1.0.0-*" + }, + "commands": { + "run" : "run" + }, + "frameworks" : { + "aspnet50" : { } + } +} diff --git a/test/AutobahnTestClient/ReadMe.txt b/test/AutobahnTestClient/ReadMe.txt new file mode 100644 index 000000000000..c49984330f5f --- /dev/null +++ b/test/AutobahnTestClient/ReadMe.txt @@ -0,0 +1,23 @@ +This test server is for use in testing client side implementations of the WebSocekt protocol. It is currently implemented to test +Microsoft.AspNet.WebSockets.Client.WebSocketClient and System.Net.WebSockets.ClientWebSocket. + +See http://autobahn.ws/ to download and install the test framework. + +Usage: +Run the test server: +"C:\Program Files\Python\2.7.6\Scripts\wstest" -d -m fuzzingserver -s fuzzingserver.json +Where fuzzingserver.json contains the following: + +{ + "url": "ws://127.0.0.1:9001", + + "options": {"failByDrop": false}, + "outdir": "./reports/clients", + "webport": 8080, + + "cases": ["*"], + "exclude-cases": [], + "exclude-agent-cases": {} +} + +Then run the client of your choice, taking care to update the serverAddress and agent fields in the client code. \ No newline at end of file diff --git a/test/AutobahnTestServer/AutobahnTestServer.kproj b/test/AutobahnTestServer/AutobahnTestServer.kproj new file mode 100644 index 000000000000..d8b0d383827b --- /dev/null +++ b/test/AutobahnTestServer/AutobahnTestServer.kproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + c03c43fe-9201-48a6-b434-ad67ef627d67 + AutobahnTestServer + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + 60351 + + + \ No newline at end of file diff --git a/test/AutobahnTestServer/Project.json b/test/AutobahnTestServer/Project.json new file mode 100644 index 000000000000..b1ac9e5da641 --- /dev/null +++ b/test/AutobahnTestServer/Project.json @@ -0,0 +1,14 @@ +{ + "webroot": "wwwroot", + "exclude": "wwwroot/**/*", + "dependencies": { + "Microsoft.AspNet.Server.IIS": "1.0.0-beta1-*", + "Microsoft.AspNet.Server.WebListener": "1.0.0-beta1-*", + "Microsoft.AspNet.WebSockets.Server": "1.0.0-beta1-*" + }, + "commands": { "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:12345" }, + "frameworks" : { + "aspnet50" : { }, + "aspnetcore50" : { } + } +} diff --git a/test/AutobahnTestServer/ReadMe.txt b/test/AutobahnTestServer/ReadMe.txt new file mode 100644 index 000000000000..0c0bb6837d7e --- /dev/null +++ b/test/AutobahnTestServer/ReadMe.txt @@ -0,0 +1,25 @@ +This test server is for use in testing server side implementations of the WebSocekt protocol. It should work with Helios, WebListener (native), +and the managed implementation of WebSockets in this project (running on WebListener, Kestrel, etc.). The tests only require that the server implement +a basic WebSocket accept and then echo any content received. + +See http://autobahn.ws/ to download and install the test framework. + +Usage: +Configure and start the server of your choice. +Run the test client: +"C:\Program Files\Python\2.7.6\Scripts\wstest.exe" -d -m fuzzingclient -s fuzzingclient.json +Where fussingclient.json contains: +{ + "options": {"failByDrop": false}, + "outdir": "./reports/servers", + + "servers": [ + {"agent": "NameOfImplementationBeingTested", + "url": "ws://localhost:12345", + "options": {"version": 18}} + ], + + "cases": ["*"], + "exclude-cases": [], + "exclude-agent-cases": {} +} \ No newline at end of file diff --git a/test/AutobahnTestServer/Startup.cs b/test/AutobahnTestServer/Startup.cs new file mode 100644 index 000000000000..1e17919b11e2 --- /dev/null +++ b/test/AutobahnTestServer/Startup.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Open Technologies, Inc. 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.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.WebSockets.Server; + +namespace AutobahnTestServer +{ + public class Startup + { + public void Configure(IApplicationBuilder app) + { + // Comment this out to test native server implementations + app.UseWebSockets(new WebSocketOptions() + { + ReplaceFeature = true, + }); + + app.Use(async (context, next) => + { + if (context.IsWebSocketRequest) + { + Console.WriteLine("Echo: " + context.Request.Path); + var webSocket = await context.AcceptWebSocketAsync(); + await Echo(webSocket); + return; + } + await next(); + }); + + app.Run(context => + { + Console.WriteLine("Hello World"); + return context.Response.WriteAsync("Hello World"); + }); + } + + private async Task Echo(WebSocket webSocket) + { + byte[] buffer = new byte[1024 * 4]; + var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + while (!result.CloseStatus.HasValue) + { + await webSocket.SendAsync(new ArraySegment(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); + result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + } + await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + } + } +}