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);
+ }
+ }
+}