public async Task PostBasketReturnsId() { var response = await testClientFactory.Create().PostAsync("Basket", null); response.StatusCode.Should().Be(HttpStatusCode.OK); var stringResponse = await response.Content.ReadAsStringAsync(); response.IsSuccessStatusCode.Should().BeTrue(); stringResponse.Should().NotBeNullOrWhiteSpace(); }
public async Task SendAuthHeader_ReceivedOnServer() { string?httpContextAuthorization = null; string?metadataAuthorization = null; Task <HelloReply> ReadAuthHeaderOnServer(HelloRequest request, ServerCallContext context) { httpContextAuthorization = context.GetHttpContext().Request.Headers[HeaderNames.Authorization]; metadataAuthorization = context.RequestHeaders.GetValue("authorization"); return(Task.FromResult(new HelloReply())); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <HelloRequest, HelloReply>(ReadAuthHeaderOnServer); var channel = CreateGrpcWebChannel(); var client = TestClientFactory.Create(channel, method); // Act var metadata = new Metadata(); metadata.Add("Authorization", "123"); var call = client.UnaryCall(new HelloRequest(), new CallOptions(headers: metadata)); await call.ResponseAsync.DefaultTimeout(); // Assert Assert.AreEqual("123", httpContextAuthorization); Assert.AreEqual("123", metadataAuthorization); }
public async Task ThrowErrorWithOK_ClientThrowsFailedToDeserializeError() { SetExpectedErrorsFilter(writeContext => { if (writeContext.State.ToString() == "Message not returned from unary or client streaming call.") { return(true); } return(false); }); Task <HelloReply> UnaryThrowError(HelloRequest request, ServerCallContext context) { return(Task.FromException <HelloReply>(new RpcException(new Status(StatusCode.OK, "Message")))); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <HelloRequest, HelloReply>(UnaryThrowError); var channel = CreateChannel(); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new HelloRequest()); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode); Assert.AreEqual("Failed to deserialize response message.", ex.Status.Detail); Assert.AreEqual(StatusCode.Internal, call.GetStatus().StatusCode); Assert.AreEqual("Failed to deserialize response message.", call.GetStatus().Detail); }
public async Task ServerStreaming_GetTrailersAndStatus_Success() { async Task ServerStreamingWithTrailers(DataMessage request, IServerStreamWriter <DataMessage> responseStream, ServerCallContext context) { await responseStream.WriteAsync(new DataMessage()); context.ResponseTrailers.Add("my-trailer", "value"); } // Arrange var method = Fixture.DynamicGrpc.AddServerStreamingMethod <DataMessage, DataMessage>(ServerStreamingWithTrailers); var channel = CreateChannel(); var client = TestClientFactory.Create(channel, method); // Act var call = client.ServerStreamingCall(new DataMessage()); // Assert Assert.IsTrue(await call.ResponseStream.MoveNext().DefaultTimeout()); Assert.AreEqual(0, call.ResponseStream.Current.Data.Length); Assert.IsFalse(await call.ResponseStream.MoveNext().DefaultTimeout()); var trailers = call.GetTrailers(); Assert.AreEqual(1, trailers.Count); Assert.AreEqual("value", trailers.GetValue("my-trailer")); Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode); }
static Task <DataMessage> MakeCall(GrpcTestFixture <FunctionalTestsWebsite.Startup> fixture, GrpcChannel channel, DataMessage request, SyncPoint syncPoint) { var callCount = 0; async Task <DataMessage> UnaryFailure(DataMessage request, ServerCallContext context) { Interlocked.Increment(ref callCount); if (callCount == 1) { await syncPoint.WaitToContinue(); throw new RpcException(new Status(StatusCode.Unavailable, "")); } else { return(request); } } // Arrange var method = fixture.DynamicGrpc.AddUnaryMethod <DataMessage, DataMessage>(UnaryFailure); var client = TestClientFactory.Create(channel, method); var call = client.UnaryCall(request); return(call.ResponseAsync); }
public async Task Unary_ExceedAttempts_Failure(int?hedgingDelay) { Task <DataMessage> UnaryFailure(DataMessage request, ServerCallContext context) { return(Task.FromException <DataMessage>(new RpcException(new Status(StatusCode.Unavailable, "")))); } // Ignore errors SetExpectedErrorsFilter(writeContext => { return(true); }); // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <DataMessage, DataMessage>(UnaryFailure); var delay = (hedgingDelay == null) ? (TimeSpan?)null : TimeSpan.FromMilliseconds(hedgingDelay.Value); var channel = CreateChannel(serviceConfig: ServiceConfigHelpers.CreateHedgingServiceConfig(maxAttempts: 5, hedgingDelay: delay)); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new DataMessage()); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.Unavailable, ex.StatusCode); Assert.AreEqual(StatusCode.Unavailable, call.GetStatus().StatusCode); AssertHasLog(LogLevel.Debug, "CallCommited", "Call commited. Reason: ExceededAttemptCount"); }
public async Task Unary_DeadlineExceedBeforeServerCall_Failure() { var callCount = 0; var tcs = new TaskCompletionSource <DataMessage>(TaskCreationOptions.RunContinuationsAsynchronously); Task <DataMessage> UnaryFailure(DataMessage request, ServerCallContext context) { callCount++; return(tcs.Task); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <DataMessage, DataMessage>(UnaryFailure); var serviceConfig = ServiceConfigHelpers.CreateHedgingServiceConfig(nonFatalStatusCodes: new List <StatusCode> { StatusCode.DeadlineExceeded }); var channel = CreateChannel(serviceConfig: serviceConfig); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new DataMessage(), new CallOptions(deadline: DateTime.UtcNow)); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.DeadlineExceeded, ex.StatusCode); Assert.AreEqual(StatusCode.DeadlineExceeded, call.GetStatus().StatusCode); Assert.AreEqual(0, callCount); AssertHasLog(LogLevel.Debug, "CallCommited", "Call commited. Reason: DeadlineExceeded"); tcs.SetResult(new DataMessage()); }
public async Task UnaryMethod_ErrorCall_PollingCountersUpdatedCorrectly() { var tcs = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); // Ignore errors SetExpectedErrorsFilter(writeContext => { return(true); }); async Task <HelloReply> UnaryError(HelloRequest request, ServerCallContext context) { await tcs.Task.DefaultTimeout(); throw new Exception("Error!"); } // Arrange var clientEventListener = CreateEnableListener(Grpc.Net.Client.Internal.GrpcEventSource.Log); var serverEventListener = CreateEnableListener(Grpc.AspNetCore.Server.Internal.GrpcEventSource.Log); // Act - Start call var method = Fixture.DynamicGrpc.AddUnaryMethod <HelloRequest, HelloReply>(UnaryError); var client = TestClientFactory.Create(Channel, method); var call = client.UnaryCall(new HelloRequest()); // Assert - Call in progress await AssertCounters("Server call in progress", serverEventListener, new Dictionary <string, long> { ["current-calls"] = 1, ["calls-failed"] = 0, }).DefaultTimeout(); await AssertCounters("Client call in progress", clientEventListener, new Dictionary <string, long> { ["current-calls"] = 1, ["calls-failed"] = 0, }).DefaultTimeout(); // Act - Complete call tcs.SetResult(true); var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync.DefaultTimeout()).DefaultTimeout(); Assert.AreEqual(StatusCode.Unknown, ex.StatusCode); Assert.AreEqual("Exception was thrown by handler. Exception: Error!", ex.Status.Detail); // Assert - Call complete await AssertCounters("Server call in complete", serverEventListener, new Dictionary <string, long> { ["current-calls"] = 0, ["calls-failed"] = 1, }).DefaultTimeout(); await AssertCounters("Client call complete", clientEventListener, new Dictionary <string, long> { ["current-calls"] = 0, ["calls-failed"] = 1, }).DefaultTimeout(); }
public async Task UnixDomainSockets() { Task <HelloReply> UnaryUds(HelloRequest request, ServerCallContext context) { #if NET6_0_OR_GREATER var endPoint = (UnixDomainSocketEndPoint)context.GetHttpContext().Features.Get <IConnectionSocketFeature>() !.Socket.LocalEndPoint !; Assert.NotNull(endPoint); #endif return(Task.FromResult(new HelloReply { Message = "Hello " + request.Name })); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <HelloRequest, HelloReply>(UnaryUds); var http = Fixture.CreateHandler(TestServerEndpointName.UnixDomainSocket); var channel = GrpcChannel.ForAddress(http.address, new GrpcChannelOptions { LoggerFactory = LoggerFactory, HttpHandler = http.handler }); var client = TestClientFactory.Create(channel, method); // Act var response = await client.UnaryCall(new HelloRequest { Name = "John" }).ResponseAsync.DefaultTimeout(); // Assert Assert.AreEqual("Hello John", response.Message); }
public async Task Unary_AttemptsGreaterThanDefaultClientLimit_LimitedAttemptsMade(int hedgingDelay) { var callCount = 0; Task <DataMessage> UnaryFailure(DataMessage request, ServerCallContext context) { Interlocked.Increment(ref callCount); return(Task.FromException <DataMessage>(new RpcException(new Status(StatusCode.Unavailable, "")))); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <DataMessage, DataMessage>(UnaryFailure); var channel = CreateChannel(serviceConfig: ServiceConfigHelpers.CreateHedgingServiceConfig(maxAttempts: 10, hedgingDelay: TimeSpan.FromMilliseconds(hedgingDelay))); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new DataMessage()); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.Unavailable, ex.StatusCode); Assert.AreEqual(StatusCode.Unavailable, call.GetStatus().StatusCode); Assert.AreEqual(5, callCount); AssertHasLog(LogLevel.Debug, "MaxAttemptsLimited", "The method has 10 attempts specified in the service config. The number of attempts has been limited by channel configuration to 5."); AssertHasLog(LogLevel.Debug, "CallCommited", "Call commited. Reason: ExceededAttemptCount"); }
public async Task Unary_DeadlineInBetweenReadAsyncCalls_DeadlineExceededStatus() { Task <DataMessage> Unary(DataMessage request, ServerCallContext context) { return(Task.FromResult(new DataMessage())); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <DataMessage, DataMessage>(Unary); var http = Fixture.CreateHandler(TestServerEndpointName.Http2); var channel = GrpcChannel.ForAddress(http.address, new GrpcChannelOptions { LoggerFactory = LoggerFactory, HttpHandler = new PauseHttpHandler { InnerHandler = http.handler } }); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new DataMessage(), new CallOptions(deadline: DateTime.UtcNow.AddMilliseconds(200))); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.DeadlineExceeded, ex.StatusCode); Assert.AreEqual(StatusCode.DeadlineExceeded, call.GetStatus().StatusCode); }
public async Task Unary_SmallDeadline_ExceededWithoutReschedule() { var tcs = new TaskCompletionSource <DataMessage>(TaskCreationOptions.RunContinuationsAsynchronously); Task <DataMessage> UnaryTimeout(DataMessage request, ServerCallContext context) { return(tcs.Task); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <DataMessage, DataMessage>(UnaryTimeout); var channel = CreateChannel(); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new DataMessage(), new CallOptions(deadline: DateTime.UtcNow.AddMilliseconds(200))); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.DeadlineExceeded, ex.StatusCode); Assert.AreEqual(StatusCode.DeadlineExceeded, call.GetStatus().StatusCode); Assert.IsFalse(Logs.Any(l => l.EventId.Name == "DeadlineTimerRescheduled")); tcs.SetResult(new DataMessage()); }
public async Task GetTrailers_LargeTrailer_ReturnedToClient() { var trailerValue = new string('!', 8000); Task <HelloReply> LargeTrailer(HelloRequest request, ServerCallContext context) { context.ResponseTrailers.Add(new Metadata.Entry("Name", trailerValue)); return(Task.FromResult(new HelloReply())); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <HelloRequest, HelloReply>(LargeTrailer); var channel = CreateGrpcWebChannel(); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new HelloRequest()); await call; // Assert var trailers = call.GetTrailers(); Assert.AreEqual(1, trailers.Count); Assert.AreEqual(trailerValue, trailers.GetValue("name")); }
public async Task Unary_ExceedRetryAttempts_Failure() { Task <DataMessage> UnaryFailure(DataMessage request, ServerCallContext context) { var metadata = new Metadata(); metadata.Add("grpc-retry-pushback-ms", "5"); return(Task.FromException <DataMessage>(new RpcException(new Status(StatusCode.Unavailable, ""), metadata))); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <DataMessage, DataMessage>(UnaryFailure); var channel = CreateChannel(serviceConfig: ServiceConfigHelpers.CreateRetryServiceConfig()); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new DataMessage()); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.Unavailable, ex.StatusCode); Assert.AreEqual(StatusCode.Unavailable, call.GetStatus().StatusCode); AssertHasLog(LogLevel.Debug, "RetryPushbackReceived", "Retry pushback of '5' received from the failed gRPC call."); AssertHasLog(LogLevel.Debug, "RetryEvaluated", "Evaluated retry for failed gRPC call. Status code: 'Unavailable', Attempt: 1, Retry: True"); AssertHasLog(LogLevel.Trace, "StartingRetryDelay", "Starting retry delay of 00:00:00.0050000."); AssertHasLog(LogLevel.Debug, "RetryEvaluated", "Evaluated retry for failed gRPC call. Status code: 'Unavailable', Attempt: 5, Retry: False"); AssertHasLog(LogLevel.Debug, "CallCommited", "Call commited. Reason: ExceededAttemptCount"); }
public async Task Unary_TriggerRetryThrottling_Failure() { var callCount = 0; Task <DataMessage> UnaryFailure(DataMessage request, ServerCallContext context) { callCount++; return(Task.FromException <DataMessage>(new RpcException(new Status(StatusCode.Unavailable, "")))); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <DataMessage, DataMessage>(UnaryFailure); var channel = CreateChannel(serviceConfig: ServiceConfigHelpers.CreateHedgingServiceConfig( hedgingDelay: TimeSpan.FromSeconds(10), retryThrottling: new RetryThrottlingPolicy { MaxTokens = 5, TokenRatio = 0.1 })); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new DataMessage()); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.Unavailable, ex.StatusCode); Assert.AreEqual(StatusCode.Unavailable, call.GetStatus().StatusCode); Assert.AreEqual(3, callCount); AssertHasLog(LogLevel.Debug, "CallCommited", "Call commited. Reason: Throttled"); }
public async Task GetTrailers_UnaryMethodThrowsExceptionWithTrailers_TrailersAvailableInClient() { Task <HelloReply> UnaryDeadlineExceeded(HelloRequest request, ServerCallContext context) { var trailers = new Metadata(); trailers.Add(new Metadata.Entry("Name", "the value was empty")); return(Task.FromException <HelloReply>(new RpcException(new Status(StatusCode.InvalidArgument, "Validation failed"), trailers))); } // Arrange SetExpectedErrorsFilter(writeContext => { if (writeContext.LoggerName == "Grpc.Net.Client.Internal.GrpcCall" && writeContext.EventId.Name == "ErrorReadingMessage" && writeContext.Message == "Error reading message.") { return(true); } if (writeContext.LoggerName == "Grpc.Net.Client.Internal.GrpcCall" && writeContext.EventId.Name == "GrpcStatusError" && writeContext.Message == "Call failed with gRPC error status. Status code: 'InvalidArgument', Message: 'Validation failed'.") { return(true); } if (writeContext.LoggerName == "SERVER Grpc.AspNetCore.Server.ServerCallHandler" && writeContext.EventId.Name == "RpcConnectionError" && writeContext.Message == "Error status code 'InvalidArgument' raised.") { return(true); } return(false); }); var method = Fixture.DynamicGrpc.AddUnaryMethod <HelloRequest, HelloReply>(UnaryDeadlineExceeded); var channel = CreateChannel(); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new HelloRequest()); var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); // Assert var trailers = call.GetTrailers(); Assert.GreaterOrEqual(trailers.Count, 1); Assert.AreEqual("the value was empty", trailers.Single(m => m.Key == "name").Value); Assert.AreEqual(StatusCode.InvalidArgument, ex.StatusCode); Assert.AreEqual("Validation failed", ex.Status.Detail); Assert.GreaterOrEqual(ex.Trailers.Count, 1); Assert.AreEqual("the value was empty", ex.Trailers.Single(m => m.Key == "name").Value); }
public async Task Resolver_SubchannelTransientFailure_ResolverRefreshed() { // Ignore errors SetExpectedErrorsFilter(writeContext => { return(true); }); string?host = null; Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context) { host = context.Host; return(Task.FromResult(new HelloReply { Message = request.Name })); } // Arrange using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod)); using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod)); SyncPoint?syncPoint = new SyncPoint(runContinuationsAsynchronously: true); syncPoint.Continue(); var resolver = new TestResolver(async() => { await syncPoint.WaitToContinue().DefaultTimeout(); syncPoint = new SyncPoint(runContinuationsAsynchronously: true); }); resolver.UpdateAddresses(new List <BalancerAddress> { new BalancerAddress(endpoint1.Address.Host, endpoint1.Address.Port), new BalancerAddress(endpoint2.Address.Host, endpoint2.Address.Port) }); var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), resolver, connect : true); await BalancerHelpers.WaitForSubChannelsToBeReadyAsync(Logger, channel, 2).DefaultTimeout(); var client = TestClientFactory.Create(channel, endpoint1.Method); var waitForRefreshTask = syncPoint.WaitForSyncPoint(); endpoint1.Dispose(); await waitForRefreshTask.DefaultTimeout(); resolver.UpdateAddresses(new List <BalancerAddress> { new BalancerAddress(endpoint2.Address.Host, endpoint2.Address.Port) }); syncPoint.Continue(); await BalancerHelpers.WaitForSubChannelsToBeReadyAsync(Logger, channel, 1).DefaultTimeout(); }
public async Task UnaryMethod_SuccessfulCall_PollingCountersUpdatedCorrectly() { var tcs = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); async Task <HelloReply> UnarySuccess(HelloRequest request, ServerCallContext context) { await tcs.Task.DefaultTimeout(); return(new HelloReply()); } // Arrange var clientEventListener = CreateEnableListener(Grpc.Net.Client.Internal.GrpcEventSource.Log); var serverEventListener = CreateEnableListener(Grpc.AspNetCore.Server.Internal.GrpcEventSource.Log); // Act - Start call var method = Fixture.DynamicGrpc.AddUnaryMethod <HelloRequest, HelloReply>(UnarySuccess); var client = TestClientFactory.Create(Channel, method); var call = client.UnaryCall(new HelloRequest()); // Assert - Call in progress await AssertCounters(serverEventListener, new Dictionary <string, long> { ["total-calls"] = 1, ["current-calls"] = 1, ["messages-sent"] = 0, ["messages-received"] = 1, }).DefaultTimeout(); await AssertCounters(clientEventListener, new Dictionary <string, long> { ["total-calls"] = 1, ["current-calls"] = 1, ["messages-sent"] = 1, ["messages-received"] = 0, }).DefaultTimeout(); // Act - Complete call tcs.SetResult(true); await call.ResponseAsync.DefaultTimeout(); // Assert - Call complete await AssertCounters(serverEventListener, new Dictionary <string, long> { ["total-calls"] = 1, ["current-calls"] = 0, ["messages-sent"] = 1, ["messages-received"] = 1, }).DefaultTimeout(); await AssertCounters(clientEventListener, new Dictionary <string, long> { ["total-calls"] = 1, ["current-calls"] = 0, ["messages-sent"] = 1, ["messages-received"] = 1, }).DefaultTimeout(); }
public async Task DuplexStreaming_CancelResponseMoveNext_CancellationSentToServer() { var tcs = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously); async Task DuplexStreamingWithCancellation(IAsyncStreamReader <DataMessage> requestStream, IServerStreamWriter <DataMessage> responseStream, ServerCallContext context) { try { await foreach (var message in requestStream.ReadAllAsync()) { await responseStream.WriteAsync(message); } } catch (Exception ex) { tcs.TrySetException(ex); } } // Arrange var method = Fixture.DynamicGrpc.AddDuplexStreamingMethod <DataMessage, DataMessage>(DuplexStreamingWithCancellation); var channel = CreateChannel(); var client = TestClientFactory.Create(channel, method); // Act var call = client.DuplexStreamingCall(); await call.RequestStream.WriteAsync(new DataMessage { Data = ByteString.CopyFrom(Encoding.UTF8.GetBytes("Hello world")) }).DefaultTimeout(); await call.ResponseStream.MoveNext().DefaultTimeout(); var cts = new CancellationTokenSource(); var task = call.ResponseStream.MoveNext(cts.Token); cts.Cancel(); // Assert var clientEx = await ExceptionAssert.ThrowsAsync <RpcException>(() => task).DefaultTimeout(); Assert.AreEqual(StatusCode.Cancelled, clientEx.StatusCode); Assert.AreEqual("Call canceled by the client.", clientEx.Status.Detail); var serverEx = await ExceptionAssert.ThrowsAsync <Exception>(() => tcs.Task).DefaultTimeout(); if (serverEx is IOException) { // Cool } else if (serverEx is InvalidOperationException) { Assert.AreEqual("Can't read messages after the request is complete.", serverEx.Message); } else { Assert.Fail(); } }
public async Task Unary_LargeMessages_ExceedPerCallBufferSize(long payloadSize, bool exceedBufferLimit, int hedgingDelayMilliseconds) { var callCount = 0; Task <DataMessage> UnaryFailure(DataMessage request, ServerCallContext context) { Interlocked.Increment(ref callCount); return(Task.FromException <DataMessage>(new RpcException(new Status(StatusCode.Unavailable, "")))); } // Ignore errors SetExpectedErrorsFilter(writeContext => { if (writeContext.EventId.Name == "ErrorSendingMessage" || writeContext.EventId.Name == "ErrorExecutingServiceMethod") { return(true); } return(false); }); // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <DataMessage, DataMessage>(UnaryFailure); var channel = CreateChannel( serviceConfig: ServiceConfigHelpers.CreateHedgingServiceConfig(hedgingDelay: TimeSpan.FromMilliseconds(hedgingDelayMilliseconds)), maxReceiveMessageSize: (int)GrpcChannel.DefaultMaxRetryBufferPerCallSize * 2); var client = TestClientFactory.Create(channel, method); // Act var call = client.UnaryCall(new DataMessage { Data = ByteString.CopyFrom(new byte[payloadSize]) }); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.Unavailable, ex.StatusCode); Assert.AreEqual(StatusCode.Unavailable, call.GetStatus().StatusCode); if (!exceedBufferLimit) { Assert.AreEqual(5, callCount); } else { Assert.AreEqual(1, callCount); AssertHasLog(LogLevel.Debug, "CallCommited", "Call commited. Reason: BufferExceeded"); // Cancelled calls could cause server errors. Delay so these error don't show up // in the next unit test. await Task.Delay(100); } Assert.AreEqual(0, channel.CurrentRetryBufferSize); }
public async Task ServerStreaming_WriteAfterMethodComplete_Error(bool writeBeforeExit) { var tcs = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously); var writeTcs = new TaskCompletionSource <Task>(TaskCreationOptions.RunContinuationsAsynchronously); var syncPoint = new SyncPoint(runContinuationsAsynchronously: true); async Task ServerStreamingWithTrailers(DataMessage request, IServerStreamWriter <DataMessage> responseStream, ServerCallContext context) { var writeTask = Task.Run(async() => { if (writeBeforeExit) { await responseStream.WriteAsync(new DataMessage()); } await syncPoint.WaitToContinue(); await responseStream.WriteAsync(new DataMessage()); }); writeTcs.SetResult(writeTask); await tcs.Task; } // Arrange var method = Fixture.DynamicGrpc.AddServerStreamingMethod <DataMessage, DataMessage>(ServerStreamingWithTrailers); var channel = CreateChannel(); var client = TestClientFactory.Create(channel, method); // Act var call = client.ServerStreamingCall(new DataMessage()); await syncPoint.WaitForSyncPoint().DefaultTimeout(); tcs.SetResult(null); // Assert if (writeBeforeExit) { Assert.IsTrue(await call.ResponseStream.MoveNext().DefaultTimeout()); } Assert.IsFalse(await call.ResponseStream.MoveNext().DefaultTimeout()); Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode); syncPoint.Continue(); var writeTask = await writeTcs.Task.DefaultTimeout(); var ex = await ExceptionAssert.ThrowsAsync <InvalidOperationException>(() => writeTask).DefaultTimeout(); Assert.AreEqual("Can't write the message because the request is complete.", ex.Message); Assert.IsFalse(await call.ResponseStream.MoveNext()); }
public async Task ClientFactory_CallCredentials_RoundtripToken() { string?authorization = null; Task <HelloReply> UnaryTelemetryHeader(HelloRequest request, ServerCallContext context) { authorization = context.RequestHeaders.GetValue("authorization"); return(Task.FromResult(new HelloReply())); } var method = Fixture.DynamicGrpc.AddUnaryMethod <HelloRequest, HelloReply>(UnaryTelemetryHeader); var token = "token!"; var credentials = CallCredentials.FromInterceptor((context, metadata) => { if (!string.IsNullOrEmpty(token)) { metadata.Add("Authorization", $"Bearer {token}"); } return(Task.CompletedTask); }); var serviceCollection = new ServiceCollection(); serviceCollection.AddSingleton <ILoggerFactory>(LoggerFactory); serviceCollection .AddGrpcClient <TestClient <HelloRequest, HelloReply> >(options => { options.Address = Fixture.GetUrl(TestServerEndpointName.Http2WithTls); }) .ConfigureChannel(channel => { channel.Credentials = ChannelCredentials.Create(new SslCredentials(), credentials); }) .ConfigureGrpcClientCreator(invoker => { return(TestClientFactory.Create(invoker, method)); }) .ConfigurePrimaryHttpMessageHandler(() => { return(new HttpClientHandler { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }); }); var services = serviceCollection.BuildServiceProvider(); var client = services.GetRequiredService <TestClient <HelloRequest, HelloReply> >(); var call = client.UnaryCall(new HelloRequest { Name = "world" }); await call.ResponseAsync.DefaultTimeout(); Assert.AreEqual("Bearer token!", authorization); }
public async Task GetsHealth() { var response = await testClientFactory.Create().GetAsync(""); response.StatusCode.Should().Be(HttpStatusCode.OK); var stringResponse = await response.Content.ReadAsStringAsync(); stringResponse.Should().Contain("Healthy"); }
public async Task ClientFactory_CreateMultipleClientsAndMakeCalls_Success() { // Arrange Task <HelloReply> UnaryCall(HelloRequest request, ServerCallContext context) { return(Task.FromResult(new HelloReply { Message = $"Hello {request.Name}" })); } var method = Fixture.DynamicGrpc.AddUnaryMethod <HelloRequest, HelloReply>(UnaryCall); var serviceCollection = new ServiceCollection(); serviceCollection.AddSingleton <ILoggerFactory>(LoggerFactory); serviceCollection .AddGrpcClient <TestClient <HelloRequest, HelloReply> >(options => { options.Address = Fixture.GetUrl(TestServerEndpointName.Http2WithTls); }) .ConfigureGrpcClientCreator(invoker => { return(TestClientFactory.Create(invoker, method)); }) .ConfigurePrimaryHttpMessageHandler(() => { return(new SocketsHttpHandler { SslOptions = new SslClientAuthenticationOptions { RemoteCertificateValidationCallback = (____, ___, __, _) => true } }); }); var services = serviceCollection.BuildServiceProvider(); // Act 1 var client1 = services.GetRequiredService <TestClient <HelloRequest, HelloReply> >(); var call1 = client1.UnaryCall(new HelloRequest { Name = "world" }); var response1 = await call1.ResponseAsync.DefaultTimeout(); // Assert 1 Assert.AreEqual("Hello world", response1.Message); // Act 2 var client2 = services.GetRequiredService <TestClient <HelloRequest, HelloReply> >(); var call2 = client2.UnaryCall(new HelloRequest { Name = "world" }); var response2 = await call2.ResponseAsync.DefaultTimeout(); // Assert 2 Assert.AreEqual("Hello world", response2.Message); }
public async Task ClientStreaming_WriteAsyncCancellationDuringRetry_Canceled(bool throwOperationCanceledOnCancellation) { async Task <DataMessage> ClientStreamingWithReadFailures(IAsyncStreamReader <DataMessage> requestStream, ServerCallContext context) { Logger.LogInformation("Server reading message 1."); Assert.IsTrue(await requestStream.MoveNext()); Logger.LogInformation("Server pausing."); await Task.Delay(TimeSpan.FromMilliseconds(500)); Logger.LogInformation("Server erroring."); throw new RpcException(new Status(StatusCode.Unavailable, string.Empty)); } SetExpectedErrorsFilter(writeContext => { return(true); }); // Arrange var method = Fixture.DynamicGrpc.AddClientStreamingMethod <DataMessage, DataMessage>(ClientStreamingWithReadFailures); var channel = CreateChannel( serviceConfig: ServiceConfigHelpers.CreateHedgingServiceConfig(maxAttempts: 5, hedgingDelay: TimeSpan.FromSeconds(20)), maxReceiveMessageSize: BigMessageSize * 2, maxRetryBufferPerCallSize: BigMessageSize * 2, throwOperationCanceledOnCancellation: throwOperationCanceledOnCancellation); var client = TestClientFactory.Create(channel, method); // Act var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); var call = client.ClientStreamingCall(); Logger.LogInformation("Client writing message 1."); await call.RequestStream.WriteAsync(new DataMessage { Data = ByteString.CopyFrom(new byte[] { (byte)1 }) }, cts.Token).DefaultTimeout(); Logger.LogInformation("Client writing message 2."); var writeTask = call.RequestStream.WriteAsync(new DataMessage { Data = ByteString.CopyFrom(new byte[BigMessageSize]) }, cts.Token); // Assert if (throwOperationCanceledOnCancellation) { var ex = await ExceptionAssert.ThrowsAsync <OperationCanceledException>(() => writeTask).DefaultTimeout(); Assert.AreEqual(StatusCode.Cancelled, call.GetStatus().StatusCode); } else { var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => writeTask).DefaultTimeout(); Assert.AreEqual(StatusCode.Cancelled, ex.StatusCode); } Assert.IsTrue(cts.Token.IsCancellationRequested, "WriteAsync finished when CancellationToken wasn't triggered."); }
public async Task ClientStreaming_MultipleWritesAndRetries_Failure() { var nextFailure = 1; async Task <DataMessage> ClientStreamingWithReadFailures(IAsyncStreamReader <DataMessage> requestStream, ServerCallContext context) { List <byte> bytes = new List <byte>(); await foreach (var message in requestStream.ReadAllAsync()) { if (bytes.Count >= nextFailure) { nextFailure = nextFailure * 2; throw new RpcException(new Status(StatusCode.Unavailable, "")); } bytes.Add(message.Data[0]); } return(new DataMessage { Data = ByteString.CopyFrom(bytes.ToArray()) }); } SetExpectedErrorsFilter(writeContext => { return(true); }); // Arrange var method = Fixture.DynamicGrpc.AddClientStreamingMethod <DataMessage, DataMessage>(ClientStreamingWithReadFailures); var channel = CreateChannel(serviceConfig: ServiceConfigHelpers.CreateRetryServiceConfig(maxAttempts: 10), maxRetryAttempts: 10); var client = TestClientFactory.Create(channel, method); var sentData = new List <byte>(); // Act var call = client.ClientStreamingCall(); for (var i = 0; i < 20; i++) { sentData.Add((byte)i); await call.RequestStream.WriteAsync(new DataMessage { Data = ByteString.CopyFrom(new byte[] { (byte)i }) }).DefaultTimeout(); await Task.Delay(1); } await call.RequestStream.CompleteAsync().DefaultTimeout(); var result = await call.ResponseAsync.DefaultTimeout(); // Assert Assert.IsTrue(result.Data.Span.SequenceEqual(sentData.ToArray())); }
public async Task Client_CallCredentials_WithLoadBalancing_RoundtripToken() { // Arrange string?authorization = null; Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context) { authorization = context.RequestHeaders.GetValue("authorization"); return(Task.FromResult(new HelloReply { Message = request.Name })); } var credentials = CallCredentials.FromInterceptor((context, metadata) => { metadata.Add("Authorization", $"Bearer TEST"); return(Task.CompletedTask); }); using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod), HttpProtocols.Http1AndHttp2, isHttps: true); using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod), HttpProtocols.Http1AndHttp2, isHttps: true); var services = new ServiceCollection(); services.AddSingleton <ResolverFactory>(new StaticResolverFactory(_ => new[] { new BalancerAddress(endpoint1.Address.Host, endpoint1.Address.Port), new BalancerAddress(endpoint2.Address.Host, endpoint2.Address.Port) })); var socketsHttpHandler = new SocketsHttpHandler { EnableMultipleHttp2Connections = true, SslOptions = new System.Net.Security.SslClientAuthenticationOptions { EnabledSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12, RemoteCertificateValidationCallback = (_, __, ___, ____) => true } }; var channel = GrpcChannel.ForAddress("static:///localhost", new GrpcChannelOptions { LoggerFactory = LoggerFactory, ServiceProvider = services.BuildServiceProvider(), Credentials = ChannelCredentials.Create(new SslCredentials(), credentials), HttpHandler = socketsHttpHandler }); var client = TestClientFactory.Create(channel, endpoint1.Method); // Act var reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout(); // Assert Assert.AreEqual("Bearer TEST", authorization); Assert.AreEqual("Balancer", reply.Message); }
public async Task UnaryCall_MultipleCalls_RoundRobin() { // Ignore errors SetExpectedErrorsFilter(writeContext => { return(true); }); string?host = null; Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context) { host = context.Host; return(Task.FromResult(new HelloReply { Message = request.Name })); } // Arrange using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod)); using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod)); var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), new[] { endpoint1.Address, endpoint2.Address }, connect : true); await BalancerHelpers.WaitForSubchannelsToBeReadyAsync(Logger, channel, 2).DefaultTimeout(); var client = TestClientFactory.Create(channel, endpoint1.Method); // Act var reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout(); // Assert Assert.AreEqual("Balancer", reply.Message); var nextHost = GetNextHost(host !); // Act reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout(); // Assert Assert.AreEqual("Balancer", reply.Message); Assert.AreEqual(nextHost, host !); nextHost = GetNextHost(host !); // Act reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout(); // Assert Assert.AreEqual("Balancer", reply.Message); Assert.AreEqual(nextHost, host); string GetNextHost(string host) { return(host == "127.0.0.1:50051" ? "127.0.0.1:50052" : "127.0.0.1:50051"); } }
public async Task Unary_ServerResetCancellationStatus_DeadlineStatus() { TaskCompletionSource <object?> tcs = null !; async Task <DataMessage> UnaryTimeout(DataMessage request, ServerCallContext context) { var httpContext = context.GetHttpContext(); var resetFeature = httpContext.Features.Get <IHttpResetFeature>() !; await tcs.Task; // Reset needs to arrive in client after it has exceeded deadline. // Delay can be imprecise. Wait extra time to ensure client has exceeded deadline. await Task.Delay(50); var cancelErrorCode = (httpContext.Request.Protocol == "HTTP/2") ? 0x8 : 0x10c; resetFeature.Reset(cancelErrorCode); return(new DataMessage()); } // Arrange var method = Fixture.DynamicGrpc.AddUnaryMethod <DataMessage, DataMessage>(UnaryTimeout); var channel = CreateChannel(); channel.DisableClientDeadline = true; var client = TestClientFactory.Create(channel, method); var deadline = TimeSpan.FromMilliseconds(300); for (var i = 0; i < 5; i++) { tcs = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously); // Act var headers = new Metadata { { "remove-deadline", "true" } }; var call = client.UnaryCall(new DataMessage(), new CallOptions(headers: headers, deadline: DateTime.UtcNow.Add(deadline))); await Task.Delay(deadline); tcs.SetResult(null); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.DeadlineExceeded, ex.StatusCode); Assert.AreEqual(StatusCode.DeadlineExceeded, call.GetStatus().StatusCode); } }
private static async Task MakeCallsAsync(GrpcChannel channel, Method <DataMessage, DataMessage> method, List <WeakReference> references, CancellationToken cancellationToken) { var client = TestClientFactory.Create(channel, method); for (int i = 0; i < 10; i++) { var call = client.ServerStreamingCall(new DataMessage(), new CallOptions(cancellationToken: cancellationToken)); references.Add(new WeakReference(call.ResponseStream)); Assert.IsFalse(await call.ResponseStream.MoveNext()); } }