• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Linq;
23 using System.Threading;
24 using System.Threading.Tasks;
25 using Grpc.Core;
26 using Grpc.Core.Internal;
27 using Grpc.Core.Profiling;
28 using Grpc.Core.Utils;
29 using NUnit.Framework;
30 
31 namespace Grpc.Core.Tests
32 {
33     public class ClientServerTest
34     {
35         const string Host = "127.0.0.1";
36 
37         MockServiceHelper helper;
38         Server server;
39         Channel channel;
40 
41         [SetUp]
Init()42         public void Init()
43         {
44             helper = new MockServiceHelper(Host);
45             server = helper.GetServer();
46             server.Start();
47             channel = helper.GetChannel();
48         }
49 
50         [TearDown]
Cleanup()51         public void Cleanup()
52         {
53             channel.ShutdownAsync().Wait();
54             server.ShutdownAsync().Wait();
55         }
56 
57         [Test]
UnaryCall()58         public async Task UnaryCall()
59         {
60             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
61             {
62                 return Task.FromResult(request);
63             });
64 
65             Assert.AreEqual("ABC", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "ABC"));
66 
67             Assert.AreEqual("ABC", await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "ABC"));
68         }
69 
70         [Test]
UnaryCall_ServerHandlerThrows()71         public void UnaryCall_ServerHandlerThrows()
72         {
73             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
74             {
75                 throw new Exception("This was thrown on purpose by a test");
76             });
77 
78             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
79             Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode);
80 
81             var ex2 = Assert.ThrowsAsync<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
82             Assert.AreEqual(StatusCode.Unknown, ex2.Status.StatusCode);
83         }
84 
85         [Test]
UnaryCall_ServerHandlerThrowsRpcException()86         public void UnaryCall_ServerHandlerThrowsRpcException()
87         {
88             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
89             {
90                 throw new RpcException(new Status(StatusCode.Unauthenticated, ""));
91             });
92 
93             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
94             Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode);
95             Assert.AreEqual(0, ex.Trailers.Count);
96 
97             var ex2 = Assert.ThrowsAsync<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
98             Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode);
99             Assert.AreEqual(0, ex.Trailers.Count);
100         }
101 
102         [Test]
UnaryCall_ServerHandlerThrowsRpcExceptionWithTrailers()103         public void UnaryCall_ServerHandlerThrowsRpcExceptionWithTrailers()
104         {
105             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
106             {
107                 var trailers = new Metadata { {"xyz", "xyz-value"} };
108                 throw new RpcException(new Status(StatusCode.Unauthenticated, ""), trailers);
109             });
110 
111             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
112             Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode);
113             Assert.AreEqual(1, ex.Trailers.Count);
114             Assert.AreEqual("xyz", ex.Trailers[0].Key);
115             Assert.AreEqual("xyz-value", ex.Trailers[0].Value);
116 
117             var ex2 = Assert.ThrowsAsync<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
118             Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode);
119             Assert.AreEqual(1, ex2.Trailers.Count);
120             Assert.AreEqual("xyz", ex2.Trailers[0].Key);
121             Assert.AreEqual("xyz-value", ex2.Trailers[0].Value);
122         }
123 
124         [Test]
UnaryCall_ServerHandlerSetsStatus()125         public void UnaryCall_ServerHandlerSetsStatus()
126         {
127             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
128             {
129                 context.Status = new Status(StatusCode.Unauthenticated, "");
130                 return Task.FromResult("");
131             });
132 
133             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
134             Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode);
135             Assert.AreEqual(0, ex.Trailers.Count);
136 
137             var ex2 = Assert.ThrowsAsync<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
138             Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode);
139             Assert.AreEqual(0, ex2.Trailers.Count);
140         }
141 
142         [Test]
UnaryCall_StatusDebugErrorStringNotTransmittedFromServer()143         public void UnaryCall_StatusDebugErrorStringNotTransmittedFromServer()
144         {
145             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
146             {
147                 context.Status = new Status(StatusCode.Unauthenticated, "", new CoreErrorDetailException("this DebugErrorString value should not be transmitted to the client"));
148                 return Task.FromResult("");
149             });
150 
151             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
152             Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode);
153             StringAssert.Contains("Error received from peer", ex.Status.DebugException.Message, "Is \"Error received from peer\" still a valid substring to search for in the client-generated error message from C-core?");
154             Assert.AreEqual(0, ex.Trailers.Count);
155 
156             var ex2 = Assert.ThrowsAsync<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
157             Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode);
158             StringAssert.Contains("Error received from peer", ex2.Status.DebugException.Message, "Is \"Error received from peer\" still a valid substring to search for in the client-generated error message from C-core?");
159             Assert.AreEqual(0, ex2.Trailers.Count);
160         }
161 
162         [Test]
UnaryCall_ServerHandlerSetsStatusAndTrailers()163         public void UnaryCall_ServerHandlerSetsStatusAndTrailers()
164         {
165             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
166             {
167                 context.Status = new Status(StatusCode.Unauthenticated, "");
168                 context.ResponseTrailers.Add("xyz", "xyz-value");
169                 return Task.FromResult("");
170             });
171 
172             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
173             Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode);
174             Assert.AreEqual(1, ex.Trailers.Count);
175             Assert.AreEqual("xyz", ex.Trailers[0].Key);
176             Assert.AreEqual("xyz-value", ex.Trailers[0].Value);
177 
178             var ex2 = Assert.ThrowsAsync<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
179             Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode);
180             Assert.AreEqual(1, ex2.Trailers.Count);
181             Assert.AreEqual("xyz", ex2.Trailers[0].Key);
182             Assert.AreEqual("xyz-value", ex2.Trailers[0].Value);
183         }
184 
185         [Test]
ClientStreamingCall()186         public async Task ClientStreamingCall()
187         {
188             helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
189             {
190                 string result = "";
191                 await requestStream.ForEachAsync((request) =>
192                 {
193                     result += request;
194                     return TaskUtils.CompletedTask;
195                 });
196                 await Task.Delay(100);
197                 return result;
198             });
199 
200             var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
201             await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
202             Assert.AreEqual("ABC", await call.ResponseAsync);
203 
204             Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
205             Assert.IsNotNull(call.GetTrailers());
206         }
207 
208         [Test]
ServerStreamingCall()209         public async Task ServerStreamingCall()
210         {
211             helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) =>
212             {
213                 await responseStream.WriteAllAsync(request.Split(new []{' '}));
214                 context.ResponseTrailers.Add("xyz", "");
215             });
216 
217             var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "A B C");
218             CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, await call.ResponseStream.ToListAsync());
219 
220             Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
221             Assert.AreEqual("xyz", call.GetTrailers()[0].Key);
222         }
223 
224         [Test]
ServerStreamingCall_EndOfStreamIsIdempotent()225         public async Task ServerStreamingCall_EndOfStreamIsIdempotent()
226         {
227             helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>((request, responseStream, context) => TaskUtils.CompletedTask);
228 
229             var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
230 
231             Assert.IsFalse(await call.ResponseStream.MoveNext());
232             Assert.IsFalse(await call.ResponseStream.MoveNext());
233         }
234 
235         [Test]
ServerStreamingCall_ErrorCanBeAwaitedTwice()236         public void ServerStreamingCall_ErrorCanBeAwaitedTwice()
237         {
238             helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>((request, responseStream, context) =>
239             {
240                 context.Status = new Status(StatusCode.InvalidArgument, "");
241                 return TaskUtils.CompletedTask;
242             });
243 
244             var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
245 
246             var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
247             Assert.AreEqual(StatusCode.InvalidArgument, ex.Status.StatusCode);
248 
249             // attempting MoveNext again should result in throwing the same exception.
250             var ex2 = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
251             Assert.AreEqual(StatusCode.InvalidArgument, ex2.Status.StatusCode);
252         }
253 
254         [Test]
ServerStreamingCall_TrailersFromMultipleSourcesGetConcatenated()255         public void ServerStreamingCall_TrailersFromMultipleSourcesGetConcatenated()
256         {
257             helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>((request, responseStream, context) =>
258             {
259                 context.ResponseTrailers.Add("xyz", "xyz-value");
260                 throw new RpcException(new Status(StatusCode.InvalidArgument, ""), new Metadata { {"abc", "abc-value"} });
261             });
262 
263             var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
264 
265             var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
266             Assert.AreEqual(StatusCode.InvalidArgument, ex.Status.StatusCode);
267             Assert.AreEqual(2, call.GetTrailers().Count);
268             Assert.AreEqual(2, ex.Trailers.Count);
269             Assert.AreEqual("xyz", ex.Trailers[0].Key);
270             Assert.AreEqual("xyz-value", ex.Trailers[0].Value);
271             Assert.AreEqual("abc", ex.Trailers[1].Key);
272             Assert.AreEqual("abc-value", ex.Trailers[1].Value);
273         }
274 
275         [Test]
DuplexStreamingCall()276         public async Task DuplexStreamingCall()
277         {
278             helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
279             {
280                 while (await requestStream.MoveNext())
281                 {
282                     await responseStream.WriteAsync(requestStream.Current);
283                 }
284                 context.ResponseTrailers.Add("xyz", "xyz-value");
285             });
286 
287             var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall());
288             await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
289             CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, await call.ResponseStream.ToListAsync());
290 
291             Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
292             Assert.AreEqual("xyz-value", call.GetTrailers()[0].Value);
293         }
294 
295         [Test]
AsyncUnaryCall_EchoMetadata()296         public async Task AsyncUnaryCall_EchoMetadata()
297         {
298             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
299             {
300                 foreach (Metadata.Entry metadataEntry in context.RequestHeaders)
301                 {
302                     if (metadataEntry.Key != "user-agent")
303                     {
304                         context.ResponseTrailers.Add(metadataEntry);
305                     }
306                 }
307                 return Task.FromResult("");
308             });
309 
310             var headers = new Metadata
311             {
312                 { "ascii-header", "abcdefg" },
313                 { "binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff } }
314             };
315             var call = Calls.AsyncUnaryCall(helper.CreateUnaryCall(new CallOptions(headers: headers)), "ABC");
316             await call;
317 
318             Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
319 
320             var trailers = call.GetTrailers();
321             Assert.AreEqual(2, trailers.Count);
322             Assert.AreEqual(headers[0].Key, trailers[0].Key);
323             Assert.AreEqual(headers[0].Value, trailers[0].Value);
324 
325             Assert.AreEqual(headers[1].Key, trailers[1].Key);
326             CollectionAssert.AreEqual(headers[1].ValueBytes, trailers[1].ValueBytes);
327         }
328 
329         [Test]
UnknownMethodHandler()330         public void UnknownMethodHandler()
331         {
332             var nonexistentMethod = new Method<string, string>(
333                 MethodType.Unary,
334                 MockServiceHelper.ServiceName,
335                 "NonExistentMethod",
336                 Marshallers.StringMarshaller,
337                 Marshallers.StringMarshaller);
338 
339             var callDetails = new CallInvocationDetails<string, string>(channel, nonexistentMethod, new CallOptions());
340 
341             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(callDetails, "abc"));
342             Assert.AreEqual(StatusCode.Unimplemented, ex.Status.StatusCode);
343         }
344 
345         [Test]
StatusDetailIsUtf8()346         public void StatusDetailIsUtf8()
347         {
348             // some japanese and chinese characters
349             var nonAsciiString = "\u30a1\u30a2\u30a3 \u62b5\u6297\u662f\u5f92\u52b3\u7684";
350             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
351             {
352                 context.Status = new Status(StatusCode.Unknown, nonAsciiString);
353                 return Task.FromResult("");
354             });
355 
356             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
357             Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode);
358             Assert.AreEqual(nonAsciiString, ex.Status.Detail);
359         }
360 
361         [Test]
ServerCallContext_PeerInfoPresent()362         public void ServerCallContext_PeerInfoPresent()
363         {
364             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
365             {
366                 return Task.FromResult(context.Peer);
367             });
368 
369             string peer = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc");
370             Assert.IsTrue(peer.Contains(Host));
371         }
372 
373         [Test]
ServerCallContext_HostAndMethodPresent()374         public void ServerCallContext_HostAndMethodPresent()
375         {
376             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
377             {
378                 Assert.IsTrue(context.Host.Contains(Host));
379                 Assert.AreEqual("/tests.Test/Unary", context.Method);
380                 return Task.FromResult("PASS");
381             });
382             Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
383         }
384 
385         [Test]
ServerCallContext_AuthContextNotPopulated()386         public void ServerCallContext_AuthContextNotPopulated()
387         {
388             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
389             {
390                 Assert.IsFalse(context.AuthContext.IsPeerAuthenticated);
391                 Assert.AreEqual(0, context.AuthContext.Properties.Count());
392                 return Task.FromResult("PASS");
393             });
394             Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
395         }
396     }
397 }
398