From b2b54fe60fd0f9353ba536f8217fa8119a5bbb77 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 27 Jun 2017 14:37:01 +0200 Subject: [PATCH] add C# test demoing custom error details --- .../CustomErrorDetailsTest.cs | 112 ++++++++++++++++++ src/csharp/generate_proto_csharp.sh | 2 +- src/csharp/tests.json | 1 + 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/csharp/Grpc.IntegrationTesting/CustomErrorDetailsTest.cs diff --git a/src/csharp/Grpc.IntegrationTesting/CustomErrorDetailsTest.cs b/src/csharp/Grpc.IntegrationTesting/CustomErrorDetailsTest.cs new file mode 100644 index 00000000000..be996f91e03 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/CustomErrorDetailsTest.cs @@ -0,0 +1,112 @@ +#region Copyright notice and license + +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf; +using Grpc.Core; +using Grpc.Core.Utils; +using Grpc.Testing; +using NUnit.Framework; + +namespace Grpc.IntegrationTesting +{ + /// + /// Shows how to attach custom error details as a binary trailer. + /// + public class CustomErrorDetailsTest + { + const string DebugInfoTrailerName = "debug-info-bin"; + const string ExceptionDetail = "Exception thrown on purpose."; + const string Host = "localhost"; + Server server; + Channel channel; + TestService.TestServiceClient client; + + [TestFixtureSetUp] + public void Init() + { + // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755 + server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) + { + Services = { TestService.BindService(new CustomErrorDetailsTestServiceImpl()) }, + Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } + }; + server.Start(); + + channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure); + client = new TestService.TestServiceClient(channel); + } + + [TestFixtureTearDown] + public void Cleanup() + { + channel.ShutdownAsync().Wait(); + server.ShutdownAsync().Wait(); + } + + [Test] + public async Task UnaryCall() + { + var call = client.UnaryCallAsync(new SimpleRequest { ResponseSize = 10 }); + + try + { + await call.ResponseAsync; + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); + var debugInfo = GetDebugInfo(call.GetTrailers()); + Assert.AreEqual(debugInfo.Detail, ExceptionDetail); + Assert.IsNotEmpty(debugInfo.StackEntries); + } + } + + private DebugInfo GetDebugInfo(Metadata trailers) + { + var entry = trailers.First((e) => e.Key == DebugInfoTrailerName); + return DebugInfo.Parser.ParseFrom(entry.ValueBytes); + } + + private class CustomErrorDetailsTestServiceImpl : TestService.TestServiceBase + { + public override async Task UnaryCall(SimpleRequest request, ServerCallContext context) + { + try + { + throw new ArgumentException(ExceptionDetail); + } + catch (Exception e) + { + // Fill debug info with some structured details about the failure. + var debugInfo = new DebugInfo(); + debugInfo.Detail = e.Message; + debugInfo.StackEntries.AddRange(e.StackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None)); + context.ResponseTrailers.Add(DebugInfoTrailerName, debugInfo.ToByteArray()); + throw new RpcException(new Status(StatusCode.Unknown, "The handler threw exception.")); + } + } + } + } +} diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh index 8caaaabe0f5..1a1adbbae56 100755 --- a/src/csharp/generate_proto_csharp.sh +++ b/src/csharp/generate_proto_csharp.sh @@ -37,4 +37,4 @@ $PROTOC --plugin=$PLUGIN --csharp_out=$REFLECTION_DIR --grpc_out=$REFLECTION_DIR # don't match the package names. Setting -I to the correct value src/proto # breaks the code generation. $PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \ - -I . src/proto/grpc/testing/{control,empty,messages,metrics,payloads,services,stats,test}.proto + -I . src/proto/grpc/testing/{control,echo_messages,empty,messages,metrics,payloads,services,stats,test}.proto diff --git a/src/csharp/tests.json b/src/csharp/tests.json index 707d140f62c..bc6adbbfe8b 100644 --- a/src/csharp/tests.json +++ b/src/csharp/tests.json @@ -42,6 +42,7 @@ "Grpc.HealthCheck.Tests.HealthServiceImplTest" ], "Grpc.IntegrationTesting": [ + "Grpc.IntegrationTesting.CustomErrorDetailsTest", "Grpc.IntegrationTesting.GeneratedClientTest", "Grpc.IntegrationTesting.GeneratedServiceBaseTest", "Grpc.IntegrationTesting.HistogramTest",