Skip to content

Commit 1344beb

Browse files
authored
Change error status when no message is returned in unary calls (#920)
1 parent c2cf536 commit 1344beb

File tree

4 files changed

+91
-6
lines changed

4 files changed

+91
-6
lines changed

src/Grpc.Net.Client/Internal/GrpcCall.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,12 @@ private async Task RunCall(HttpRequestMessage request, TimeSpan? timeout)
496496
// If it does then throw an error that no message was returned from the server.
497497
GrpcCallLog.MessageNotReturned(Logger);
498498

499+
// Change the status code to a more accurate status.
500+
// This is consistent with Grpc.Core client behavior.
501+
status = new Status(StatusCode.Internal, "Failed to deserialize response message.");
502+
499503
finished = FinishCall(request, diagnosticSourceEnabled, activity, status.Value);
500-
_responseTcs.TrySetException(new InvalidOperationException("Call did not return a response message."));
504+
SetFailedResult(status.Value);
501505
}
502506

503507
FinishResponseAndCleanUp(status.Value);
@@ -524,19 +528,28 @@ private async Task RunCall(HttpRequestMessage request, TimeSpan? timeout)
524528
singleMessage: true,
525529
_callCts.Token).ConfigureAwait(false);
526530
status = GrpcProtocolHelpers.GetResponseStatus(HttpResponse);
527-
FinishResponseAndCleanUp(status.Value);
528531

529532
if (message == null)
530533
{
531534
GrpcCallLog.MessageNotReturned(Logger);
532535

536+
if (status.Value.StatusCode == StatusCode.OK)
537+
{
538+
// Change the status code if OK is returned to a more accurate status.
539+
// This is consistent with Grpc.Core client behavior.
540+
status = new Status(StatusCode.Internal, "Failed to deserialize response message.");
541+
}
542+
543+
FinishResponseAndCleanUp(status.Value);
533544
finished = FinishCall(request, diagnosticSourceEnabled, activity, status.Value);
545+
534546
SetFailedResult(status.Value);
535547
}
536548
else
537549
{
538550
GrpcEventSource.Log.MessageReceived();
539551

552+
FinishResponseAndCleanUp(status.Value);
540553
finished = FinishCall(request, diagnosticSourceEnabled, activity, status.Value);
541554

542555
if (status.Value.StatusCode == StatusCode.OK)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#region Copyright notice and license
2+
3+
// Copyright 2019 The gRPC Authors
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
#endregion
18+
19+
using System;
20+
using System.Threading.Tasks;
21+
using Greet;
22+
using Grpc.AspNetCore.FunctionalTests.Infrastructure;
23+
using Grpc.Core;
24+
using Grpc.Tests.Shared;
25+
using NUnit.Framework;
26+
27+
namespace Grpc.AspNetCore.FunctionalTests.Client
28+
{
29+
[TestFixture]
30+
public class UnaryTests : FunctionalTestBase
31+
{
32+
[Test]
33+
public async Task ThrowErrorWithOK_ClientThrowsFailedToDeserializeError()
34+
{
35+
SetExpectedErrorsFilter(writeContext =>
36+
{
37+
if (writeContext.State.ToString() == "Message not returned from unary or client streaming call.")
38+
{
39+
return true;
40+
}
41+
42+
return false;
43+
});
44+
45+
Task<HelloReply> UnaryThrowError(HelloRequest request, ServerCallContext context)
46+
{
47+
return Task.FromException<HelloReply>(new RpcException(new Status(StatusCode.OK, "Message")));
48+
}
49+
50+
// Arrange
51+
var method = Fixture.DynamicGrpc.AddUnaryMethod<HelloRequest, HelloReply>(UnaryThrowError);
52+
var channel = CreateChannel();
53+
var client = TestClientFactory.Create(channel, method);
54+
55+
// Act
56+
var call = client.UnaryCall(new HelloRequest());
57+
58+
// Assert
59+
var ex = await ExceptionAssert.ThrowsAsync<RpcException>(() => call.ResponseAsync).DefaultTimeout();
60+
61+
Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
62+
Assert.AreEqual("Failed to deserialize response message.", ex.Status.Detail);
63+
64+
Assert.AreEqual(StatusCode.Internal, call.GetStatus().StatusCode);
65+
Assert.AreEqual("Failed to deserialize response message.", call.GetStatus().Detail);
66+
}
67+
}
68+
}

test/Grpc.Net.Client.Tests/AsyncClientStreamingCallTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ public async Task ClientStreamWriter_WriteAfterResponseHasFinished_ErrorThrown()
241241

242242
// Assert
243243
Assert.AreEqual("Can't write the message because the call is complete.", ex.Message);
244-
Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
244+
Assert.AreEqual(StatusCode.Internal, call.GetStatus().StatusCode);
245+
Assert.AreEqual("Failed to deserialize response message.", call.GetStatus().Detail);
245246
}
246247

247248
[Test]

test/Grpc.Net.Client.Tests/AsyncUnaryCallTests.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,17 @@ public async Task AsyncUnaryCall_SuccessTrailersOnly_ThrowNoMessageError()
158158
// Act
159159
var call = invoker.AsyncUnaryCall<HelloRequest, HelloReply>(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest());
160160
var headers = await call.ResponseHeadersAsync.DefaultTimeout();
161-
var response = await ExceptionAssert.ThrowsAsync<InvalidOperationException>(() => call.ResponseAsync).DefaultTimeout();
161+
var ex = await ExceptionAssert.ThrowsAsync<RpcException>(() => call.ResponseAsync).DefaultTimeout();
162162

163163
// Assert
164164
Assert.NotNull(responseMessage);
165165
Assert.IsFalse(responseMessage!.TrailingHeaders.Any()); // sanity check that there are no trailers
166166

167-
Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
168-
Assert.AreEqual("Detail!", call.GetStatus().Detail);
167+
Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
168+
Assert.AreEqual("Failed to deserialize response message.", ex.Status.Detail);
169+
170+
Assert.AreEqual(StatusCode.Internal, call.GetStatus().StatusCode);
171+
Assert.AreEqual("Failed to deserialize response message.", call.GetStatus().Detail);
169172

170173
Assert.AreEqual(0, headers.Count);
171174
Assert.AreEqual(0, call.GetTrailers().Count);

0 commit comments

Comments
 (0)