blob: 643af4daf9a7fde28d9e1682a796548ca110fe5d [file] [log] [blame]
Jan Tattermuscha7fff862015-02-13 11:08:08 -08001#region Copyright notice and license
2
Jan Tattermuschaf77b3d2015-02-13 11:22:21 -08003// Copyright 2015, Google Inc.
Jan Tattermuscha7fff862015-02-13 11:08:08 -08004// All rights reserved.
Craig Tiller190d3602015-02-18 09:23:38 -08005//
Jan Tattermuscha7fff862015-02-13 11:08:08 -08006// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
Craig Tiller190d3602015-02-18 09:23:38 -08009//
Jan Tattermuscha7fff862015-02-13 11:08:08 -080010// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
Craig Tiller190d3602015-02-18 09:23:38 -080019//
Jan Tattermuscha7fff862015-02-13 11:08:08 -080020// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32#endregion
33
Jan Tattermuscha7608b02015-02-03 17:54:38 -080034using System;
Jan Tattermusch337a2dd2015-02-13 15:41:41 -080035using System.Diagnostics;
Jan Tattermusch766d72b2015-07-21 20:09:25 -070036using System.Linq;
Jan Tattermusch30868622015-02-19 09:22:33 -080037using System.Threading;
Jan Tattermuscha7608b02015-02-03 17:54:38 -080038using System.Threading.Tasks;
Jan Tattermusch30868622015-02-19 09:22:33 -080039using Grpc.Core;
40using Grpc.Core.Internal;
41using Grpc.Core.Utils;
42using NUnit.Framework;
Jan Tattermuscha7608b02015-02-03 17:54:38 -080043
Jan Tattermusch30868622015-02-19 09:22:33 -080044namespace Grpc.Core.Tests
Jan Tattermuscha7608b02015-02-03 17:54:38 -080045{
46 public class ClientServerTest
47 {
Jan Tattermusch062c3292015-07-23 20:28:42 -070048 const string Host = "127.0.0.1";
Jan Tattermuscha5272b62015-04-30 11:56:46 -070049 const string ServiceName = "/tests.Test";
Jan Tattermuscha7608b02015-02-03 17:54:38 -080050
Jan Tattermusche5c44602015-05-01 11:12:34 -070051 static readonly Method<string, string> EchoMethod = new Method<string, string>(
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -080052 MethodType.Unary,
Jan Tattermusche5c44602015-05-01 11:12:34 -070053 "/tests.Test/Echo",
54 Marshallers.StringMarshaller,
55 Marshallers.StringMarshaller);
56
57 static readonly Method<string, string> ConcatAndEchoMethod = new Method<string, string>(
58 MethodType.ClientStreaming,
59 "/tests.Test/ConcatAndEcho",
60 Marshallers.StringMarshaller,
61 Marshallers.StringMarshaller);
62
63 static readonly Method<string, string> NonexistentMethod = new Method<string, string>(
64 MethodType.Unary,
65 "/tests.Test/NonexistentMethod",
Jan Tattermusch15111f52015-02-05 18:15:14 -080066 Marshallers.StringMarshaller,
67 Marshallers.StringMarshaller);
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -080068
Jan Tattermuscha5272b62015-04-30 11:56:46 -070069 static readonly ServerServiceDefinition ServiceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName)
Jan Tattermusche5c44602015-05-01 11:12:34 -070070 .AddMethod(EchoMethod, EchoHandler)
71 .AddMethod(ConcatAndEchoMethod, ConcatAndEchoHandler)
72 .Build();
73
74 Server server;
75 Channel channel;
Jan Tattermuscha5272b62015-04-30 11:56:46 -070076
Jan Tattermusche5c44602015-05-01 11:12:34 -070077 [SetUp]
78 public void Init()
79 {
Jan Tattermusche5c44602015-05-01 11:12:34 -070080 server = new Server();
81 server.AddServiceDefinition(ServiceDefinition);
Jan Tattermuscha96ac052015-07-24 14:49:30 -070082 int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure);
Jan Tattermusche5c44602015-05-01 11:12:34 -070083 server.Start();
Jan Tattermuscha96ac052015-07-24 14:49:30 -070084 channel = new Channel(Host, port, Credentials.Insecure);
Jan Tattermusche5c44602015-05-01 11:12:34 -070085 }
86
87 [TearDown]
Jan Tattermusch607307d2015-02-18 11:05:45 -080088 public void Cleanup()
89 {
Jan Tattermusche5c44602015-05-01 11:12:34 -070090 channel.Dispose();
91 server.ShutdownAsync().Wait();
92 }
93
94 [TestFixtureTearDown]
95 public void CleanupClass()
96 {
Jan Tattermuschec776242015-02-18 14:06:56 -080097 GrpcEnvironment.Shutdown();
Jan Tattermusch607307d2015-02-18 11:05:45 -080098 }
99
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800100 [Test]
Jan Tattermusch337a2dd2015-02-13 15:41:41 -0800101 public void UnaryCall()
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800102 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700103 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
104 Assert.AreEqual("ABC", Calls.BlockingUnaryCall(internalCall, "ABC", CancellationToken.None));
Jan Tattermuscha5272b62015-04-30 11:56:46 -0700105 }
106
107 [Test]
Jan Tattermusche5c44602015-05-01 11:12:34 -0700108 public void UnaryCall_ServerHandlerThrows()
Jan Tattermuscha5272b62015-04-30 11:56:46 -0700109 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700110 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
Jan Tattermuscha5272b62015-04-30 11:56:46 -0700111 try
112 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700113 Calls.BlockingUnaryCall(internalCall, "THROW", CancellationToken.None);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700114 Assert.Fail();
Jan Tattermuscha5272b62015-04-30 11:56:46 -0700115 }
Jan Tattermusche5c44602015-05-01 11:12:34 -0700116 catch (RpcException e)
Jan Tattermuscha5272b62015-04-30 11:56:46 -0700117 {
Jan Tattermusche5c44602015-05-01 11:12:34 -0700118 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800119 }
Jan Tattermusche5c44602015-05-01 11:12:34 -0700120 }
Craig Tiller190d3602015-02-18 09:23:38 -0800121
Jan Tattermusche5c44602015-05-01 11:12:34 -0700122 [Test]
Jan Tattermusch1cf8d422015-07-21 10:37:55 -0700123 public void UnaryCall_ServerHandlerThrowsRpcException()
124 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700125 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
Jan Tattermusch1cf8d422015-07-21 10:37:55 -0700126 try
127 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700128 Calls.BlockingUnaryCall(internalCall, "THROW_UNAUTHENTICATED", CancellationToken.None);
Jan Tattermusch1cf8d422015-07-21 10:37:55 -0700129 Assert.Fail();
130 }
131 catch (RpcException e)
132 {
Jan Tattermusch7d219cf2015-07-21 12:23:31 -0700133 Assert.AreEqual(StatusCode.Unauthenticated, e.Status.StatusCode);
Jan Tattermusch1cf8d422015-07-21 10:37:55 -0700134 }
135 }
136
137 [Test]
138 public void UnaryCall_ServerHandlerSetsStatus()
139 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700140 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
Jan Tattermusch1cf8d422015-07-21 10:37:55 -0700141 try
142 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700143 Calls.BlockingUnaryCall(internalCall, "SET_UNAUTHENTICATED", CancellationToken.None);
Jan Tattermusch1cf8d422015-07-21 10:37:55 -0700144 Assert.Fail();
145 }
146 catch (RpcException e)
147 {
148 Assert.AreEqual(StatusCode.Unauthenticated, e.Status.StatusCode);
149 }
150 }
151
152 [Test]
Jan Tattermusche5c44602015-05-01 11:12:34 -0700153 public void AsyncUnaryCall()
154 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700155 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
156 var result = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None).ResponseAsync.Result;
Jan Tattermusche5c44602015-05-01 11:12:34 -0700157 Assert.AreEqual("ABC", result);
158 }
159
160 [Test]
161 public void AsyncUnaryCall_ServerHandlerThrows()
162 {
Jan Tattermusch32d95b92015-05-04 17:56:32 -0700163 Task.Run(async () =>
Jan Tattermusche5c44602015-05-01 11:12:34 -0700164 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700165 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700166 try
167 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700168 await Calls.AsyncUnaryCall(internalCall, "THROW", CancellationToken.None);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700169 Assert.Fail();
170 }
171 catch (RpcException e)
172 {
Jan Tattermusch32d95b92015-05-04 17:56:32 -0700173 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700174 }
175 }).Wait();
176 }
177
178 [Test]
179 public void ClientStreamingCall()
180 {
181 Task.Run(async () =>
182 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700183 var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
184 var call = Calls.AsyncClientStreamingCall(internalCall, CancellationToken.None);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700185
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700186 await call.RequestStream.WriteAll(new string[] { "A", "B", "C" });
187 Assert.AreEqual("ABC", await call.ResponseAsync);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700188 }).Wait();
189 }
190
191 [Test]
Jan Tattermusche5c44602015-05-01 11:12:34 -0700192 public void ClientStreamingCall_CancelAfterBegin()
193 {
194 Task.Run(async () =>
195 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700196 var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700197
198 var cts = new CancellationTokenSource();
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700199 var call = Calls.AsyncClientStreamingCall(internalCall, cts.Token);
Jan Tattermusch8c2dd9d2015-05-04 09:20:43 -0700200
201 // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
202 await Task.Delay(1000);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700203 cts.Cancel();
204
205 try
206 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700207 await call.ResponseAsync;
Jan Tattermusche5c44602015-05-01 11:12:34 -0700208 }
Jan Tattermusch618647d2015-05-01 11:23:28 -0700209 catch (RpcException e)
Jan Tattermusche5c44602015-05-01 11:12:34 -0700210 {
211 Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
212 }
213 }).Wait();
214 }
215
216 [Test]
Jan Tattermusch998eb9b2015-07-20 22:12:53 -0700217 public void AsyncUnaryCall_EchoMetadata()
218 {
Jan Tattermusch7d219cf2015-07-21 12:23:31 -0700219 var headers = new Metadata
Jan Tattermusch998eb9b2015-07-20 22:12:53 -0700220 {
221 new Metadata.Entry("asciiHeader", "abcdefg"),
Jan Tattermuschae017092015-07-22 11:59:13 -0700222 new Metadata.Entry("binaryHeader-bin", new byte[] { 1, 2, 3, 0, 0xff }),
Jan Tattermusch998eb9b2015-07-20 22:12:53 -0700223 };
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700224 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, headers);
225 var call = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None);
Jan Tattermusch25bb2ef2015-07-21 12:15:53 -0700226
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700227 Assert.AreEqual("ABC", call.ResponseAsync.Result);
Jan Tattermusch1cf8d422015-07-21 10:37:55 -0700228
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700229 Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
Jan Tattermusch7d219cf2015-07-21 12:23:31 -0700230
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700231 var trailers = call.GetTrailers();
Jan Tattermusch7d219cf2015-07-21 12:23:31 -0700232 Assert.AreEqual(2, trailers.Count);
233 Assert.AreEqual(headers[0].Key, trailers[0].Key);
234 Assert.AreEqual(headers[0].Value, trailers[0].Value);
235
236 Assert.AreEqual(headers[1].Key, trailers[1].Key);
237 CollectionAssert.AreEqual(headers[1].ValueBytes, trailers[1].ValueBytes);
Jan Tattermusch998eb9b2015-07-20 22:12:53 -0700238 }
239
240 [Test]
Jan Tattermusche5c44602015-05-01 11:12:34 -0700241 public void UnaryCall_DisposedChannel()
242 {
243 channel.Dispose();
244
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700245 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
246 Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(internalCall, "ABC", CancellationToken.None));
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800247 }
248
Jan Tattermusch337a2dd2015-02-13 15:41:41 -0800249 [Test]
250 public void UnaryCallPerformance()
251 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700252 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700253 BenchmarkUtil.RunBenchmark(100, 100,
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700254 () => { Calls.BlockingUnaryCall(internalCall, "ABC", default(CancellationToken)); });
Jan Tattermusch337a2dd2015-02-13 15:41:41 -0800255 }
Jan Tattermusch797b8752015-06-17 10:53:59 -0700256
257 [Test]
258 public void UnknownMethodHandler()
259 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700260 var internalCall = new Call<string, string>(ServiceName, NonexistentMethod, channel, Metadata.Empty);
Jan Tattermusch797b8752015-06-17 10:53:59 -0700261 try
262 {
Jan Tattermusche7e1c822015-07-21 12:38:07 -0700263 Calls.BlockingUnaryCall(internalCall, "ABC", default(CancellationToken));
Jan Tattermusch797b8752015-06-17 10:53:59 -0700264 Assert.Fail();
265 }
266 catch (RpcException e)
267 {
268 Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode);
269 }
270 }
Jan Tattermusch337a2dd2015-02-13 15:41:41 -0800271
Jan Tattermusch766d72b2015-07-21 20:09:25 -0700272 [Test]
273 public void UserAgentStringPresent()
274 {
275 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
276 string userAgent = Calls.BlockingUnaryCall(internalCall, "RETURN-USER-AGENT", CancellationToken.None);
277 Assert.IsTrue(userAgent.StartsWith("grpc-csharp/"));
278 }
279
Jan Tattermusch062c3292015-07-23 20:28:42 -0700280 [Test]
281 public void PeerInfoPresent()
282 {
283 var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
284 string peer = Calls.BlockingUnaryCall(internalCall, "RETURN-PEER", CancellationToken.None);
285 Assert.IsTrue(peer.Contains(Host));
286 }
287
Jan Tattermusch25bb2ef2015-07-21 12:15:53 -0700288 private static async Task<string> EchoHandler(string request, ServerCallContext context)
Jan Tattermusch8d7ce432015-02-18 11:20:43 -0800289 {
Jan Tattermusch998eb9b2015-07-20 22:12:53 -0700290 foreach (Metadata.Entry metadataEntry in context.RequestHeaders)
291 {
Jan Tattermusch766d72b2015-07-21 20:09:25 -0700292 if (metadataEntry.Key != "user-agent")
293 {
294 context.ResponseTrailers.Add(metadataEntry);
295 }
296 }
297
298 if (request == "RETURN-USER-AGENT")
299 {
300 return context.RequestHeaders.Where(entry => entry.Key == "user-agent").Single().Value;
Jan Tattermusch998eb9b2015-07-20 22:12:53 -0700301 }
302
Jan Tattermusch062c3292015-07-23 20:28:42 -0700303 if (request == "RETURN-PEER")
304 {
305 return context.Peer;
306 }
307
Jan Tattermusche5c44602015-05-01 11:12:34 -0700308 if (request == "THROW")
309 {
310 throw new Exception("This was thrown on purpose by a test");
311 }
Jan Tattermusch998eb9b2015-07-20 22:12:53 -0700312
Jan Tattermusch1cf8d422015-07-21 10:37:55 -0700313 if (request == "THROW_UNAUTHENTICATED")
314 {
315 throw new RpcException(new Status(StatusCode.Unauthenticated, ""));
316 }
317
318 if (request == "SET_UNAUTHENTICATED")
319 {
320 context.Status = new Status(StatusCode.Unauthenticated, "");
321 }
322
Jan Tattermusche5c44602015-05-01 11:12:34 -0700323 return request;
324 }
325
Jan Tattermusch25bb2ef2015-07-21 12:15:53 -0700326 private static async Task<string> ConcatAndEchoHandler(IAsyncStreamReader<string> requestStream, ServerCallContext context)
Jan Tattermusche5c44602015-05-01 11:12:34 -0700327 {
328 string result = "";
329 await requestStream.ForEach(async (request) =>
330 {
331 if (request == "THROW")
332 {
333 throw new Exception("This was thrown on purpose by a test");
334 }
335 result += request;
336 });
Jan Tattermusch8c2dd9d2015-05-04 09:20:43 -0700337 // simulate processing takes some time.
338 await Task.Delay(250);
339 return result;
Jan Tattermusch8ce5e8b2015-02-05 10:56:49 -0800340 }
Jan Tattermuscha7608b02015-02-03 17:54:38 -0800341 }
342}