Example #1
0
        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();
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
Example #4
0
        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);
        }
Example #5
0
            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);
            }
Example #6
0
        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");
        }
Example #7
0
        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());
        }
Example #8
0
        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);
        }
Example #10
0
        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);
        }
Example #12
0
        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());
        }
Example #13
0
        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"));
        }
Example #14
0
        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");
        }
Example #15
0
        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");
        }
Example #16
0
        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);
        }
Example #17
0
        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();
        }
Example #18
0
        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();
        }
Example #19
0
        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();
            }
        }
Example #20
0
        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);
        }
Example #21
0
        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());
        }
Example #22
0
        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);
        }
Example #23
0
        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");
        }
Example #24
0
        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);
        }
Example #25
0
        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.");
        }
Example #26
0
        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()));
        }
Example #27
0
        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);
        }
Example #28
0
        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");
            }
        }
Example #29
0
        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);
            }
        }
Example #30
0
        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());
            }
        }