Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 1 | #region Copyright notice and license |
| 2 | |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 3 | // Copyright 2015 gRPC authors. |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 4 | // |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 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 |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 8 | // |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 9 | // http://www.apache.org/licenses/LICENSE-2.0 |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 10 | // |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 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. |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 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 | { |
Jan Tattermusch | a4291e7 | 2015-08-07 19:13:31 -0700 | [diff] [blame] | 36 | MockServiceHelper helper; |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 37 | Server server; |
| 38 | Channel channel; |
| 39 | |
| 40 | [SetUp] |
| 41 | public void Init() |
| 42 | { |
Jan Tattermusch | a4291e7 | 2015-08-07 19:13:31 -0700 | [diff] [blame] | 43 | helper = new MockServiceHelper(); |
| 44 | |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 45 | server = helper.GetServer(); |
Jan Tattermusch | a4291e7 | 2015-08-07 19:13:31 -0700 | [diff] [blame] | 46 | server.Start(); |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 47 | channel = helper.GetChannel(); |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 48 | } |
| 49 | |
| 50 | [TearDown] |
| 51 | public void Cleanup() |
| 52 | { |
Jan Tattermusch | 2b35795 | 2015-08-20 14:54:33 -0700 | [diff] [blame] | 53 | channel.ShutdownAsync().Wait(); |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 54 | server.ShutdownAsync().Wait(); |
| 55 | } |
| 56 | |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 57 | [Test] |
| 58 | public void InfiniteDeadline() |
| 59 | { |
Jan Tattermusch | 2fb313c | 2017-08-09 09:41:25 +0200 | [diff] [blame] | 60 | helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => |
Jan Tattermusch | c75c57c | 2015-08-07 22:07:40 -0700 | [diff] [blame] | 61 | { |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 62 | Assert.AreEqual(DateTime.MaxValue, context.Deadline); |
Jan Tattermusch | 2fb313c | 2017-08-09 09:41:25 +0200 | [diff] [blame] | 63 | return Task.FromResult("PASS"); |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 64 | }); |
| 65 | |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 66 | // no deadline specified, check server sees infinite deadline |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 67 | Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc")); |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 68 | |
| 69 | // DateTime.MaxValue deadline specified, check server sees infinite deadline |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 70 | Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: DateTime.MaxValue)), "abc")); |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | [Test] |
| 74 | public void DeadlineTransferredToServer() |
| 75 | { |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 76 | var clientDeadline = DateTime.UtcNow + TimeSpan.FromDays(7); |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 77 | |
Jan Tattermusch | 2fb313c | 2017-08-09 09:41:25 +0200 | [diff] [blame] | 78 | helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => |
Jan Tattermusch | c75c57c | 2015-08-07 22:07:40 -0700 | [diff] [blame] | 79 | { |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 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); |
Jan Tattermusch | 2fb313c | 2017-08-09 09:41:25 +0200 | [diff] [blame] | 84 | return Task.FromResult("PASS"); |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 85 | }); |
| 86 | Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(deadline: clientDeadline)), "abc"); |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 87 | } |
| 88 | |
| 89 | [Test] |
Jan Tattermusch | 49313ce | 2015-07-23 19:17:30 -0700 | [diff] [blame] | 90 | public void DeadlineInThePast() |
| 91 | { |
Jan Tattermusch | c75c57c | 2015-08-07 22:07:40 -0700 | [diff] [blame] | 92 | helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) => |
| 93 | { |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 94 | await Task.Delay(60000); |
| 95 | return "FAIL"; |
| 96 | }); |
Jan Tattermusch | 49313ce | 2015-07-23 19:17:30 -0700 | [diff] [blame] | 97 | |
Jan Tattermusch | 0abb847 | 2015-08-07 20:28:44 -0700 | [diff] [blame] | 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 }); |
Jan Tattermusch | 49313ce | 2015-07-23 19:17:30 -0700 | [diff] [blame] | 101 | } |
| 102 | |
| 103 | [Test] |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 104 | public void DeadlineExceededStatusOnTimeout() |
| 105 | { |
Jan Tattermusch | c75c57c | 2015-08-07 22:07:40 -0700 | [diff] [blame] | 106 | helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) => |
| 107 | { |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 108 | await Task.Delay(60000); |
| 109 | return "FAIL"; |
| 110 | }); |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 111 | |
Jan Tattermusch | 0abb847 | 2015-08-07 20:28:44 -0700 | [diff] [blame] | 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 }); |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | [Test] |
Jan Tattermusch | 2615f39 | 2015-08-07 20:41:26 -0700 | [diff] [blame] | 118 | public async Task ServerReceivesCancellationOnTimeout() |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 119 | { |
Jan Tattermusch | 2615f39 | 2015-08-07 20:41:26 -0700 | [diff] [blame] | 120 | var serverReceivedCancellationTcs = new TaskCompletionSource<bool>(); |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 121 | |
Jan Tattermusch | c75c57c | 2015-08-07 22:07:40 -0700 | [diff] [blame] | 122 | helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) => |
| 123 | { |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 124 | // wait until cancellation token is fired. |
| 125 | var tcs = new TaskCompletionSource<object>(); |
| 126 | context.CancellationToken.Register(() => { tcs.SetResult(null); }); |
| 127 | await tcs.Task; |
Jan Tattermusch | 2615f39 | 2015-08-07 20:41:26 -0700 | [diff] [blame] | 128 | serverReceivedCancellationTcs.SetResult(true); |
Jan Tattermusch | 5b0b392 | 2015-08-07 19:07:14 -0700 | [diff] [blame] | 129 | return ""; |
| 130 | }); |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 131 | |
Jan Tattermusch | 0abb847 | 2015-08-07 20:28:44 -0700 | [diff] [blame] | 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 }); |
Jan Tattermusch | a4291e7 | 2015-08-07 19:13:31 -0700 | [diff] [blame] | 135 | |
Jan Tattermusch | 2615f39 | 2015-08-07 20:41:26 -0700 | [diff] [blame] | 136 | Assert.IsTrue(await serverReceivedCancellationTcs.Task); |
Jan Tattermusch | 0846b68 | 2015-07-23 17:02:12 -0700 | [diff] [blame] | 137 | } |
| 138 | } |
| 139 | } |