public void ServerTransportCanSendMessages()
        {
            var logger = XUnitLogger.CreateLogger(_testOutput);

            using (var connection = new TestWebSocketConnectionFeature())
            {
                var server          = connection.AcceptAsync().GetAwaiter().GetResult();
                var client          = connection.Client;
                var receiverRunning = ReceiveAsync(client);

                var fromTransport = new Pipe(PipeOptions.Default);
                var toTransport   = new Pipe(PipeOptions.Default);

                var webSocketManager = new Mock <WebSocketManager>();
                webSocketManager.Setup(m => m.AcceptWebSocketAsync()).Returns(Task.FromResult(server));
                var httpContext = new Mock <HttpContext>();
                httpContext.Setup(c => c.WebSockets).Returns(webSocketManager.Object);

                var sut = new WebSocketTransport(httpContext.Object.WebSockets.AcceptWebSocketAsync().GetAwaiter().GetResult(), new DuplexPipe(toTransport.Reader, fromTransport.Writer), logger);
                var serverTransportRunning = sut.ConnectAsync(CancellationToken.None);

                var messages = new List <byte[]> {
                    Encoding.UTF8.GetBytes("foo")
                };
                WriteAsync(toTransport.Writer, messages).Wait();
                toTransport.Writer.CompleteAsync().GetAwaiter().GetResult();

                serverTransportRunning.Wait();

                var output = receiverRunning.GetAwaiter().GetResult();

                Assert.Equal("foo", Encoding.UTF8.GetString(output[0]));
            }
        }
        public async Task ServerTransportCanReceiveMessages()
        {
            var logger = XUnitLogger.CreateLogger(_testOutput);

            using (var connection = new TestWebSocketConnectionFeature())
            {
                var server = connection.AcceptAsync();
                var client = connection.Client;

                var fromTransport   = new Pipe(PipeOptions.Default);
                var toTransport     = new Pipe(PipeOptions.Default);
                var listenerRunning = ListenAsync(fromTransport.Reader);

                var webSocketManager = new Mock <WebSocketManager>();
                webSocketManager.Setup(m => m.AcceptWebSocketAsync()).Returns(server);
                var httpContext = new Mock <HttpContext>();
                httpContext.Setup(c => c.WebSockets).Returns(webSocketManager.Object);

                var sut = new WebSocketTransport(httpContext.Object.WebSockets.AcceptWebSocketAsync().GetAwaiter().GetResult(), new DuplexPipe(toTransport.Reader, fromTransport.Writer), logger);
                var serverTransportRunning = sut.ConnectAsync(CancellationToken.None);

                var messages = new List <byte[]> {
                    Encoding.UTF8.GetBytes("foo"), Encoding.UTF8.GetBytes("bar")
                };
                SendBinaryAsync(client, messages).Wait();
                client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Done sending.", CancellationToken.None).Wait();

                serverTransportRunning.Wait();

                var output = await listenerRunning;

                Assert.Equal("foo", Encoding.UTF8.GetString(output[0]));
                Assert.Equal("bar", Encoding.UTF8.GetString(output[1]));
            }
        }
Exemple #3
0
    public async Task TransportClosesOnCloseTimeoutIfClientDoesNotSendCloseFrame()
    {
        using (StartVerifiableLog())
        {
            var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
            var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)), pair.Transport, pair.Application, new());

            using (var feature = new TestWebSocketConnectionFeature())
            {
                var options = new WebSocketOptions()
                {
                    CloseTimeout = TimeSpan.FromSeconds(1)
                };

                var ws = new WebSocketsServerTransport(options, connection.Application, connection, LoggerFactory);

                var serverSocket = await feature.AcceptAsync();

                // Give the server socket to the transport and run it
                var transport = ws.ProcessSocketAsync(serverSocket);

                // End the app
                connection.Transport.Output.Complete();

                await transport.DefaultTimeout(TimeSpan.FromSeconds(10));

                // Now we're closed
                Assert.Equal(WebSocketState.Aborted, serverSocket.State);

                serverSocket.Dispose();
            }
        }
    }
        public async Task ServerGracefullyClosesWhenClientSendsCloseFrameThenApplicationEnds()
        {
            //using (StartVerifiableLog())
            {
                var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    var serverSocket = await feature.AcceptAsync();

                    var transport = new WebSocketTransport(serverSocket, pair.Application, NullLogger.Instance);

                    // Accept web socket, start receiving / sending at the transport level
                    var processTask = transport.ConnectAsync(CancellationToken.None);

                    // Start a socket client that will capture traffic for posterior analysis
                    var clientTask = feature.Client.ExecuteAndCaptureFramesAsync();

                    await feature.Client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None).TimeoutAfterAsync(TimeSpan.FromSeconds(5));

                    // close the client to server channel
                    pair.Transport.Output.Complete();

                    _ = await clientTask.TimeoutAfterAsync(TimeSpan.FromSeconds(5));

                    await processTask.TimeoutAfterAsync(TimeSpan.FromSeconds(5));

                    Assert.Equal(WebSocketCloseStatus.NormalClosure, serverSocket.CloseStatus);
                }
            }
        }
Exemple #5
0
    public async Task TransportFailsOnTimeoutWithErrorWhenApplicationFailsAndClientDoesNotSendCloseFrame()
    {
        using (StartVerifiableLog())
        {
            var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
            var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)), pair.Transport, pair.Application, new());

            using (var feature = new TestWebSocketConnectionFeature())
            {
                var options = new WebSocketOptions
                {
                    CloseTimeout = TimeSpan.FromSeconds(1)
                };

                var ws = new WebSocketsServerTransport(options, connection.Application, connection, LoggerFactory);

                var serverSocket = await feature.AcceptAsync();

                // Give the server socket to the transport and run it
                var transport = ws.ProcessSocketAsync(serverSocket);

                // Run the client socket
                var client = feature.Client.ExecuteAndCaptureFramesAsync();

                // fail the client to server channel
                connection.Transport.Output.Complete(new Exception());

                await transport.DefaultTimeout();

                Assert.Equal(WebSocketState.Aborted, serverSocket.State);
            }
        }
    }
        public async Task ClientReceivesInternalServerErrorWhenTheApplicationFails()
        {
            //using (StartVerifiableLog())
            {
                var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    var transport = new WebSocketTransport(await feature.AcceptAsync(), pair.Application, NullLogger.Instance);

                    // Accept web socket, start receiving / sending at the transport level
                    var processTask = transport.ConnectAsync(CancellationToken.None);

                    // Start a socket client that will capture traffic for posterior analysis
                    var clientTask = feature.Client.ExecuteAndCaptureFramesAsync();

                    // Fail in the app
                    pair.Transport.Output.Complete(new InvalidOperationException("Catastrophic failure."));
                    var clientSummary = await clientTask.TimeoutAfterAsync <WebSocketConnectionSummary>(TimeSpan.FromSeconds(5));

                    Assert.Equal(WebSocketCloseStatus.InternalServerError, clientSummary.CloseResult.CloseStatus);

                    // Close from the client
                    await feature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);

                    await processTask.TimeoutAfterAsync(TimeSpan.FromSeconds(5));
                }
            }
        }
        public async Task TransportFailsOnTimeoutWithErrorWhenApplicationFailsAndClientDoesNotSendCloseFrame()
        {
            //using (StartVerifiableLog())
            {
                var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    var serverSocket = await feature.AcceptAsync();

                    var transport = new WebSocketTransport(serverSocket, pair.Application, NullLogger.Instance);

                    // Accept web socket, start receiving / sending at the transport level
                    var processTask = transport.ConnectAsync(CancellationToken.None);

                    // Start a socket client that will capture traffic for posterior analysis
                    var clientTask = feature.Client.ExecuteAndCaptureFramesAsync();

                    // fail the client to server channel
                    pair.Transport.Output.Complete(new Exception());

                    await processTask.TimeoutAfterAsync(TimeSpan.FromSeconds(10));

                    Assert.Equal(WebSocketState.Aborted, serverSocket.State);
                }
            }
        }
Exemple #8
0
        public void ClientTransportCanReceiveMessages()
        {
            var logger = XUnitLogger.CreateLogger(_testOutput);

            using (var connection = new TestWebSocketConnectionFeature())
            {
                var server = connection.AcceptAsync().GetAwaiter().GetResult();
                var client = connection.Client;

                var fromTransport   = new Pipe(PipeOptions.Default);
                var toTransport     = new Pipe(PipeOptions.Default);
                var listenerRunning = ListenAsync(fromTransport.Reader);

                var sut = new WebSocketTransport(new DuplexPipe(toTransport.Reader, fromTransport.Writer), logger);
                var clientTransportRunning = sut.ProcessSocketAsync(client, CancellationToken.None);

                var messages = new List <byte[]> {
                    Encoding.UTF8.GetBytes("foo")
                };
                SendBinaryAsync(server, messages).Wait();
                server.CloseAsync(WebSocketCloseStatus.NormalClosure, "Done sending.", CancellationToken.None).Wait();

                clientTransportRunning.Wait();

                var output = listenerRunning.GetAwaiter().GetResult();

                Assert.Equal("foo", Encoding.UTF8.GetString(output[0]));
            }
        }
Exemple #9
0
    public async Task MultiSegmentSendWillNotSendEmptyEndOfMessageFrame()
    {
        using (var feature = new TestWebSocketConnectionFeature())
        {
            var serverSocket = await feature.AcceptAsync();

            var sequence = ReadOnlySequenceFactory.CreateSegments(new byte[] { 1 }, new byte[] { 15 });
            Assert.False(sequence.IsSingleSegment);

            await serverSocket.SendAsync(sequence, WebSocketMessageType.Text);

            // Run the client socket
            var client = feature.Client.ExecuteAndCaptureFramesAsync();

            await serverSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", default);

            var messages = await client.DefaultTimeout();

            Assert.Equal(2, messages.Received.Count);

            // First message: 1 byte, endOfMessage false
            Assert.Single(messages.Received[0].Buffer);
            Assert.Equal(1, messages.Received[0].Buffer[0]);
            Assert.False(messages.Received[0].EndOfMessage);

            // Second message: 1 byte, endOfMessage true
            Assert.Single(messages.Received[1].Buffer);
            Assert.Equal(15, messages.Received[1].Buffer[0]);
            Assert.True(messages.Received[1].EndOfMessage);
        }
    }
Exemple #10
0
    public async Task ClientReceivesInternalServerErrorWhenTheApplicationFails()
    {
        using (StartVerifiableLog())
        {
            var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
            var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)), pair.Transport, pair.Application, new());

            using (var feature = new TestWebSocketConnectionFeature())
            {
                var ws = new WebSocketsServerTransport(new WebSocketOptions(), connection.Application, connection, LoggerFactory);

                // Give the server socket to the transport and run it
                var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                // Run the client socket
                var client = feature.Client.ExecuteAndCaptureFramesAsync();

                // Fail in the app
                connection.Transport.Output.Complete(new InvalidOperationException("Catastrophic failure."));
                var clientSummary = await client.DefaultTimeout();

                Assert.Equal(WebSocketCloseStatus.InternalServerError, clientSummary.CloseResult.CloseStatus);

                // Close from the client
                await feature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);

                await transport.DefaultTimeout();
            }
        }
    }
        public void ClientTransportCanSendMessages()
        {
            var logger = XUnitLogger.CreateLogger(_testOutput);

            using (var connection = new TestWebSocketConnectionFeature())
            {
                var server          = connection.AcceptAsync().GetAwaiter().GetResult();
                var client          = connection.Client;
                var receiverRunning = ReceiveAsync(server);

                var fromTransport = new Pipe(PipeOptions.Default);
                var toTransport   = new Pipe(PipeOptions.Default);

                var sut = new WebSocketTransport(client, new DuplexPipe(toTransport.Reader, fromTransport.Writer), logger);
                var clientTransportRunning = sut.ConnectAsync(CancellationToken.None);

                var messages = new List <byte[]> {
                    Encoding.UTF8.GetBytes("foo")
                };
                WriteAsync(toTransport.Writer, messages).Wait();
                toTransport.Writer.CompleteAsync().GetAwaiter().GetResult();

                clientTransportRunning.Wait();

                var output = receiverRunning.GetAwaiter().GetResult();

                Assert.Equal("foo", Encoding.UTF8.GetString(output[0]));
            }
        }
Exemple #12
0
        public async Task Integration_KeepAlive()
        {
            // TODO: Transform this test into a theory and do multi-message, multi-thread, multi-client, etc.
            var logger = XUnitLogger.CreateLogger(_outputHelper);
            var cts    = new CancellationTokenSource();

            using (var webSocketFeature = new TestWebSocketConnectionFeature())
            {
                // Bot / server setup
                var botRequestHandler = new Mock <RequestHandler>();

                botRequestHandler
                .Setup(r => r.ProcessRequestAsync(It.IsAny <ReceiveRequest>(), null, null, CancellationToken.None))
                .ReturnsAsync(() => new StreamingResponse()
                {
                    StatusCode = 200
                });

                var socket = await webSocketFeature.AcceptAsync().ConfigureAwait(false);

                var connection = new WebSocketStreamingConnection(socket, logger);
                var serverTask = connection.ListenAsync(botRequestHandler.Object, cts.Token);

                // Client / channel setup
                var clientRequestHandler = new Mock <RequestHandler>();

                clientRequestHandler
                .Setup(r => r.ProcessRequestAsync(It.IsAny <ReceiveRequest>(), null, null, CancellationToken.None))
                .ReturnsAsync(() => new StreamingResponse()
                {
                    StatusCode = 200
                });

                var client = new WebSocketClient(webSocketFeature.Client, "wss://test", clientRequestHandler.Object, logger: logger, closeTimeOut: TimeSpan.FromSeconds(10), keepAlive: TimeSpan.FromMilliseconds(200));

                var clientTask = client.ConnectInternalAsync(CancellationToken.None);

                // Send request bot (server) -> channel (client)
                const string path = "api/version";
                const string botToClientPayload = "Hello human, I'm Bender!";
                var          request            = StreamingRequest.CreatePost(path, new StringContent(botToClientPayload));

                var responseFromClient = await connection.SendStreamingRequestAsync(request).ConfigureAwait(false);

                Assert.Equal(200, responseFromClient.StatusCode);

                const string clientToBotPayload = "Hello bot, I'm Calculon!";
                var          clientRequest      = StreamingRequest.CreatePost(path, new StringContent(clientToBotPayload));

                // Send request bot channel (client) -> (server)
                var clientToBotResult = await client.SendAsync(clientRequest).ConfigureAwait(false);

                Assert.Equal(200, clientToBotResult.StatusCode);

                await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);

                Assert.True(client.IsConnected);
            }
        }
Exemple #13
0
        public async Task Integration_Interop_LegacyClient()
        {
            // TODO: Transform this test into a theory and do multi-message, multi-thread, multi-client, etc.
            var logger = XUnitLogger.CreateLogger(_outputHelper);

            using (var webSocketFeature = new TestWebSocketConnectionFeature())
            {
                // Bot / server setup
                var botRequestHandler = new Mock <RequestHandler>();

                botRequestHandler
                .Setup(r => r.ProcessRequestAsync(It.IsAny <ReceiveRequest>(), null, null, CancellationToken.None))
                .ReturnsAsync(() => new StreamingResponse()
                {
                    StatusCode = 200
                });

                var socket = await webSocketFeature.AcceptAsync().ConfigureAwait(false);

                var connection = new WebSocketStreamingConnection(socket, logger);
                var serverTask = Task.Run(() => connection.ListenAsync(botRequestHandler.Object));

                // Client / channel setup
                var clientRequestHandler = new Mock <RequestHandler>();

                clientRequestHandler
                .Setup(r => r.ProcessRequestAsync(It.IsAny <ReceiveRequest>(), null, null, CancellationToken.None))
                .ReturnsAsync(() => new StreamingResponse()
                {
                    StatusCode = 200
                });

                using (var client = new Microsoft.Bot.Streaming.Transport.WebSockets.WebSocketClient("wss://test", clientRequestHandler.Object))
                {
                    await client.ConnectInternalAsync(webSocketFeature.Client).ConfigureAwait(false);

                    // Send request bot (server) -> channel (client)
                    const string path = "api/version";
                    const string botToClientPayload = "Hello human, I'm Bender!";
                    var          request            = StreamingRequest.CreatePost(path, new StringContent(botToClientPayload));

                    var responseFromClient = await connection.SendStreamingRequestAsync(request).ConfigureAwait(false);

                    Assert.Equal(200, responseFromClient.StatusCode);

                    const string clientToBotPayload = "Hello bot, I'm Calculon!";
                    var          clientRequest      = StreamingRequest.CreatePost(path, new StringContent(clientToBotPayload));

                    // Send request bot channel (client) -> (server)
                    var clientToBotResult = await client.SendAsync(clientRequest).ConfigureAwait(false);

                    Assert.Equal(200, clientToBotResult.StatusCode);
                    client.Disconnect();
                }

                await serverTask.ConfigureAwait(false);
            }
        }
        private void RunStreamingCrashTest(Action <WebSocket, TestWebSocketConnectionFeature.WebSocketChannel, WebSocketClient, CancellationTokenSource, CancellationTokenSource> induceCrash)
        {
            var logger = XUnitLogger.CreateLogger(_testOutput);

            var serverCts = new CancellationTokenSource();
            var clientCts = new CancellationTokenSource();

            using (var connection = new TestWebSocketConnectionFeature())
            {
                var webSocket       = connection.AcceptAsync().Result;
                var clientWebSocket = connection.Client;

                var bot = new StreamingTestBot((turnContext, cancellationToken) => Task.CompletedTask);

                var server        = new CloudAdapter(new StreamingTestBotFrameworkAuthentication(), logger);
                var serverRunning = server.ProcessAsync(CreateWebSocketUpgradeRequest(webSocket), new Mock <HttpResponse>().Object, bot, serverCts.Token);

                var clientRequestHandler = new Mock <RequestHandler>();
                clientRequestHandler
                .Setup(h => h.ProcessRequestAsync(It.IsAny <ReceiveRequest>(), It.IsAny <ILogger <RequestHandler> >(), It.IsAny <object>(), It.IsAny <CancellationToken>()))
                .Returns(Task.FromResult(StreamingResponse.OK()));
                using (var client = new WebSocketClient("wss://test", clientRequestHandler.Object, logger: logger))
                {
                    var clientRunning = client.ConnectInternalAsync(clientWebSocket, clientCts.Token);

                    var activity = new Activity
                    {
                        Id   = Guid.NewGuid().ToString("N"),
                        Type = ActivityTypes.Message,
                        From = new ChannelAccount {
                            Id = "testUser"
                        },
                        Conversation = new ConversationAccount {
                            Id = Guid.NewGuid().ToString("N")
                        },
                        Recipient = new ChannelAccount {
                            Id = "testBot"
                        },
                        ServiceUrl = "wss://InvalidServiceUrl/api/messages",
                        ChannelId  = "test",
                        Text       = "hi"
                    };

                    var content  = new StringContent(JsonConvert.SerializeObject(activity), Encoding.UTF8, "application/json");
                    var response = client.SendAsync(StreamingRequest.CreatePost("/api/messages", content)).Result;
                    Assert.Equal(200, response.StatusCode);

                    induceCrash(webSocket, clientWebSocket, client, serverCts, clientCts);

                    clientRunning.Wait();
                    Assert.True(clientRunning.IsCompletedSuccessfully);
                }

                serverRunning.Wait();
                Assert.True(serverRunning.IsCompletedSuccessfully);
            }
        }
Exemple #15
0
    public async Task TransportCommunicatesErrorToApplicationWhenClientDisconnectsAbnormally()
    {
        using (StartVerifiableLog())
        {
            var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
            var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger("HttpConnectionContext1"), pair.Transport, pair.Application, new());

            using (var feature = new TestWebSocketConnectionFeature())
            {
                async Task CompleteApplicationAfterTransportCompletes()
                {
                    try
                    {
                        // Wait until the transport completes so that we can end the application
                        var result = await connection.Transport.Input.ReadAsync();

                        connection.Transport.Input.AdvanceTo(result.Buffer.End);
                    }
                    catch (Exception ex)
                    {
                        Assert.IsType <WebSocketError>(ex);
                    }
                    finally
                    {
                        // Complete the application so that the connection unwinds without aborting
                        connection.Transport.Output.Complete();
                    }
                }

                var ws = new WebSocketsServerTransport(new WebSocketOptions(), connection.Application, connection, LoggerFactory);

                // Give the server socket to the transport and run it
                var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                // Run the client socket
                var client = feature.Client.ExecuteAndCaptureFramesAsync();

                // When the close frame is received, we complete the application so the send
                // loop unwinds
                _ = CompleteApplicationAfterTransportCompletes();

                // Terminate the client to server channel with an exception
                feature.Client.SendAbort();

                // Wait for the transport
                await transport.DefaultTimeout();

                await client.DefaultTimeout();
            }
        }
    }
        public async Task TransportCommunicatesErrorToApplicationWhenClientDisconnectsAbnormally()
        {
            //using (StartVerifiableLog())
            {
                var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    async Task CompleteApplicationAfterTransportCompletes()
                    {
                        try
                        {
                            // Wait until the transport completes so that we can end the application
                            var result = await pair.Transport.Input.ReadAsync();

                            pair.Transport.Input.AdvanceTo(result.Buffer.End);
                        }
                        catch (Exception ex)
                        {
                            Assert.IsType <WebSocketError>(ex);
                        }
                        finally
                        {
                            // Complete the application so that the connection unwinds without aborting
                            pair.Transport.Output.Complete();
                        }
                    }

                    var transport = new WebSocketTransport(await feature.AcceptAsync(), pair.Application, NullLogger.Instance);

                    // Accept web socket, start receiving / sending at the transport level
                    var processTask = transport.ConnectAsync(CancellationToken.None);

                    // Start a socket client that will capture traffic for posterior analysis
                    var clientTask = feature.Client.ExecuteAndCaptureFramesAsync();

                    // When the close frame is received, we complete the application so the send
                    // loop unwinds
                    _ = CompleteApplicationAfterTransportCompletes();

                    // Terminate the client to server channel with an exception
                    feature.Client.SendAbort();

                    // Wait for the transport
                    await processTask.TimeoutAfterAsync(TimeSpan.FromSeconds(5));

                    await clientTask.TimeoutAfterAsync(TimeSpan.FromSeconds(5));
                }
            }
        }
        public async Task WebSocketTransport_ClientServer_WhatIsSentIsReceived()
        {
            var serverPipePair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
            var clientPipePair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

            using (var webSocketFeature = new TestWebSocketConnectionFeature())
            {
                // Build server transport
                var serverTransport = new WebSocketTransport(await webSocketFeature.AcceptAsync(), serverPipePair.Application, NullLogger.Instance);

                // Accept server web socket, start receiving / sending at the transport level
                var serverTask = serverTransport.ConnectAsync(CancellationToken.None);

                var clientTransport = new WebSocketTransport(webSocketFeature.Client, clientPipePair.Application, NullLogger.Instance);
                var clientTask      = clientTransport.ConnectAsync(CancellationToken.None);

                // Send a frame client -> server
                await clientPipePair.Transport.Output.WriteAsync(new ArraySegment <byte>(Encoding.UTF8.GetBytes("Hello")));

                await clientPipePair.Transport.Output.FlushAsync();

                var result = await serverPipePair.Transport.Input.ReadAsync();

                var buffer = result.Buffer;

                Assert.Equal("Hello", Encoding.UTF8.GetString(buffer.ToArray()));
                serverPipePair.Transport.Input.AdvanceTo(buffer.End);

                // Send a frame server -> client
                await serverPipePair.Transport.Output.WriteAsync(new ArraySegment <byte>(Encoding.UTF8.GetBytes("World")));

                await serverPipePair.Transport.Output.FlushAsync();

                var clientResult = await clientPipePair.Transport.Input.ReadAsync();

                buffer = clientResult.Buffer;

                Assert.Equal("World", Encoding.UTF8.GetString(buffer.ToArray()));
                clientPipePair.Transport.Input.AdvanceTo(buffer.End);

                clientPipePair.Transport.Output.Complete();
                serverPipePair.Transport.Output.Complete();

                // The transport should finish now
                await serverTask;
                await clientTask;
            }
        }
Exemple #18
0
    public async Task ReceivedFramesAreWrittenToChannel(string webSocketMessageType)
    {
        using (StartVerifiableLog())
        {
            var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
            var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger("HttpConnectionContext1"), pair.Transport, pair.Application, new());

            using (var feature = new TestWebSocketConnectionFeature())
            {
                var ws = new WebSocketsServerTransport(new WebSocketOptions(), connection.Application, connection, LoggerFactory);

                // Give the server socket to the transport and run it
                var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                // Run the client socket
                var client = feature.Client.ExecuteAndCaptureFramesAsync();

                // Send a frame, then close
                await feature.Client.SendAsync(
                    buffer : new ArraySegment <byte>(Encoding.UTF8.GetBytes("Hello")),
                    messageType : (WebSocketMessageType)Enum.Parse(typeof(WebSocketMessageType), webSocketMessageType),
                    endOfMessage : true,
                    cancellationToken : CancellationToken.None);

                await feature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);

                var result = await connection.Transport.Input.ReadAsync();

                var buffer = result.Buffer;
                Assert.Equal("Hello", Encoding.UTF8.GetString(buffer.ToArray()));
                connection.Transport.Input.AdvanceTo(buffer.End);

                connection.Transport.Output.Complete();

                // The transport should finish now
                await transport;

                // The connection should close after this, which means the client will get a close frame.
                var clientSummary = await client;

                Assert.Equal(WebSocketCloseStatus.NormalClosure, clientSummary.CloseResult.CloseStatus);
            }
        }
    }
        public async Task WebSocketTransport_WhatIsReceivedIsWritten()
        {
            var pipePair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

            using (var webSocketFeature = new TestWebSocketConnectionFeature())
            {
                // Build transport
                var transport = new WebSocketTransport(await webSocketFeature.AcceptAsync(), pipePair.Application, NullLogger.Instance);

                // Accept web socket, start receiving / sending at the transport level
                var processTask = transport.ConnectAsync(CancellationToken.None);

                // Start a socket client that will capture traffic for posterior analysis
                var clientTask = webSocketFeature.Client.ExecuteAndCaptureFramesAsync();

                // Send a frame, then close
                await webSocketFeature.Client.SendAsync(
                    buffer : new ArraySegment <byte>(Encoding.UTF8.GetBytes("Hello")),
                    messageType : WebSocketMessageType.Binary,
                    endOfMessage : true,
                    cancellationToken : CancellationToken.None);

                await webSocketFeature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);

                var result = await pipePair.Transport.Input.ReadAsync();

                var buffer = result.Buffer;
                Assert.Equal("Hello", Encoding.UTF8.GetString(buffer.ToArray()));
                pipePair.Transport.Input.AdvanceTo(buffer.End);

                pipePair.Transport.Output.Complete();

                // The transport should finish now
                await processTask;

                // The connection should close after this, which means the client will get a close frame.
                var clientSummary = await clientTask;

                Assert.Equal(WebSocketCloseStatus.NormalClosure, clientSummary.CloseResult.CloseStatus);
            }
        }
        private static void RunActivityStreamingTest(Activity[] activities, IBot bot, IBotFrameworkHttpAdapter server, RequestHandler clientRequestHandler, ILogger logger, bool useLegacyClient = false, int messageCount = 1, int threadCount = 1)
        {
            using (var connection = new TestWebSocketConnectionFeature())
            {
                var webSocket       = connection.AcceptAsync().Result;
                var clientWebSocket = connection.Client;
                var client          = new TestStreamingTransportClient("wss://test", clientRequestHandler, clientWebSocket, logger, useLegacyClient);

                var serverRunning = server.ProcessAsync(CreateWebSocketUpgradeRequest(webSocket), new Mock <HttpResponse>().Object, bot, CancellationToken.None);
                var clientRunning = client.ConnectAsync();

                if (messageCount == 1)
                {
                    SimulateMultiTurnConversation(1, activities, client, logger);
                }
                else
                {
                    var conversations = new Task[messageCount];
                    var throttler     = new SemaphoreSlim(threadCount);

                    for (var i = 0; i < messageCount; i++)
                    {
                        throttler.Wait();

                        var conversationId = i;
                        conversations[i] = Task.Factory.StartNew(() => SimulateMultiTurnConversation(conversationId, activities, client, logger, throttler));
                    }

                    Task.WhenAny(Task.WhenAll(conversations), Task.Delay(new TimeSpan(0, 0, 5, 0))).Wait();
                }

                clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "End of test", CancellationToken.None).Wait();

                clientRunning.Wait();
                Assert.Equal(TaskStatus.RanToCompletion, clientRunning.Status);

                serverRunning.Wait();
                Assert.Equal(TaskStatus.RanToCompletion, serverRunning.Status);
            }
        }
Exemple #21
0
    public async Task ServerGracefullyClosesWhenClientSendsCloseFrameThenApplicationEnds()
    {
        using (StartVerifiableLog())
        {
            var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
            var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)), pair.Transport, pair.Application, new());

            using (var feature = new TestWebSocketConnectionFeature())
            {
                var options = new WebSocketOptions
                {
                    // We want to verify behavior without timeout affecting it
                    CloseTimeout = TimeSpan.FromSeconds(20)
                };

                var ws = new WebSocketsServerTransport(options, connection.Application, connection, LoggerFactory);

                var serverSocket = await feature.AcceptAsync();

                // Give the server socket to the transport and run it
                var transport = ws.ProcessSocketAsync(serverSocket);

                // Run the client socket
                var client = feature.Client.ExecuteAndCaptureFramesAsync();

                await feature.Client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None).DefaultTimeout();

                // close the client to server channel
                connection.Transport.Output.Complete();

                _ = await client.DefaultTimeout();

                await transport.DefaultTimeout();

                Assert.Equal(WebSocketCloseStatus.NormalClosure, serverSocket.CloseStatus);
            }
        }
    }
        public async Task MultiSegmentSendWillNotSendEmptyEndOfMessageFrame()
        {
            using (var feature = new TestWebSocketConnectionFeature())
            {
                var serverSocket = await feature.AcceptAsync();

                var firstSegment  = new byte[] { 1 };
                var secondSegment = new byte[] { 15 };

                var first = new MemorySegment <byte>(firstSegment);
                var last  = first.Append(secondSegment);

                var sequence = new ReadOnlySequence <byte>(first, 0, last, last.Memory.Length);

                Assert.False(sequence.IsSingleSegment);

                await serverSocket.SendAsync(sequence, WebSocketMessageType.Text);

                // Run the client socket
                var client = feature.Client.ExecuteAndCaptureFramesAsync();

                await serverSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, default);

                var messages = await client.TimeoutAfterAsync(TimeSpan.FromSeconds(5));

                Assert.Equal(2, messages.Received.Count);

                // First message: 1 byte, endOfMessage false
                Assert.Single(messages.Received[0].Buffer);
                Assert.Equal(1, messages.Received[0].Buffer[0]);
                Assert.False(messages.Received[0].EndOfMessage);

                // Second message: 1 byte, endOfMessage true
                Assert.Single(messages.Received[1].Buffer);
                Assert.Equal(15, messages.Received[1].Buffer[0]);
                Assert.True(messages.Received[1].EndOfMessage);
            }
        }
Exemple #23
0
    public async Task WebSocketTransportSetsMessageTypeBasedOnTransferFormatFeature(TransferFormat transferFormat, string expectedMessageType)
    {
        using (StartVerifiableLog())
        {
            var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
            var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger("HttpConnectionContext1"), pair.Transport, pair.Application, new());

            using (var feature = new TestWebSocketConnectionFeature())
            {
                connection.ActiveFormat = transferFormat;
                var ws = new WebSocketsServerTransport(new WebSocketOptions(), connection.Application, connection, LoggerFactory);

                // Give the server socket to the transport and run it
                var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                // Run the client socket
                var client = feature.Client.ExecuteAndCaptureFramesAsync();

                // Write to the output channel, and then complete it
                await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello"));

                connection.Transport.Output.Complete();

                // The client should finish now, as should the server
                var clientSummary = await client;
                await feature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);

                await transport;

                Assert.Equal(1, clientSummary.Received.Count);
                Assert.True(clientSummary.Received[0].EndOfMessage);
                Assert.Equal((WebSocketMessageType)Enum.Parse(typeof(WebSocketMessageType), expectedMessageType), clientSummary.Received[0].MessageType);
                Assert.Equal("Hello", Encoding.UTF8.GetString(clientSummary.Received[0].Buffer));
            }
        }
    }
Exemple #24
0
        public async Task Integration_Interop_LegacyClient_MiniLoad(int threadCount, int messageCount)
        {
            var logger = XUnitLogger.CreateLogger(_outputHelper);

            using (var webSocketFeature = new TestWebSocketConnectionFeature())
            {
                var botRequestHandler = new Mock <RequestHandler>();

                botRequestHandler
                .Setup(r => r.ProcessRequestAsync(It.IsAny <ReceiveRequest>(), null, null, CancellationToken.None))
                .ReturnsAsync(() => new StreamingResponse()
                {
                    StatusCode = 200
                });

                var socket = await webSocketFeature.AcceptAsync().ConfigureAwait(false);

                var connection = new WebSocketStreamingConnection(socket, logger);
                var serverTask = Task.Run(() => connection.ListenAsync(botRequestHandler.Object));
                await Task.Delay(TimeSpan.FromSeconds(1));

                var clients = new List <Microsoft.Bot.Streaming.Transport.WebSockets.WebSocketClient>();

                var clientRequestHandler = new Mock <RequestHandler>();

                clientRequestHandler
                .Setup(r => r.ProcessRequestAsync(It.IsAny <ReceiveRequest>(), null, null, CancellationToken.None))
                .ReturnsAsync(() => new StreamingResponse()
                {
                    StatusCode = 200
                });

                using (var client = new Microsoft.Bot.Streaming.Transport.WebSockets.WebSocketClient(
                           "wss://test",
                           clientRequestHandler.Object))
                {
                    await client.ConnectInternalAsync(webSocketFeature.Client).ConfigureAwait(false);

                    clients.Add(client);

                    // Send request bot (server) -> channel (client)
                    const string path = "api/version";
                    const string botToClientPayload = "Hello human, I'm Bender!";

                    Func <int, Task> testFlow = async(i) =>
                    {
                        var request = StreamingRequest.CreatePost(path, new StringContent(botToClientPayload));

                        var stopwatch          = Stopwatch.StartNew();
                        var responseFromClient =
                            await connection.SendStreamingRequestAsync(request).ConfigureAwait(false);

                        stopwatch.Stop();

                        Assert.Equal(200, responseFromClient.StatusCode);
                        logger.LogInformation(
                            $"Server->Client {i} latency: {stopwatch.ElapsedMilliseconds}. Status code: {responseFromClient.StatusCode}");

                        const string clientToBotPayload = "Hello bot, I'm Calculon!";
                        var          clientRequest      = StreamingRequest.CreatePost(path, new StringContent(clientToBotPayload));

                        stopwatch = Stopwatch.StartNew();

                        // Send request bot channel (client) -> (server)
                        var clientToBotResult = await client.SendAsync(clientRequest).ConfigureAwait(false);

                        stopwatch.Stop();

                        Assert.Equal(200, clientToBotResult.StatusCode);

                        logger.LogInformation(
                            $"Client->Server {i} latency: {stopwatch.ElapsedMilliseconds}. Status code: {responseFromClient.StatusCode}");
                    };

                    await testFlow(-1).ConfigureAwait(false);

                    var tasks = new List <Task>();

                    using (var throttler = new SemaphoreSlim(threadCount))
                    {
                        for (int j = 0; j < messageCount; j++)
                        {
                            await throttler.WaitAsync().ConfigureAwait(false);

                            // using Task.Run(...) to run the lambda in its own parallel
                            // flow on the threadpool
                            tasks.Add(
                                Task.Run(async() =>
                            {
                                try
                                {
                                    await testFlow(j).ConfigureAwait(false);
                                }
                                finally
                                {
                                    throttler.Release();
                                }
                            }));
                        }

                        await Task.WhenAll(tasks).ConfigureAwait(false);
                    }

                    client.Disconnect();
                }

                await serverTask.ConfigureAwait(false);
            }
        }