1 #region Copyright notice and license 2 3 // Copyright 2015 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.Collections.Generic; 21 using System.Diagnostics; 22 using System.IO; 23 using System.Linq; 24 using System.Threading; 25 using System.Threading.Tasks; 26 27 using Grpc.Core; 28 using Grpc.Core.Internal; 29 using Grpc.Core.Utils; 30 using NUnit.Framework; 31 32 namespace Grpc.Core.Tests 33 { 34 public class MarshallingErrorsTest 35 { 36 const string Host = "127.0.0.1"; 37 38 MockServiceHelper helper; 39 Server server; 40 Channel channel; 41 42 [SetUp] Init()43 public void Init() 44 { 45 var marshaller = new Marshaller<string>( 46 (str) => 47 { 48 if (str == "UNSERIALIZABLE_VALUE") 49 { 50 // Google.Protobuf throws exception inherited from IOException 51 throw new IOException("Error serializing the message."); 52 } 53 return System.Text.Encoding.UTF8.GetBytes(str); 54 }, 55 (payload) => 56 { 57 var s = System.Text.Encoding.UTF8.GetString(payload); 58 if (s == "UNPARSEABLE_VALUE") 59 { 60 // Google.Protobuf throws exception inherited from IOException 61 throw new IOException("Error parsing the message."); 62 } 63 return s; 64 }); 65 helper = new MockServiceHelper(Host, marshaller); 66 server = helper.GetServer(); 67 server.Start(); 68 channel = helper.GetChannel(); 69 } 70 71 [TearDown] Cleanup()72 public void Cleanup() 73 { 74 channel.ShutdownAsync().Wait(); 75 server.ShutdownAsync().Wait(); 76 } 77 78 [Test] ResponseParsingError_UnaryResponse()79 public void ResponseParsingError_UnaryResponse() 80 { 81 helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => 82 { 83 return Task.FromResult("UNPARSEABLE_VALUE"); 84 }); 85 86 var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "REQUEST")); 87 Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode); 88 } 89 90 [Test] ResponseParsingError_StreamingResponse()91 public void ResponseParsingError_StreamingResponse() 92 { 93 helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) => 94 { 95 await responseStream.WriteAsync("UNPARSEABLE_VALUE"); 96 await Task.Delay(10000); 97 }); 98 99 var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "REQUEST"); 100 var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext()); 101 Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode); 102 } 103 104 [Test] RequestParsingError_UnaryRequest()105 public void RequestParsingError_UnaryRequest() 106 { 107 helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => 108 { 109 return Task.FromResult("RESPONSE"); 110 }); 111 112 var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "UNPARSEABLE_VALUE")); 113 // Spec doesn't define the behavior. With the current implementation server handler throws exception which results in StatusCode.Unknown. 114 Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode); 115 } 116 117 [Test] RequestParsingError_StreamingRequest()118 public async Task RequestParsingError_StreamingRequest() 119 { 120 helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) => 121 { 122 try 123 { 124 // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. 125 await requestStream.MoveNext(); 126 Assert.Fail(); 127 } 128 catch (IOException) 129 { 130 } 131 return "RESPONSE"; 132 }); 133 134 var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); 135 await call.RequestStream.WriteAsync("UNPARSEABLE_VALUE"); 136 137 Assert.AreEqual("RESPONSE", await call); 138 } 139 140 [Test] RequestSerializationError_BlockingUnary()141 public void RequestSerializationError_BlockingUnary() 142 { 143 Assert.Throws<IOException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE")); 144 } 145 146 [Test] RequestSerializationError_AsyncUnary()147 public void RequestSerializationError_AsyncUnary() 148 { 149 Assert.ThrowsAsync<IOException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE")); 150 } 151 152 [Test] RequestSerializationError_ClientStreaming()153 public async Task RequestSerializationError_ClientStreaming() 154 { 155 helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) => 156 { 157 CollectionAssert.AreEqual(new[] { "A", "B" }, await requestStream.ToListAsync()); 158 return "RESPONSE"; 159 }); 160 var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); 161 await call.RequestStream.WriteAsync("A"); 162 Assert.ThrowsAsync<IOException>(async () => await call.RequestStream.WriteAsync("UNSERIALIZABLE_VALUE")); 163 await call.RequestStream.WriteAsync("B"); 164 await call.RequestStream.CompleteAsync(); 165 166 Assert.AreEqual("RESPONSE", await call); 167 } 168 } 169 } 170