• 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_ServerHandlerSetsStatusAndTrailers()143         public void UnaryCall_ServerHandlerSetsStatusAndTrailers()
144         {
145             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
146             {
147                 context.Status = new Status(StatusCode.Unauthenticated, "");
148                 context.ResponseTrailers.Add("xyz", "xyz-value");
149                 return Task.FromResult("");
150             });
151 
152             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
153             Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode);
154             Assert.AreEqual(1, ex.Trailers.Count);
155             Assert.AreEqual("xyz", ex.Trailers[0].Key);
156             Assert.AreEqual("xyz-value", ex.Trailers[0].Value);
157 
158             var ex2 = Assert.ThrowsAsync<RpcException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"));
159             Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode);
160             Assert.AreEqual(1, ex2.Trailers.Count);
161             Assert.AreEqual("xyz", ex2.Trailers[0].Key);
162             Assert.AreEqual("xyz-value", ex2.Trailers[0].Value);
163         }
164 
165         [Test]
ClientStreamingCall()166         public async Task ClientStreamingCall()
167         {
168             helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
169             {
170                 string result = "";
171                 await requestStream.ForEachAsync((request) =>
172                 {
173                     result += request;
174                     return TaskUtils.CompletedTask;
175                 });
176                 await Task.Delay(100);
177                 return result;
178             });
179 
180             var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
181             await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
182             Assert.AreEqual("ABC", await call.ResponseAsync);
183 
184             Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
185             Assert.IsNotNull(call.GetTrailers());
186         }
187 
188         [Test]
ServerStreamingCall()189         public async Task ServerStreamingCall()
190         {
191             helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) =>
192             {
193                 await responseStream.WriteAllAsync(request.Split(new []{' '}));
194                 context.ResponseTrailers.Add("xyz", "");
195             });
196 
197             var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "A B C");
198             CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, await call.ResponseStream.ToListAsync());
199 
200             Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
201             Assert.AreEqual("xyz", call.GetTrailers()[0].Key);
202         }
203 
204         [Test]
ServerStreamingCall_EndOfStreamIsIdempotent()205         public async Task ServerStreamingCall_EndOfStreamIsIdempotent()
206         {
207             helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>((request, responseStream, context) => TaskUtils.CompletedTask);
208 
209             var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
210 
211             Assert.IsFalse(await call.ResponseStream.MoveNext());
212             Assert.IsFalse(await call.ResponseStream.MoveNext());
213         }
214 
215         [Test]
ServerStreamingCall_ErrorCanBeAwaitedTwice()216         public void ServerStreamingCall_ErrorCanBeAwaitedTwice()
217         {
218             helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>((request, responseStream, context) =>
219             {
220                 context.Status = new Status(StatusCode.InvalidArgument, "");
221                 return TaskUtils.CompletedTask;
222             });
223 
224             var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
225 
226             var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
227             Assert.AreEqual(StatusCode.InvalidArgument, ex.Status.StatusCode);
228 
229             // attempting MoveNext again should result in throwing the same exception.
230             var ex2 = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
231             Assert.AreEqual(StatusCode.InvalidArgument, ex2.Status.StatusCode);
232         }
233 
234         [Test]
ServerStreamingCall_TrailersFromMultipleSourcesGetConcatenated()235         public void ServerStreamingCall_TrailersFromMultipleSourcesGetConcatenated()
236         {
237             helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>((request, responseStream, context) =>
238             {
239                 context.ResponseTrailers.Add("xyz", "xyz-value");
240                 throw new RpcException(new Status(StatusCode.InvalidArgument, ""), new Metadata { {"abc", "abc-value"} });
241             });
242 
243             var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
244 
245             var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
246             Assert.AreEqual(StatusCode.InvalidArgument, ex.Status.StatusCode);
247             Assert.AreEqual(2, call.GetTrailers().Count);
248             Assert.AreEqual(2, ex.Trailers.Count);
249             Assert.AreEqual("xyz", ex.Trailers[0].Key);
250             Assert.AreEqual("xyz-value", ex.Trailers[0].Value);
251             Assert.AreEqual("abc", ex.Trailers[1].Key);
252             Assert.AreEqual("abc-value", ex.Trailers[1].Value);
253         }
254 
255         [Test]
DuplexStreamingCall()256         public async Task DuplexStreamingCall()
257         {
258             helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
259             {
260                 while (await requestStream.MoveNext())
261                 {
262                     await responseStream.WriteAsync(requestStream.Current);
263                 }
264                 context.ResponseTrailers.Add("xyz", "xyz-value");
265             });
266 
267             var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall());
268             await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
269             CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, await call.ResponseStream.ToListAsync());
270 
271             Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
272             Assert.AreEqual("xyz-value", call.GetTrailers()[0].Value);
273         }
274 
275         [Test]
AsyncUnaryCall_EchoMetadata()276         public async Task AsyncUnaryCall_EchoMetadata()
277         {
278             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
279             {
280                 foreach (Metadata.Entry metadataEntry in context.RequestHeaders)
281                 {
282                     if (metadataEntry.Key != "user-agent")
283                     {
284                         context.ResponseTrailers.Add(metadataEntry);
285                     }
286                 }
287                 return Task.FromResult("");
288             });
289 
290             var headers = new Metadata
291             {
292                 { "ascii-header", "abcdefg" },
293                 { "binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff } }
294             };
295             var call = Calls.AsyncUnaryCall(helper.CreateUnaryCall(new CallOptions(headers: headers)), "ABC");
296             await call;
297 
298             Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
299 
300             var trailers = call.GetTrailers();
301             Assert.AreEqual(2, trailers.Count);
302             Assert.AreEqual(headers[0].Key, trailers[0].Key);
303             Assert.AreEqual(headers[0].Value, trailers[0].Value);
304 
305             Assert.AreEqual(headers[1].Key, trailers[1].Key);
306             CollectionAssert.AreEqual(headers[1].ValueBytes, trailers[1].ValueBytes);
307         }
308 
309         [Test]
UnknownMethodHandler()310         public void UnknownMethodHandler()
311         {
312             var nonexistentMethod = new Method<string, string>(
313                 MethodType.Unary,
314                 MockServiceHelper.ServiceName,
315                 "NonExistentMethod",
316                 Marshallers.StringMarshaller,
317                 Marshallers.StringMarshaller);
318 
319             var callDetails = new CallInvocationDetails<string, string>(channel, nonexistentMethod, new CallOptions());
320 
321             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(callDetails, "abc"));
322             Assert.AreEqual(StatusCode.Unimplemented, ex.Status.StatusCode);
323         }
324 
325         [Test]
StatusDetailIsUtf8()326         public void StatusDetailIsUtf8()
327         {
328             // some japanese and chinese characters
329             var nonAsciiString = "\u30a1\u30a2\u30a3 \u62b5\u6297\u662f\u5f92\u52b3\u7684";
330             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
331             {
332                 context.Status = new Status(StatusCode.Unknown, nonAsciiString);
333                 return Task.FromResult("");
334             });
335 
336             var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
337             Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode);
338             Assert.AreEqual(nonAsciiString, ex.Status.Detail);
339         }
340 
341         [Test]
ServerCallContext_PeerInfoPresent()342         public void ServerCallContext_PeerInfoPresent()
343         {
344             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
345             {
346                 return Task.FromResult(context.Peer);
347             });
348 
349             string peer = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc");
350             Assert.IsTrue(peer.Contains(Host));
351         }
352 
353         [Test]
ServerCallContext_HostAndMethodPresent()354         public void ServerCallContext_HostAndMethodPresent()
355         {
356             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
357             {
358                 Assert.IsTrue(context.Host.Contains(Host));
359                 Assert.AreEqual("/tests.Test/Unary", context.Method);
360                 return Task.FromResult("PASS");
361             });
362             Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
363         }
364 
365         [Test]
ServerCallContext_AuthContextNotPopulated()366         public void ServerCallContext_AuthContextNotPopulated()
367         {
368             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
369             {
370                 Assert.IsFalse(context.AuthContext.IsPeerAuthenticated);
371                 Assert.AreEqual(0, context.AuthContext.Properties.Count());
372                 return Task.FromResult("PASS");
373             });
374             Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
375         }
376     }
377 }
378