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