diff options
-rw-r--r-- | src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs | 31 | ||||
-rw-r--r-- | src/csharp/Grpc.Core/Internal/AsyncCallBase.cs | 6 |
2 files changed, 33 insertions, 4 deletions
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs index 605072b323..324b682510 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs @@ -160,7 +160,7 @@ namespace Grpc.Core.Internal.Tests } [Test] - public void ServerStreaming_NoResponse1_Success() + public void ServerStreaming_NoResponse_Success1() { asyncCall.StartServerStreamingCall("request1"); var responseStream = new ClientResponseStream<string, string>(asyncCall); @@ -176,7 +176,7 @@ namespace Grpc.Core.Internal.Tests } [Test] - public void ServerStreaming_NoResponse2_Success() + public void ServerStreaming_NoResponse_Success2() { asyncCall.StartServerStreamingCall("request1"); var responseStream = new ClientResponseStream<string, string>(asyncCall); @@ -192,6 +192,22 @@ namespace Grpc.Core.Internal.Tests AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask); } + [Test] + public void ServerStreaming_NoResponse_ReadFailure() + { + asyncCall.StartServerStreamingCall("request1"); + var responseStream = new ClientResponseStream<string, string>(asyncCall); + var readTask = responseStream.MoveNext(); + + fakeCall.ReceivedResponseHeadersHandler(true, new Metadata()); + Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count); + + fakeCall.ReceivedMessageHandler(false, null); // after a failed read, we rely on C core to deliver appropriate status code. + fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Internal)); + + AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Internal); + } + ClientSideStatus CreateClientSideStatus(StatusCode statusCode) { return new ClientSideStatus(new Status(statusCode, ""), new Metadata()); @@ -236,6 +252,17 @@ namespace Grpc.Core.Internal.Tests Assert.AreEqual(0, asyncCall.GetTrailers().Count); } + static void AssertStreamingResponseError(AsyncCall<string, string> asyncCall, FakeNativeCall fakeCall, Task<bool> moveNextTask, StatusCode expectedStatusCode) + { + Assert.IsTrue(moveNextTask.IsCompleted); + Assert.IsTrue(fakeCall.IsDisposed); + + var ex = Assert.ThrowsAsync<RpcException>(async () => await moveNextTask); + Assert.AreEqual(expectedStatusCode, asyncCall.GetStatus().StatusCode); + Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count); + Assert.AreEqual(0, asyncCall.GetTrailers().Count); + } + internal class FakeNativeCall : INativeCall { public UnaryResponseClientHandler UnaryResponseClientHandler diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index ccd047f469..877b997aba 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -346,6 +346,10 @@ namespace Grpc.Core.Internal /// </summary> protected void HandleReadFinished(bool success, byte[] receivedMessage) { + // if success == false, received message will be null. It that case we will + // treat this completion as the last read an rely on C core to handle the failed + // read (e.g. deliver approriate statusCode on the clientside). + TRead msg = default(TRead); var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null; @@ -370,8 +374,6 @@ namespace Grpc.Core.Internal ReleaseResourcesIfPossible(); } - // TODO: handle the case when success==false - if (deserializeException != null && !IsClient) { FireCompletion(origCompletionDelegate, default(TRead), new IOException("Failed to deserialize request message.", deserializeException)); |