コード例 #1
0
ファイル: Subscription.cs プロジェクト: JasonKStevens/Qube
        public void Connect <TIn, TOut>(Expression expression, IObserver <TOut> observer)
        {
            var seralizedExpression = SerializationHelper.SerializeLinqExpression <TIn, TOut>(
                expression,
                _options.TypesToTransfer.ToArray());

            Channel channel = new Channel(_options.ConnectionString, ChannelCredentials.Insecure);
            var     client  = new StreamService.StreamServiceClient(channel.CreateCallInvoker());

            var definer         = new PortableTypeDefiner();
            var classDefinition = definer.BuildDefinition(typeof(TIn));
            var enums           = definer.BuildDefinitions(_options.TypesToTransfer.Where(t => t.IsEnum).ToArray());
            var types           = definer.BuildDefinitions(_options.TypesToTransfer.Where(t => !t.IsEnum).ToArray());

            _types = enums
                     .Concat(new[] { classDefinition })
                     .Concat(types)
                     .GroupBy(t => new { t.AssemblyName, t.ClassName })
                     .Select(g => g.First())
                     .ToArray();

            var queryEnvelope = new QueryEnvelope
            {
                Payload         = seralizedExpression,
                SourceTypeName  = classDefinition.ClassName,
                RegisteredTypes = JsonConvert.SerializeObject(_types),
                StreamPattern   = JsonConvert.SerializeObject(_streamPatterns)
            };

            _streamingCall = client.QueryStreamAsync(queryEnvelope);

            // TODO: No need for one thread per subscription - this can be made more efficient
            Task.Run(GetObserveTask(observer), _cancelSource.Token)
            .ContinueWith(_ => _cancelSource.Dispose());
        }
コード例 #2
0
        public async Task DuplexStreaming_SimultaniousSendAndReceive_Success(int total, int batchSize)
        {
            // Arrange
            var data = new byte[batchSize];

            var client = new StreamService.StreamServiceClient(Channel);

            var(sent, received) = await EchoData(total, data, client);

            // Assert
            Assert.AreEqual(sent, total);
            Assert.AreEqual(received, total);
        }
コード例 #3
0
        public async Task DuplexStream_SendLargeFileBatchedAndRecieveLargeFileBatched_Success()
        {
            // Arrange
            var data = new byte[1024 * 1024 * 1]; // 1 MB

            for (var i = 0; i < data.Length; i++)
            {
                data[i] = (byte)i; // Will loop around back to zero
            }
            var client = new StreamService.StreamServiceClient(Channel);

            // Act
            var call = client.BufferAllData();

            var sent = 0;

            while (sent < data.Length)
            {
                const int BatchSize = 1024 * 64; // 64 KB

                var writeCount = Math.Min(data.Length - sent, BatchSize);

                await call.RequestStream.WriteAsync(new DataMessage
                {
                    Data = ByteString.CopyFrom(data, sent, writeCount)
                }).DefaultTimeout();

                sent += writeCount;

                Logger.LogInformation($"Sent {sent} bytes");
            }

            await call.RequestStream.CompleteAsync().DefaultTimeout();

            var ms = new MemoryStream();

            while (await call.ResponseStream.MoveNext(CancellationToken.None).DefaultTimeout())
            {
                ms.Write(call.ResponseStream.Current.Data.Span);

                Logger.LogInformation($"Received {ms.Length} bytes");
            }

            // Assert
            CollectionAssert.AreEqual(data, ms.ToArray());
        }
コード例 #4
0
        public async Task ClientStream_SendLargeFileBatched_Success()
        {
            // Arrange
            var total       = 1024 * 1024 * 64;    // 64 MB
            var data        = new byte[1024 * 64]; // 64 KB
            var client      = new StreamService.StreamServiceClient(Channel);
            var dataMessage = new DataMessage
            {
                Data = ByteString.CopyFrom(data)
            };

            // Act
            var call = client.ClientStreamedData();

            var sent = 0;

            while (sent < total)
            {
                var         writeCount = Math.Min(total - sent, data.Length);
                DataMessage m;
                if (writeCount == data.Length)
                {
                    m = dataMessage;
                }
                else
                {
                    m = new DataMessage
                    {
                        Data = ByteString.CopyFrom(data, 0, writeCount)
                    };
                }

                await call.RequestStream.WriteAsync(m).DefaultTimeout();

                sent += writeCount;
            }

            await call.RequestStream.CompleteAsync().DefaultTimeout();

            var response = await call.ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual(total, response.Size);
        }
コード例 #5
0
        public async Task DuplexStreaming_SimultaniousSendAndReceiveInParallel_Success(int tasks)
        {
            // Arrange
            const int total     = 1024 * 1024 * 1;
            const int batchSize = 1024 * 64;

            var data = new byte[batchSize];

            var client = new StreamService.StreamServiceClient(Channel);

            await TestHelpers.RunParallel(tasks, async() =>
            {
                var(sent, received) = await EchoData(total, data, client);

                // Assert
                Assert.AreEqual(sent, total);
                Assert.AreEqual(received, total);
            });
        }
コード例 #6
0
        private async Task CancelInParallel(int tasks, bool waitForHeaders, int interations)
        {
            SetExpectedErrorsFilter(writeContext =>
            {
                if (writeContext.LoggerName == TestConstants.ServerCallHandlerTestName)
                {
                    // Kestrel cancellation error message
                    if (writeContext.Exception is IOException &&
                        writeContext.Exception.Message == "The client reset the request stream.")
                    {
                        return(true);
                    }

                    // Cancellation when service is receiving message
                    if (writeContext.Exception is InvalidOperationException &&
                        writeContext.Exception.Message == "Cannot write message after request is complete.")
                    {
                        return(true);
                    }

                    // Cancellation before service writes message
                    if (writeContext.Exception is TaskCanceledException &&
                        writeContext.Exception.Message == "A task was canceled.")
                    {
                        return(true);
                    }
                }

                if (writeContext.LoggerName == "Grpc.Net.Client.Internal.GrpcCall")
                {
                    // Cancellation when call hasn't returned headers
                    if (writeContext.EventId.Name == "ErrorStartingCall" &&
                        writeContext.Exception is TaskCanceledException)
                    {
                        return(true);
                    }

                    if (writeContext.EventId.Name == "GrpcStatusError")
                    {
                        if (writeContext.Message == "Call failed with gRPC error status. Status code: 'Cancelled', Message: 'Call canceled by the client.'." ||
                            writeContext.Message == "Call failed with gRPC error status. Status code: 'Cancelled', Message: 'Error starting gRPC call.'.")
                        {
                            return(true);
                        }
                    }
                }

                return(false);
            });

            // Arrange
            var data = new byte[1024 * 64];

            var client = new StreamService.StreamServiceClient(Channel);

            await TestHelpers.RunParallel(tasks, async() =>
            {
                for (int i = 0; i < interations; i++)
                {
                    var cts     = new CancellationTokenSource();
                    var headers = new Metadata();
                    if (waitForHeaders)
                    {
                        headers.Add("flush-headers", bool.TrueString);
                    }
                    var call = client.EchoAllData(cancellationToken: cts.Token, headers: headers);

                    if (waitForHeaders)
                    {
                        await call.ResponseHeadersAsync.DefaultTimeout();
                    }

                    await call.RequestStream.WriteAsync(new DataMessage
                    {
                        Data = ByteString.CopyFrom(data)
                    }).DefaultTimeout();

                    cts.Cancel();
                }
            });
        }
コード例 #7
0
        public async Task ClientStream_HttpClientWithTimeout_Success()
        {
            SetExpectedErrorsFilter(writeContext =>
            {
                if (writeContext.LoggerName == "Grpc.Net.Client.Internal.GrpcCall" &&
                    writeContext.EventId.Name == "ErrorStartingCall" &&
                    writeContext.Exception is TaskCanceledException)
                {
                    return(true);
                }

                if (writeContext.LoggerName == "Grpc.Net.Client.Internal.GrpcCall" &&
                    writeContext.EventId.Name == "GrpcStatusError" &&
                    writeContext.Message == "Call failed with gRPC error status. Status code: 'Cancelled', Message: 'Error starting gRPC call.'.")
                {
                    return(true);
                }

                if (writeContext.LoggerName == "Grpc.Net.Client.Internal.GrpcCall" &&
                    writeContext.EventId.Name == "WriteMessageError" &&
                    writeContext.Exception is InvalidOperationException &&
                    writeContext.Exception.Message == "Can't write the message because the call is complete.")
                {
                    return(true);
                }

                if (writeContext.LoggerName == "SERVER FunctionalTestsWebsite.Services.StreamService")
                {
                    return(true);
                }

                return(false);
            });

            // Arrange
            var data = new byte[1024 * 64]; // 64 KB

            var httpClient = Fixture.CreateClient();

            httpClient.Timeout = TimeSpan.FromSeconds(0.5);

            var channel = GrpcChannel.ForAddress(httpClient.BaseAddress, new GrpcChannelOptions
            {
                HttpClient    = httpClient,
                LoggerFactory = LoggerFactory
            });

            var client      = new StreamService.StreamServiceClient(channel);
            var dataMessage = new DataMessage
            {
                Data = ByteString.CopyFrom(data)
            };

            // Act
            var call = client.ClientStreamedData();

            var ex = await ExceptionAssert.ThrowsAsync <RpcException>(async() =>
            {
                while (true)
                {
                    await call.RequestStream.WriteAsync(dataMessage).DefaultTimeout();

                    await Task.Delay(100);
                }
            }).DefaultTimeout();

            // Assert
            Assert.AreEqual(StatusCode.Cancelled, ex.StatusCode);
            Assert.AreEqual(StatusCode.Cancelled, call.GetStatus().StatusCode);
        }
コード例 #8
0
        private async Task <(int sent, int received)> EchoData(int total, byte[] data, StreamService.StreamServiceClient client)
        {
            var sent     = 0;
            var received = 0;
            var call     = client.EchoAllData();

            var readTask = Task.Run(async() =>
            {
                await foreach (var message in call.ResponseStream.ReadAllAsync())
                {
                    received += message.Data.Length;

                    Logger.LogInformation($"Received {sent} bytes");
                }
            });

            while (sent < total)
            {
                var writeCount = Math.Min(total - sent, data.Length);

                await call.RequestStream.WriteAsync(new DataMessage
                {
                    Data = ByteString.CopyFrom(data, 0, writeCount)
                }).DefaultTimeout();

                sent += writeCount;

                Logger.LogInformation($"Sent {sent} bytes");
            }

            await call.RequestStream.CompleteAsync().DefaultTimeout();

            await readTask;

            return(sent, received);
        }
コード例 #9
0
        private async Task CancelInParallel(int tasks, bool waitForHeaders, int interations)
        {
            SetExpectedErrorsFilter(writeContext =>
            {
                if (writeContext.LoggerName == TestConstants.ServerCallHandlerTestName)
                {
                    // Kestrel cancellation error message
                    if (writeContext.Exception is IOException &&
                        writeContext.Exception.Message == "The client reset the request stream.")
                    {
                        return(true);
                    }

                    // Cancellation when service is receiving message
                    if (writeContext.Exception is InvalidOperationException &&
                        writeContext.Exception.Message == "Can't read messages after the request is complete.")
                    {
                        return(true);
                    }

                    // Cancellation when service is writing message
                    if (writeContext.Exception is InvalidOperationException &&
                        writeContext.Exception.Message == "Can't write the message because the request is complete.")
                    {
                        return(true);
                    }

                    // Cancellation before service writes message
                    if (writeContext.Exception is TaskCanceledException &&
                        writeContext.Exception.Message == "A task was canceled.")
                    {
                        return(true);
                    }
                }

                if (writeContext.LoggerName == "Grpc.Net.Client.Internal.GrpcCall")
                {
                    // Cancellation when call hasn't returned headers
                    if (writeContext.EventId.Name == "ErrorStartingCall" &&
                        writeContext.Exception is TaskCanceledException)
                    {
                        return(true);
                    }
                }

                return(false);
            });

            // Arrange
            var data = new byte[1024 * 64];

            var client = new StreamService.StreamServiceClient(Channel);

            await TestHelpers.RunParallel(tasks, async taskIndex =>
            {
                try
                {
                    for (var i = 0; i < interations; i++)
                    {
                        Logger.LogInformation($"Staring {taskIndex}-{i}");

                        var cts     = new CancellationTokenSource();
                        var headers = new Metadata();
                        if (waitForHeaders)
                        {
                            headers.Add("flush-headers", bool.TrueString);
                        }
                        using var call = client.EchoAllData(cancellationToken: cts.Token, headers: headers);

                        if (waitForHeaders)
                        {
                            await call.ResponseHeadersAsync.DefaultTimeout();
                        }

                        await call.RequestStream.WriteAsync(new DataMessage
                        {
                            Data = ByteString.CopyFrom(data)
                        }).DefaultTimeout();

                        cts.Cancel();
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex, "Cancellation error");
                    throw;
                }
            });

            // Wait a short amount of time so that any server cancellation error
            // finishes being thrown before the next test starts.
            await Task.Delay(50);
        }