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.Diagnostics; 21 using System.Linq; 22 using System.Threading; 23 using System.Threading.Tasks; 24 using Grpc.Core; 25 using Grpc.Core.Internal; 26 using Grpc.Core.Utils; 27 using NUnit.Framework; 28 29 namespace Grpc.Core.Tests 30 { 31 /// <summary> 32 /// Tests for Deadline support. 33 /// </summary> 34 public class TimeoutsTest 35 { 36 MockServiceHelper helper; 37 Server server; 38 Channel channel; 39 40 [SetUp] Init()41 public void Init() 42 { 43 helper = new MockServiceHelper(); 44 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] InfiniteDeadline()58 public void InfiniteDeadline() 59 { 60 helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => 61 { 62 Assert.AreEqual(DateTime.MaxValue, context.Deadline); 63 return Task.FromResult("PASS"); 64 }); 65 66 // no deadline specified, check server sees infinite deadline 67 Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); 68 69 // DateTime.MaxValue deadline specified, check server sees infinite deadline 70 Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.MaxValue)), "abc")); 71 } 72 73 [Test] DeadlineTransferredToServer()74 public void DeadlineTransferredToServer() 75 { 76 var clientDeadline = DateTime.UtcNow + TimeSpan.FromDays(7); 77 78 helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => 79 { 80 // A fairly relaxed check that the deadline set by client and deadline seen by server 81 // are in agreement. C core takes care of the work with transferring deadline over the wire, 82 // so we don't need an exact check here. 83 Assert.IsTrue(Math.Abs((clientDeadline - context.Deadline).TotalMilliseconds) < 5000); 84 return Task.FromResult("PASS"); 85 }); 86 Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: clientDeadline)), "abc"); 87 } 88 89 [Test] DeadlineInThePast()90 public void DeadlineInThePast() 91 { 92 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) => 93 { 94 await Task.Delay(60000); 95 return "FAIL"; 96 }); 97 98 var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.MinValue)), "abc")); 99 // We can't guarantee the status code always DeadlineExceeded. See issue #2685. 100 Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); 101 } 102 103 [Test] DeadlineExceededStatusOnTimeout()104 public void DeadlineExceededStatusOnTimeout() 105 { 106 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) => 107 { 108 await Task.Delay(60000); 109 return "FAIL"; 110 }); 111 112 var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)))), "abc")); 113 // We can't guarantee the status code always DeadlineExceeded. See issue #2685. 114 Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); 115 } 116 117 [Test] ServerReceivesCancellationOnTimeout()118 public async Task ServerReceivesCancellationOnTimeout() 119 { 120 var serverReceivedCancellationTcs = new TaskCompletionSource<bool>(); 121 122 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) => 123 { 124 // wait until cancellation token is fired. 125 var tcs = new TaskCompletionSource<object>(); 126 context.CancellationToken.Register(() => { tcs.SetResult(null); }); 127 await tcs.Task; 128 serverReceivedCancellationTcs.SetResult(true); 129 return ""; 130 }); 131 132 var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)))), "abc")); 133 // We can't guarantee the status code always DeadlineExceeded. See issue #2685. 134 Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); 135 136 Assert.IsTrue(await serverReceivedCancellationTcs.Task); 137 } 138 } 139 } 140