public async Task AsyncUnaryCall_MissingStatus_ThrowError() { // Arrange var httpClient = ClientTestHelpers.CreateTestClient(async request => { var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply()).DefaultTimeout(); var response = ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent, grpcStatusCode: null); return(response); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual("No grpc-status found on response.", ex.Status.Detail); Assert.AreEqual(StatusCode.Cancelled, ex.StatusCode); Assert.AreEqual(StatusCode.Cancelled, call.GetStatus().StatusCode); }
public async Task AsyncClientStreamingCall_CompleteAndWriteAfterResult_Error() { // Arrange var requestContent = new MemoryStream(); var callCount = 0; var httpClient = ClientTestHelpers.CreateTestClient(async request => { Interlocked.Increment(ref callCount); _ = request.Content !.ReadAsStreamAsync(); var reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var serviceConfig = ServiceConfigHelpers.CreateHedgingServiceConfig(); var invoker = HttpClientCallInvokerFactory.Create(httpClient, serviceConfig: serviceConfig); // Act var call = invoker.AsyncClientStreamingCall <HelloRequest, HelloReply>(ClientTestHelpers.GetServiceMethod(MethodType.ClientStreaming), string.Empty, new CallOptions()); // Assert var responseMessage = await call.ResponseAsync.DefaultTimeout(); Assert.AreEqual("Hello world", responseMessage.Message); requestContent.Seek(0, SeekOrigin.Begin); await call.RequestStream.CompleteAsync().DefaultTimeout(); var ex = await ExceptionAssert.ThrowsAsync <InvalidOperationException>(() => call.RequestStream.WriteAsync(new HelloRequest { Name = "1" })).DefaultTimeout(); Assert.AreEqual("Request stream has already been completed.", ex.Message); }
public async Task AsyncUnaryCall_Success_HttpRequestMessagePopulated() { // Arrange HttpRequestMessage?httpRequestMessage = null; var httpClient = ClientTestHelpers.CreateTestClient(async request => { httpRequestMessage = request; HelloReply reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var rs = await invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); // Assert Assert.AreEqual("Hello world", rs.Message); Assert.IsNotNull(httpRequestMessage); Assert.AreEqual(new Version(2, 0), httpRequestMessage !.Version); Assert.AreEqual(HttpMethod.Post, httpRequestMessage.Method); Assert.AreEqual(new Uri("https://localhost/ServiceName/MethodName"), httpRequestMessage.RequestUri); Assert.AreEqual(new MediaTypeHeaderValue("application/grpc"), httpRequestMessage.Content.Headers.ContentType); Assert.AreEqual(GrpcProtocolConstants.TEHeader, httpRequestMessage.Headers.TE.Single()); Assert.AreEqual("identity,gzip,deflate", httpRequestMessage.Headers.GetValues(GrpcProtocolConstants.MessageAcceptEncodingHeader).Single()); var userAgent = httpRequestMessage.Headers.UserAgent.Single(); Assert.AreEqual(GrpcProtocolConstants.UserAgentHeader, userAgent); Assert.AreEqual("grpc-dotnet", userAgent.Product.Name); Assert.IsTrue(!string.IsNullOrEmpty(userAgent.Product.Version)); }
public async Task AsyncUnaryCall_Success_LogToFactory() { // Arrange var httpClient = ClientTestHelpers.CreateTestClient(async request => { // Trigger request stream serialization await request.Content !.ReadAsStreamAsync().DefaultTimeout(); var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply { Message = "Hello world" }).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var testSink = new TestSink(); var loggerFactory = new TestLoggerFactory(testSink, true); var invoker = HttpClientCallInvokerFactory.Create(httpClient, loggerFactory); // Act var rs = await invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); // Assert Assert.AreEqual("Hello world", rs.Message); var logs = testSink.Writes.Where(w => w.LogLevel >= Microsoft.Extensions.Logging.LogLevel.Debug).ToList(); Assert.AreEqual("Starting gRPC call. Method type: 'Unary', URI: 'https://localhost/ServiceName/MethodName'.", logs[0].State.ToString()); AssertScope(logs[0]); Assert.AreEqual("Sending message.", logs[1].State.ToString()); AssertScope(logs[1]); Assert.AreEqual("Reading message.", logs[2].State.ToString()); AssertScope(logs[2]); Assert.AreEqual("Finished gRPC call.", logs[3].State.ToString()); AssertScope(logs[3]);
public async Task AsyncUnaryCall_Success_RequestContentSent() { // Arrange HttpContent?content = null; var handler = TestHttpMessageHandler.Create(async request => { content = request.Content; HelloReply reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var invoker = HttpClientCallInvokerFactory.Create(handler, "http://localhost"); // Act var rs = await invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest { Name = "World" }); // Assert Assert.AreEqual("Hello world", rs.Message); Assert.IsNotNull(content); var requestContent = await content !.ReadAsStreamAsync().DefaultTimeout(); var requestMessage = await StreamSerializationHelper.ReadMessageAsync( requestContent, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, maximumMessageSize : null, GrpcProtocolConstants.DefaultCompressionProviders, singleMessage : true, CancellationToken.None).DefaultTimeout(); Assert.AreEqual("World", requestMessage !.Name); }
public async Task AsyncUnaryCall_OneAttempt_Success(int maxAttempts) { // Arrange var tcs = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously); var callCount = 0; var httpClient = ClientTestHelpers.CreateTestClient(async request => { Interlocked.Increment(ref callCount); await tcs.Task; await request.Content !.CopyToAsync(new MemoryStream()); var reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var serviceConfig = ServiceConfigHelpers.CreateHedgingServiceConfig(maxAttempts: maxAttempts); var invoker = HttpClientCallInvokerFactory.Create( httpClient, serviceConfig: serviceConfig, configure: o => o.MaxRetryAttempts = maxAttempts); // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest { Name = "World" }); // Assert await TestHelpers.AssertIsTrueRetryAsync(() => callCount == maxAttempts, "All calls made at once."); tcs.SetResult(null); var rs = await call.ResponseAsync.DefaultTimeout(); Assert.AreEqual("Hello world", rs.Message); Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode); }
public async Task AsyncUnaryCall_NoTrailers_WinHttpHandler_ThrowsError() { // Arrange var httpMessageHandler = TestHttpMessageHandler.Create(async request => { var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply()).DefaultTimeout(); var response = ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent); response.RequestMessage.Properties.Remove("__ResponseTrailers"); response.Headers.Add("custom", "ABC"); return response; }); var invoker = HttpClientCallInvokerFactory.Create(new WinHttpHandler(httpMessageHandler), "https://localhost"); // Act var call = invoker.AsyncUnaryCall<HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); var ex = await ExceptionAssert.ThrowsAsync<RpcException>(() => call.ResponseAsync).DefaultTimeout(); // Assert Assert.AreEqual(StatusCode.Cancelled, ex.StatusCode); Assert.AreEqual("No grpc-status found on response. Using gRPC with WinHttp has Windows and package version requirements. See https://aka.ms/aspnet/grpc/netstandard for details.", ex.Status.Detail); Assert.AreEqual(0, ex.Trailers.Count); }
public async Task AsyncUnaryCall_BadTrailersType_ThrowsError() { // Arrange var httpClient = ClientTestHelpers.CreateTestClient(async request => { var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply()).DefaultTimeout(); var response = ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent); response.RequestMessage.Properties["__ResponseTrailers"] = new object(); response.Headers.Add("custom", "ABC"); return response; }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var call = invoker.AsyncUnaryCall<HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); var ex = await ExceptionAssert.ThrowsAsync<RpcException>(() => call.ResponseAsync).DefaultTimeout(); // Assert Assert.AreEqual(StatusCode.Cancelled, ex.StatusCode); Assert.AreEqual("No grpc-status found on response.", ex.Status.Detail); Assert.AreEqual(0, ex.Trailers.Count); }
public async Task AsyncUnaryCall_PushbackExpicitDelay_DelayForSpecifiedDuration() { // Arrange Task?delayTask = null; var callCount = 0; var httpClient = ClientTestHelpers.CreateTestClient(async request => { callCount++; if (callCount == 1) { await request.Content !.CopyToAsync(new MemoryStream()); delayTask = Task.Delay(100); return(ResponseUtils.CreateHeadersOnlyResponse(HttpStatusCode.OK, StatusCode.Unavailable, retryPushbackHeader: "200")); } var reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var serviceConfig = ServiceConfigHelpers.CreateRetryServiceConfig(backoffMultiplier: 1); var invoker = HttpClientCallInvokerFactory.Create(httpClient, serviceConfig: serviceConfig); // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest { Name = "World" }); // Delay of 100ms will finish before second record which has a pushback delay of 200ms var completedTask = await Task.WhenAny(call.ResponseAsync, delayTask !).DefaultTimeout(); var rs = await call.ResponseAsync.DefaultTimeout(); // Assert Assert.AreEqual(delayTask, completedTask); // Response task should finish after Assert.AreEqual(2, callCount); Assert.AreEqual("Hello world", rs.Message); }
public async Task AsyncUnaryCall_Success_SuccussCommitLogged() { // Arrange var testSink = new TestSink(); var services = new ServiceCollection(); services.AddLogging(b => { b.AddProvider(new TestLoggerProvider(testSink)); }); services.AddNUnitLogger(); var provider = services.BuildServiceProvider(); var httpClient = ClientTestHelpers.CreateTestClient(async request => { var content = request.Content !; await content.CopyToAsync(new MemoryStream()); var reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var serviceConfig = ServiceConfigHelpers.CreateRetryServiceConfig(); var invoker = HttpClientCallInvokerFactory.Create(httpClient, loggerFactory: provider.GetRequiredService <ILoggerFactory>(), serviceConfig: serviceConfig); // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.GetServiceMethod(MethodType.Unary), string.Empty, new CallOptions(), new HelloRequest { Name = "World" }); await call.ResponseAsync.DefaultTimeout(); // Assert var log = testSink.Writes.Single(w => w.EventId.Name == "CallCommited"); Assert.AreEqual("Call commited. Reason: ResponseHeadersReceived", log.State.ToString()); }
public async Task AsyncUnaryCall_Success_ResponseHeadersPopulated() { // Arrange var httpClient = ClientTestHelpers.CreateTestClient(async request => { HelloReply reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); var response = ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent); response.Headers.Server.Add(new ProductInfoHeaderValue("TestName", "1.0")); response.Headers.Add("custom", "ABC"); response.Headers.Add("binary-bin", Convert.ToBase64String(Encoding.UTF8.GetBytes("Hello world"))); return(response); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); var responseHeaders1 = await call.ResponseHeadersAsync.DefaultTimeout(); var responseHeaders2 = await call.ResponseHeadersAsync.DefaultTimeout(); // Assert Assert.AreSame(responseHeaders1, responseHeaders2); var header = responseHeaders1.Single(h => h.Key == "server"); Assert.AreEqual("TestName/1.0", header.Value); header = responseHeaders1.Single(h => h.Key == "custom"); Assert.AreEqual("ABC", header.Value); header = responseHeaders1.Single(h => h.Key == "binary-bin"); Assert.AreEqual(true, header.IsBinary); CollectionAssert.AreEqual(Encoding.UTF8.GetBytes("Hello world"), header.ValueBytes); }
public async Task AsyncUnaryCall_InvalidStatus_ThrowError() { // Arrange var httpClient = ClientTestHelpers.CreateTestClient(async request => { var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply()).DefaultTimeout(); var response = ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent, grpcStatusCode: null); response.TrailingHeaders.Add(GrpcProtocolConstants.StatusTrailer, "value"); return(response); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); // Assert await ExceptionAssert.ThrowsAsync <InvalidOperationException>(() => call.ResponseAsync).DefaultTimeout(); var ex = Assert.Throws <InvalidOperationException>(() => call.GetStatus()); Assert.AreEqual("Unexpected grpc-status value: value", ex.Message); }
public async Task CompositeCallCredentialsWithHttps_MetadataOnRequest() { // Arrange HttpRequestHeaders?requestHeaders = null; var httpClient = ClientTestHelpers.CreateTestClient(async request => { requestHeaders = request.Headers; var reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); var first = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => { metadata.Add("first_authorization", "FIRST_SECRET_TOKEN"); return(Task.CompletedTask); })); var second = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => { metadata.Add("second_authorization", "SECOND_SECRET_TOKEN"); return(Task.CompletedTask); })); var third = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => { metadata.Add("third_authorization", "THIRD_SECRET_TOKEN"); return(Task.CompletedTask); })); // Act var callCredentials = CallCredentials.Compose(first, second, third); var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(credentials: callCredentials), new HelloRequest()); await call.ResponseAsync.DefaultTimeout(); // Assert Assert.AreEqual("FIRST_SECRET_TOKEN", requestHeaders !.GetValues("first_authorization").Single()); Assert.AreEqual("SECOND_SECRET_TOKEN", requestHeaders !.GetValues("second_authorization").Single()); Assert.AreEqual("THIRD_SECRET_TOKEN", requestHeaders !.GetValues("third_authorization").Single()); }
public async Task AsyncUnaryCall_HeadersReturned_ReturnsTrailers() { // Arrange var httpClient = ClientTestHelpers.CreateTestClient(async request => { var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply()).DefaultTimeout(); var response = ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent); response.Headers.Add("custom", "ABC"); response.TrailingHeaders.Add("custom-header", "value"); return(response); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); var responseHeaders = await call.ResponseHeadersAsync.DefaultTimeout(); var trailers = call.GetTrailers(); // Assert Assert.AreEqual("value", trailers.Single(t => t.Key == "custom-header").Value); }
private async Task <HttpResponseMessage> HandleRequest(HttpRequestMessage request) { var requestStream = await request.Content !.ReadAsStreamAsync().DefaultTimeout(); var helloRequest = await StreamSerializationHelper.ReadMessageAsync( requestStream, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, "gzip", maximumMessageSize : null, GrpcProtocolConstants.DefaultCompressionProviders, singleMessage : true, CancellationToken.None).DefaultTimeout(); var reply = new HelloReply { Message = "Hello " + helloRequest !.Name }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }
public void Intercept_InterceptorOrder_ExecutedInReversedOrder() { // Arrange var httpClient = ClientTestHelpers.CreateTestClient(async request => { var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply { Message = "PASS" }).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var stringBuilder = new StringBuilder(); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var callInvoker = invoker.Intercept(metadata => { stringBuilder.Append("interceptor1"); return(metadata); }).Intercept(new CallbackInterceptor(() => stringBuilder.Append("array1")), new CallbackInterceptor(() => stringBuilder.Append("array2")), new CallbackInterceptor(() => stringBuilder.Append("array3"))) .Intercept(metadata => { stringBuilder.Append("interceptor2"); return(metadata); }).Intercept(metadata => { stringBuilder.Append("interceptor3"); return(metadata); }); var result = callInvoker.BlockingUnaryCall(ClientTestHelpers.ServiceMethod, Host, new CallOptions(), new HelloRequest()); // Assert Assert.AreEqual("PASS", result.Message); Assert.AreEqual("interceptor3interceptor2array1array2array3interceptor1", stringBuilder.ToString()); }
public async Task AsyncUnaryCall_SetSecondDeadline_RequestMessageContainsDeadlineHeader() { // Arrange HttpRequestMessage?httpRequestMessage = null; var httpClient = ClientTestHelpers.CreateTestClient(async request => { httpRequestMessage = request; var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply()).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var invoker = HttpClientCallInvokerFactory.Create( httpClient, systemClock: new TestSystemClock(new DateTime(2019, 11, 29, 1, 1, 1, DateTimeKind.Utc))); // Act await invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(deadline : invoker.Channel.Clock.UtcNow.AddSeconds(1)), new HelloRequest()); // Assert Assert.IsNotNull(httpRequestMessage); Assert.AreEqual("1S", httpRequestMessage !.Headers.GetValues(GrpcProtocolConstants.TimeoutHeader).Single()); }
public async Task AsyncUnaryCall_MultipleStatusHeaders_ThrowError() { // Arrange var httpClient = ClientTestHelpers.CreateTestClient(async request => { var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply()).DefaultTimeout(); var response = ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent, grpcStatusCode: StatusCode.Aborted); response.TrailingHeaders.Add(GrpcProtocolConstants.MessageTrailer, "one"); response.TrailingHeaders.Add(GrpcProtocolConstants.MessageTrailer, "two"); return(response); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual("Multiple grpc-message headers.", ex.Status.Detail); Assert.AreEqual(StatusCode.Cancelled, ex.StatusCode); Assert.AreEqual(StatusCode.Cancelled, call.GetStatus().StatusCode); }
public async Task Intercept_WrapClientStream_ClientStreamWrapperExecuted() { // Arrange var serviceMethod = new Method <string, string>(MethodType.Unary, "ServiceName", "Unary", Marshallers.StringMarshaller, Marshallers.StringMarshaller); var httpClient = ClientTestHelpers.CreateTestClient(async request => { var requestContent = await request.Content.ReadAsStreamAsync(); await requestContent.CopyToAsync(new MemoryStream()); var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply { Message = "PASS" }).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var stringBuilder = new StringBuilder(); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var callInvoker = invoker.Intercept(new ClientStreamingCountingInterceptor()); var call = callInvoker.AsyncClientStreamingCall(serviceMethod, Host, new CallOptions()); await call.RequestStream.WriteAsync("A"); await call.RequestStream.WriteAsync("B"); await call.RequestStream.WriteAsync("C"); await call.RequestStream.CompleteAsync(); // Assert Assert.AreEqual("3", await call.ResponseAsync); Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode); Assert.IsNotNull(call.GetTrailers()); }
public async Task AsyncServerStreamingCall_MessagesReturnedTogether_MessagesReceived() { // Arrange var httpClient = ClientTestHelpers.CreateTestClient(async request => { var streamContent = await ClientTestHelpers.CreateResponseContent( new HelloReply { Message = "Hello world 1" }, new HelloReply { Message = "Hello world 2" }).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var call = invoker.AsyncServerStreamingCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); var responseStream = call.ResponseStream; // Assert Assert.IsNull(responseStream.Current); Assert.IsTrue(await responseStream.MoveNext(CancellationToken.None).DefaultTimeout()); Assert.IsNotNull(responseStream.Current); Assert.AreEqual("Hello world 1", responseStream.Current.Message); Assert.IsTrue(await responseStream.MoveNext(CancellationToken.None).DefaultTimeout()); Assert.IsNotNull(responseStream.Current); Assert.AreEqual("Hello world 2", responseStream.Current.Message); Assert.IsFalse(await responseStream.MoveNext(CancellationToken.None).DefaultTimeout()); }
public async Task ResolverReturnsNoAddresses_DisposeWhileWaitForReady_Error() { // Arrange var testMessageHandler = TestHttpMessageHandler.Create(async request => { var reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var services = new ServiceCollection(); var resolver = new TestResolver(); services.AddSingleton <ResolverFactory>(new TestResolverFactory(resolver)); services.AddSingleton <ISubchannelTransportFactory>(new TestSubchannelTransportFactory()); var invoker = HttpClientCallInvokerFactory.Create(testMessageHandler, "test:///localhost", configure: o => { o.Credentials = ChannelCredentials.Insecure; o.ServiceProvider = services.BuildServiceProvider(); }); // Act var callOptions = new CallOptions().WithWaitForReady(); var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, callOptions, new HelloRequest()); var exTask = ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync); call.Dispose(); var ex = await exTask.DefaultTimeout(); Assert.AreEqual(StatusCode.Cancelled, ex.StatusCode); Assert.AreEqual("gRPC call disposed.", ex.Status.Detail); }
public async Task AsyncUnaryCall_ErrorParsingTrailers_ThrowsError() { // Arrange var testSink = new TestSink(); var loggerFactory = new TestLoggerFactory(testSink, true); var httpClient = ClientTestHelpers.CreateTestClient(async request => { var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply()).DefaultTimeout(); var response = ResponseUtils.CreateResponse( HttpStatusCode.OK, streamContent, grpcStatusCode: StatusCode.Aborted, customTrailers: new Dictionary <string, string> { ["blah-bin"] = "!" }); response.Headers.Add("custom", "ABC"); return(response); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient, loggerFactory); // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest()); var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); // Assert Assert.AreEqual(StatusCode.Aborted, ex.StatusCode); Assert.AreEqual(null, ex.Status.Detail); Assert.AreEqual(0, ex.Trailers.Count); var log = testSink.Writes.Single(w => w.EventId.Name == "ErrorParsingTrailers"); Assert.AreEqual("Error parsing trailers.", log.State.ToString()); Assert.AreEqual("Invalid Base-64 header value.", log.Exception.Message); }
public void InterceptMetadata_AddRequestHeader_HeaderInRequest() { // Arrange const string HeaderKey = "x-client-interceptor"; const string HeaderValue = "hello-world"; string?requestHeaderValue = null; var httpClient = ClientTestHelpers.CreateTestClient(async request => { if (request.Headers.TryGetValues(HeaderKey, out var values)) { requestHeaderValue = values.Single(); } var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply { Message = "PASS" }).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var callInvoker = invoker.Intercept(metadata => { metadata = metadata ?? new Metadata(); metadata.Add(new Metadata.Entry(HeaderKey, HeaderValue)); return(metadata); }); var result = callInvoker.BlockingUnaryCall(ClientTestHelpers.ServiceMethod, Host, new CallOptions(), new HelloRequest()); // Assert Assert.AreEqual("PASS", result.Message); Assert.AreEqual(HeaderValue, requestHeaderValue); }
public async Task CallCredentialsWithHttp_NoMetadataOnRequest() { // Arrange bool?hasAuthorizationValue = null; var httpClient = ClientTestHelpers.CreateTestClient(async request => { hasAuthorizationValue = request.Headers.TryGetValues("authorization", out _); var reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }, new Uri("http://localhost")); var testSink = new TestSink(); var loggerFactory = new TestLoggerFactory(testSink, true); var invoker = HttpClientCallInvokerFactory.Create(httpClient, loggerFactory); // Act var callCredentials = CallCredentials.FromInterceptor((context, metadata) => { metadata.Add("authorization", "SECRET_TOKEN"); return(Task.CompletedTask); }); var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(credentials: callCredentials), new HelloRequest()); await call.ResponseAsync.DefaultTimeout(); // Assert Assert.AreEqual(false, hasAuthorizationValue); var log = testSink.Writes.Single(w => w.EventId.Name == "CallCredentialsNotUsed"); Assert.AreEqual("The configured CallCredentials were not used because the call does not use TLS.", log.State.ToString()); }
public async Task AsyncClientStreamingCall_Success_RequestContentSent() { // Arrange PushStreamContent <HelloRequest, HelloReply>?content = null; var httpClient = ClientTestHelpers.CreateTestClient(async request => { content = (PushStreamContent <HelloRequest, HelloReply>)request.Content !; await content.PushComplete.DefaultTimeout(); HelloReply reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); // Act var call = invoker.AsyncClientStreamingCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions()); // Assert Assert.IsNotNull(call); Assert.IsNotNull(content); var responseTask = call.ResponseAsync; Assert.IsFalse(responseTask.IsCompleted, "Response not returned until client stream is complete."); var streamTask = content !.ReadAsStreamAsync().DefaultTimeout(); await call.RequestStream.WriteAsync(new HelloRequest { Name = "1" }).DefaultTimeout(); await call.RequestStream.WriteAsync(new HelloRequest { Name = "2" }).DefaultTimeout(); await call.RequestStream.CompleteAsync().DefaultTimeout(); var requestContent = await streamTask.DefaultTimeout(); var requestMessage = await requestContent.ReadMessageAsync( NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, maximumMessageSize : null, GrpcProtocolConstants.DefaultCompressionProviders, singleMessage : false, CancellationToken.None).AsTask().DefaultTimeout(); Assert.AreEqual("1", requestMessage !.Name); requestMessage = await requestContent.ReadMessageAsync( NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, maximumMessageSize : null, GrpcProtocolConstants.DefaultCompressionProviders, singleMessage : false, CancellationToken.None).AsTask().DefaultTimeout(); Assert.AreEqual("2", requestMessage !.Name); var responseMessage = await responseTask.DefaultTimeout(); Assert.AreEqual("Hello world", responseMessage.Message); }
public async Task AsyncUnaryCall_CompressMetadataSentWithRequest_RequestMessageCompressed(bool compressionDisabledOnOptions) { // Arrange HttpRequestMessage?httpRequestMessage = null; HelloRequest? helloRequest = null; bool?isRequestNotCompressed = null; var httpClient = ClientTestHelpers.CreateTestClient(async request => { httpRequestMessage = request; var requestData = await request.Content.ReadAsByteArrayAsync(); isRequestNotCompressed = requestData[0] == 0; helloRequest = await StreamExtensions.ReadSingleMessageAsync( new MemoryStream(requestData), NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, "gzip", maximumMessageSize: null, GrpcProtocolConstants.DefaultCompressionProviders, CancellationToken.None); HelloReply reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var compressionProviders = GrpcProtocolConstants.DefaultCompressionProviders.Values.ToList(); compressionProviders.Add(new TestCompressionProvider()); var invoker = HttpClientCallInvokerFactory.Create(httpClient, configure: o => o.CompressionProviders = compressionProviders); var compressionMetadata = CreateClientCompressionMetadata("gzip"); var callOptions = new CallOptions(headers: compressionMetadata); if (compressionDisabledOnOptions) { callOptions = callOptions.WithWriteOptions(new WriteOptions(WriteFlags.NoCompress)); } // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, callOptions, new HelloRequest { Name = "Hello" }); // Assert var response = await call.ResponseAsync; Assert.IsNotNull(response); Assert.AreEqual("Hello world", response.Message); Debug.Assert(httpRequestMessage != null); Assert.AreEqual("identity,gzip,deflate,test", httpRequestMessage.Headers.GetValues(GrpcProtocolConstants.MessageAcceptEncodingHeader).Single()); Assert.AreEqual("gzip", httpRequestMessage.Headers.GetValues(GrpcProtocolConstants.MessageEncodingHeader).Single()); Assert.AreEqual(false, httpRequestMessage.Headers.Contains(GrpcProtocolConstants.CompressionRequestAlgorithmHeader)); Debug.Assert(helloRequest != null); Assert.AreEqual("Hello", helloRequest.Name); Assert.AreEqual(compressionDisabledOnOptions, isRequestNotCompressed); }
public async Task AsyncClientStreamingCall_Success_RequestContentSent() { // Arrange var requestContentTcs = new TaskCompletionSource <Task <Stream> >(TaskCreationOptions.RunContinuationsAsynchronously); PushStreamContent <HelloRequest, HelloReply>?content = null; var handler = TestHttpMessageHandler.Create(async request => { content = (PushStreamContent <HelloRequest, HelloReply>)request.Content !; var streamTask = content.ReadAsStreamAsync(); requestContentTcs.SetResult(streamTask); // Wait for RequestStream.CompleteAsync() await streamTask; HelloReply reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var invoker = HttpClientCallInvokerFactory.Create(handler, "http://localhost"); // Act var call = invoker.AsyncClientStreamingCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions()); var requestContentTask = await requestContentTcs.Task.DefaultTimeout(); // Assert Assert.IsNotNull(call); Assert.IsNotNull(content); var responseTask = call.ResponseAsync; Assert.IsFalse(responseTask.IsCompleted, "Response not returned until client stream is complete."); await call.RequestStream.WriteAsync(new HelloRequest { Name = "1" }).DefaultTimeout(); await call.RequestStream.WriteAsync(new HelloRequest { Name = "2" }).DefaultTimeout(); await call.RequestStream.CompleteAsync().DefaultTimeout(); var requestContent = await requestContentTask.DefaultTimeout(); var requestMessage = await StreamSerializationHelper.ReadMessageAsync( requestContent, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, maximumMessageSize : null, GrpcProtocolConstants.DefaultCompressionProviders, singleMessage : false, CancellationToken.None).DefaultTimeout(); Assert.AreEqual("1", requestMessage !.Name); requestMessage = await StreamSerializationHelper.ReadMessageAsync( requestContent, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, maximumMessageSize : null, GrpcProtocolConstants.DefaultCompressionProviders, singleMessage : false, CancellationToken.None).DefaultTimeout(); Assert.AreEqual("2", requestMessage !.Name); var responseMessage = await responseTask.DefaultTimeout(); Assert.AreEqual("Hello world", responseMessage.Message); }
public async Task PickAsync_HedgingWithDrop_ThrowsError() { // Arrange string?authority = null; var testMessageHandler = TestHttpMessageHandler.Create(async request => { authority = request.RequestUri !.Authority; var reply = new HelloReply { Message = "Hello world" }; var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var services = new ServiceCollection(); services.AddNUnitLogger(); services.AddSingleton <TestResolver>(); services.AddSingleton <ResolverFactory, TestResolverFactory>(); DropLoadBalancer?loadBalancer = null; services.AddSingleton <LoadBalancerFactory>(new DropLoadBalancerFactory(c => { loadBalancer = new DropLoadBalancer(c); return(loadBalancer); })); services.AddSingleton <ISubchannelTransportFactory>(new TestSubchannelTransportFactory()); var invoker = HttpClientCallInvokerFactory.Create(testMessageHandler, "test:///localhost", configure: o => { o.Credentials = ChannelCredentials.Insecure; o.ServiceProvider = services.BuildServiceProvider(); o.ServiceConfig = new ServiceConfig { MethodConfigs = { new MethodConfig { Names = { MethodName.Default }, HedgingPolicy = new HedgingPolicy { MaxAttempts = 5, HedgingDelay = TimeSpan.FromMinutes(10), NonFatalStatusCodes ={ StatusCode.DataLoss } } } }, LoadBalancingConfigs = { new LoadBalancingConfig("drop") } }; }); // Act var call = invoker.AsyncUnaryCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions().WithWaitForReady(), new HelloRequest()); // Assert var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.DataLoss, ex.StatusCode); Assert.AreEqual(1, loadBalancer !.PickCount); }
public void DiagnosticListener_MakeCall_ActivityWritten() { // Arrange HttpRequestMessage? requestMessage = null; HttpResponseMessage?responseMessage = null; var httpClient = ClientTestHelpers.CreateTestClient(async request => { requestMessage = request; var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply()).DefaultTimeout(); responseMessage = ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent, grpcStatusCode: StatusCode.Aborted); responseMessage.TrailingHeaders().Add(GrpcProtocolConstants.MessageTrailer, "value"); return(responseMessage); }); var invoker = HttpClientCallInvokerFactory.Create(httpClient); var result = new List <KeyValuePair <string, object?> >(); var dataMessageMarshaller = new Marshaller <DataMessage>(m => m.ToByteArray(), data => DataMessage.Parser.ParseFrom(data)); var dataMessageMethod = ClientTestHelpers.GetServiceMethod <DataMessage, DataMessage>( MethodType.DuplexStreaming, dataMessageMarshaller, dataMessageMarshaller); // Act HttpRequestMessage? requestMessage1 = null; HttpResponseMessage?responseMessage1 = null; HttpRequestMessage? requestMessage2 = null; HttpResponseMessage?responseMessage2 = null; using (GrpcDiagnostics.DiagnosticListener.Subscribe(new ObserverToList <KeyValuePair <string, object?> >(result))) { var c1 = invoker.AsyncDuplexStreamingCall <HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions()); c1.Dispose(); requestMessage1 = requestMessage; responseMessage1 = responseMessage; var c2 = invoker.AsyncDuplexStreamingCall <DataMessage, DataMessage>(dataMessageMethod, string.Empty, new CallOptions()); c2.Dispose(); requestMessage2 = requestMessage; responseMessage2 = responseMessage; } // Assert Assert.AreEqual(4, result.Count); // First call Assert.AreEqual(GrpcDiagnostics.ActivityStartKey, result[0].Key); Assert.AreEqual(requestMessage1, GetValueFromAnonymousType <HttpRequestMessage>(result[0].Value !, "Request")); Assert.AreEqual(GrpcDiagnostics.ActivityStopKey, result[1].Key); Assert.AreEqual(requestMessage1, GetValueFromAnonymousType <HttpRequestMessage>(result[1].Value !, "Request")); Assert.AreEqual(responseMessage1, GetValueFromAnonymousType <HttpResponseMessage>(result[1].Value !, "Response")); // Second call Assert.AreEqual(GrpcDiagnostics.ActivityStartKey, result[2].Key); Assert.AreEqual(requestMessage2, GetValueFromAnonymousType <HttpRequestMessage>(result[2].Value !, "Request")); Assert.AreEqual(GrpcDiagnostics.ActivityStopKey, result[3].Key); Assert.AreEqual(requestMessage2, GetValueFromAnonymousType <HttpRequestMessage>(result[3].Value !, "Request")); Assert.AreEqual(responseMessage2, GetValueFromAnonymousType <HttpResponseMessage>(result[3].Value !, "Response")); // Check types are expected Assert.AreEqual(typeof(GrpcCall.ActivityStartData), result[0].Value !.GetType()); Assert.AreEqual(typeof(GrpcCall.ActivityStopData), result[1].Value !.GetType()); Assert.AreEqual(result[0].Value !.GetType(), result[2].Value !.GetType()); Assert.AreEqual(result[1].Value !.GetType(), result[3].Value !.GetType()); // Check values are unique for each call Assert.AreNotEqual(result[0].Value, result[2].Value); Assert.AreNotEqual(result[1].Value, result[3].Value); }
public async Task CreateClient_ServerCallContextAndUserCancellationToken_PropogatedDeadlineAndCancellation(Canceller canceller) { // Arrange var baseAddress = new Uri("http://localhost"); var deadline = DateTime.UtcNow.AddDays(1); var contextCts = new CancellationTokenSource(); var userCts = new CancellationTokenSource(); var tcs = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously); CallOptions options = default; var handler = TestHttpMessageHandler.Create(async(r, token) => { token.Register(() => tcs.SetCanceled()); await tcs.Task; var streamContent = await ClientTestHelpers.CreateResponseContent(new HelloReply()).DefaultTimeout(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent)); }); var services = new ServiceCollection(); services.AddOptions(); services.AddSingleton(CreateHttpContextAccessorWithServerCallContext(deadline, contextCts.Token)); services .AddGrpcClient <Greeter.GreeterClient>(o => { o.Address = baseAddress; }) .EnableCallContextPropagation() .AddInterceptor(() => new CallbackInterceptor(o => options = o)) .ConfigurePrimaryHttpMessageHandler(() => handler); var serviceProvider = services.BuildServiceProvider(validateScopes: true); var clientFactory = CreateGrpcClientFactory(serviceProvider); var client = clientFactory.CreateClient <Greeter.GreeterClient>(nameof(Greeter.GreeterClient)); // Act using var call = client.SayHelloAsync(new HelloRequest(), cancellationToken: userCts.Token); var responseTask = call.ResponseAsync; // Assert Assert.AreEqual(deadline, options.Deadline); // CancellationToken passed to call is a linked cancellation token. // It's created from the context and user tokens. Assert.AreNotEqual(contextCts.Token, options.CancellationToken); Assert.AreNotEqual(userCts.Token, options.CancellationToken); Assert.AreNotEqual(CancellationToken.None, options.CancellationToken); Assert.IsFalse(responseTask.IsCompleted); // Either CTS should cancel call. switch (canceller) { case Canceller.Context: contextCts.Cancel(); break; case Canceller.User: userCts.Cancel(); break; } var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => responseTask).DefaultTimeout(); Assert.AreEqual(StatusCode.Cancelled, ex.StatusCode); ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => call.ResponseHeadersAsync).DefaultTimeout(); Assert.AreEqual(StatusCode.Cancelled, ex.StatusCode); Assert.AreEqual(StatusCode.Cancelled, call.GetStatus().StatusCode); Assert.Throws <InvalidOperationException>(() => call.GetTrailers()); }