OLD | NEW |
(Empty) | |
| 1 #region Copyright notice and license |
| 2 |
| 3 // Copyright 2015, Google Inc. |
| 4 // All rights reserved. |
| 5 // |
| 6 // Redistribution and use in source and binary forms, with or without |
| 7 // modification, are permitted provided that the following conditions are |
| 8 // met: |
| 9 // |
| 10 // * 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. |
| 19 // |
| 20 // 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 |
| 34 using System; |
| 35 using System.Collections.Generic; |
| 36 using System.Diagnostics; |
| 37 using System.Linq; |
| 38 using System.Threading; |
| 39 using System.Threading.Tasks; |
| 40 using Grpc.Core; |
| 41 using Grpc.Core.Internal; |
| 42 using Grpc.Core.Profiling; |
| 43 using Grpc.Core.Utils; |
| 44 using NUnit.Framework; |
| 45 |
| 46 namespace Grpc.Core.Tests |
| 47 { |
| 48 public class ClientServerTest |
| 49 { |
| 50 const string Host = "127.0.0.1"; |
| 51 |
| 52 MockServiceHelper helper; |
| 53 Server server; |
| 54 Channel channel; |
| 55 |
| 56 [SetUp] |
| 57 public void Init() |
| 58 { |
| 59 helper = new MockServiceHelper(Host); |
| 60 server = helper.GetServer(); |
| 61 server.Start(); |
| 62 channel = helper.GetChannel(); |
| 63 } |
| 64 |
| 65 [TearDown] |
| 66 public void Cleanup() |
| 67 { |
| 68 channel.ShutdownAsync().Wait(); |
| 69 server.ShutdownAsync().Wait(); |
| 70 } |
| 71 |
| 72 [Test] |
| 73 public async Task UnaryCall() |
| 74 { |
| 75 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (r
equest, context) => |
| 76 { |
| 77 return request; |
| 78 }); |
| 79 |
| 80 Assert.AreEqual("ABC", Calls.BlockingUnaryCall(helper.CreateUnaryCal
l(), "ABC")); |
| 81 |
| 82 Assert.AreEqual("ABC", await Calls.AsyncUnaryCall(helper.CreateUnary
Call(), "ABC")); |
| 83 } |
| 84 |
| 85 [Test] |
| 86 public void UnaryCall_ServerHandlerThrows() |
| 87 { |
| 88 helper.UnaryHandler = new UnaryServerMethod<string, string>((request
, context) => |
| 89 { |
| 90 throw new Exception("This was thrown on purpose by a test"); |
| 91 }); |
| 92 |
| 93 var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(h
elper.CreateUnaryCall(), "abc")); |
| 94 Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode); |
| 95 |
| 96 var ex2 = Assert.Throws<RpcException>(async () => await Calls.AsyncU
naryCall(helper.CreateUnaryCall(), "abc")); |
| 97 Assert.AreEqual(StatusCode.Unknown, ex2.Status.StatusCode); |
| 98 } |
| 99 |
| 100 [Test] |
| 101 public void UnaryCall_ServerHandlerThrowsRpcException() |
| 102 { |
| 103 helper.UnaryHandler = new UnaryServerMethod<string, string>((request
, context) => |
| 104 { |
| 105 throw new RpcException(new Status(StatusCode.Unauthenticated, ""
)); |
| 106 }); |
| 107 |
| 108 var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(h
elper.CreateUnaryCall(), "abc")); |
| 109 Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode); |
| 110 |
| 111 var ex2 = Assert.Throws<RpcException>(async () => await Calls.AsyncU
naryCall(helper.CreateUnaryCall(), "abc")); |
| 112 Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode); |
| 113 } |
| 114 |
| 115 [Test] |
| 116 public void UnaryCall_ServerHandlerSetsStatus() |
| 117 { |
| 118 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (r
equest, context) => |
| 119 { |
| 120 context.Status = new Status(StatusCode.Unauthenticated, ""); |
| 121 return ""; |
| 122 }); |
| 123 |
| 124 var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(h
elper.CreateUnaryCall(), "abc")); |
| 125 Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode); |
| 126 |
| 127 var ex2 = Assert.Throws<RpcException>(async () => await Calls.AsyncU
naryCall(helper.CreateUnaryCall(), "abc")); |
| 128 Assert.AreEqual(StatusCode.Unauthenticated, ex2.Status.StatusCode); |
| 129 } |
| 130 |
| 131 [Test] |
| 132 public async Task ClientStreamingCall() |
| 133 { |
| 134 helper.ClientStreamingHandler = new ClientStreamingServerMethod<stri
ng, string>(async (requestStream, context) => |
| 135 { |
| 136 string result = ""; |
| 137 await requestStream.ForEachAsync(async (request) => |
| 138 { |
| 139 result += request; |
| 140 }); |
| 141 await Task.Delay(100); |
| 142 return result; |
| 143 }); |
| 144 |
| 145 var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreami
ngCall()); |
| 146 await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C"
}); |
| 147 Assert.AreEqual("ABC", await call.ResponseAsync); |
| 148 |
| 149 Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode); |
| 150 Assert.IsNotNull(call.GetTrailers()); |
| 151 } |
| 152 |
| 153 [Test] |
| 154 public async Task ServerStreamingCall() |
| 155 { |
| 156 helper.ServerStreamingHandler = new ServerStreamingServerMethod<stri
ng, string>(async (request, responseStream, context) => |
| 157 { |
| 158 await responseStream.WriteAllAsync(request.Split(new []{' '})); |
| 159 context.ResponseTrailers.Add("xyz", ""); |
| 160 }); |
| 161 |
| 162 var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreami
ngCall(), "A B C"); |
| 163 CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, await call
.ResponseStream.ToListAsync()); |
| 164 |
| 165 Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode); |
| 166 Assert.IsNotNull("xyz", call.GetTrailers()[0].Key); |
| 167 } |
| 168 |
| 169 [Test] |
| 170 public async Task DuplexStreamingCall() |
| 171 { |
| 172 helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<stri
ng, string>(async (requestStream, responseStream, context) => |
| 173 { |
| 174 while (await requestStream.MoveNext()) |
| 175 { |
| 176 await responseStream.WriteAsync(requestStream.Current); |
| 177 } |
| 178 context.ResponseTrailers.Add("xyz", "xyz-value"); |
| 179 }); |
| 180 |
| 181 var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreami
ngCall()); |
| 182 await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C"
}); |
| 183 CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, await call
.ResponseStream.ToListAsync()); |
| 184 |
| 185 Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode); |
| 186 Assert.IsNotNull("xyz-value", call.GetTrailers()[0].Value); |
| 187 } |
| 188 |
| 189 [Test] |
| 190 public async Task ClientStreamingCall_CancelAfterBegin() |
| 191 { |
| 192 var barrier = new TaskCompletionSource<object>(); |
| 193 |
| 194 helper.ClientStreamingHandler = new ClientStreamingServerMethod<stri
ng, string>(async (requestStream, context) => |
| 195 { |
| 196 barrier.SetResult(null); |
| 197 await requestStream.ToListAsync(); |
| 198 return ""; |
| 199 }); |
| 200 |
| 201 var cts = new CancellationTokenSource(); |
| 202 var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreami
ngCall(new CallOptions(cancellationToken: cts.Token))); |
| 203 |
| 204 await barrier.Task; // make sure the handler has started. |
| 205 cts.Cancel(); |
| 206 |
| 207 var ex = Assert.Throws<RpcException>(async () => await call.Response
Async); |
| 208 Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); |
| 209 } |
| 210 |
| 211 [Test] |
| 212 public async Task AsyncUnaryCall_EchoMetadata() |
| 213 { |
| 214 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (r
equest, context) => |
| 215 { |
| 216 foreach (Metadata.Entry metadataEntry in context.RequestHeaders) |
| 217 { |
| 218 if (metadataEntry.Key != "user-agent") |
| 219 { |
| 220 context.ResponseTrailers.Add(metadataEntry); |
| 221 } |
| 222 } |
| 223 return ""; |
| 224 }); |
| 225 |
| 226 var headers = new Metadata |
| 227 { |
| 228 { "ascii-header", "abcdefg" }, |
| 229 { "binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff } } |
| 230 }; |
| 231 var call = Calls.AsyncUnaryCall(helper.CreateUnaryCall(new CallOptio
ns(headers: headers)), "ABC"); |
| 232 await call; |
| 233 |
| 234 Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode); |
| 235 |
| 236 var trailers = call.GetTrailers(); |
| 237 Assert.AreEqual(2, trailers.Count); |
| 238 Assert.AreEqual(headers[0].Key, trailers[0].Key); |
| 239 Assert.AreEqual(headers[0].Value, trailers[0].Value); |
| 240 |
| 241 Assert.AreEqual(headers[1].Key, trailers[1].Key); |
| 242 CollectionAssert.AreEqual(headers[1].ValueBytes, trailers[1].ValueBy
tes); |
| 243 } |
| 244 |
| 245 [Test] |
| 246 public void UnknownMethodHandler() |
| 247 { |
| 248 var nonexistentMethod = new Method<string, string>( |
| 249 MethodType.Unary, |
| 250 MockServiceHelper.ServiceName, |
| 251 "NonExistentMethod", |
| 252 Marshallers.StringMarshaller, |
| 253 Marshallers.StringMarshaller); |
| 254 |
| 255 var callDetails = new CallInvocationDetails<string, string>(channel,
nonexistentMethod, new CallOptions()); |
| 256 |
| 257 var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(c
allDetails, "abc")); |
| 258 Assert.AreEqual(StatusCode.Unimplemented, ex.Status.StatusCode); |
| 259 } |
| 260 |
| 261 [Test] |
| 262 public void ServerCallContext_PeerInfoPresent() |
| 263 { |
| 264 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (r
equest, context) => |
| 265 { |
| 266 return context.Peer; |
| 267 }); |
| 268 |
| 269 string peer = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc
"); |
| 270 Assert.IsTrue(peer.Contains(Host)); |
| 271 } |
| 272 |
| 273 [Test] |
| 274 public void ServerCallContext_HostAndMethodPresent() |
| 275 { |
| 276 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (r
equest, context) => |
| 277 { |
| 278 Assert.IsTrue(context.Host.Contains(Host)); |
| 279 Assert.AreEqual("/tests.Test/Unary", context.Method); |
| 280 return "PASS"; |
| 281 }); |
| 282 Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCa
ll(), "abc")); |
| 283 } |
| 284 |
| 285 [Test] |
| 286 public async Task Channel_WaitForStateChangedAsync() |
| 287 { |
| 288 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (r
equest, context) => |
| 289 { |
| 290 return request; |
| 291 }); |
| 292 |
| 293 Assert.Throws(typeof(TaskCanceledException), |
| 294 async () => await channel.WaitForStateChangedAsync(channel.State
, DateTime.UtcNow.AddMilliseconds(10))); |
| 295 |
| 296 var stateChangedTask = channel.WaitForStateChangedAsync(channel.Stat
e); |
| 297 |
| 298 await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc"); |
| 299 |
| 300 await stateChangedTask; |
| 301 Assert.AreEqual(ChannelState.Ready, channel.State); |
| 302 } |
| 303 |
| 304 [Test] |
| 305 public async Task Channel_ConnectAsync() |
| 306 { |
| 307 await channel.ConnectAsync(); |
| 308 Assert.AreEqual(ChannelState.Ready, channel.State); |
| 309 |
| 310 await channel.ConnectAsync(DateTime.UtcNow.AddMilliseconds(1000)); |
| 311 Assert.AreEqual(ChannelState.Ready, channel.State); |
| 312 } |
| 313 } |
| 314 } |
OLD | NEW |