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