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 NUnit.Framework;
21 using System.Threading;
22 using System.Threading.Tasks;
23 
24 namespace Grpc.Core.Tests
25 {
26     public class ThreadingModelTest
27     {
28         const string Host = "127.0.0.1";
29 
30         MockServiceHelper helper;
31         Server server;
32         Channel channel;
33 
34         [SetUp]
Init()35         public void Init()
36         {
37             helper = new MockServiceHelper(Host);
38             server = helper.GetServer();
39             server.Start();
40             channel = helper.GetChannel();
41         }
42 
43         [TearDown]
Cleanup()44         public void Cleanup()
45         {
46             channel.ShutdownAsync().Wait();
47             server.ShutdownAsync().Wait();
48         }
49 
50         [Test]
BlockingCallInServerHandlerDoesNotDeadlock()51         public void BlockingCallInServerHandlerDoesNotDeadlock()
52         {
53             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
54             {
55                 int recursionDepth = int.Parse(request);
56                 if (recursionDepth <= 0) {
57                     return Task.FromResult("SUCCESS");
58                 }
59                 var response = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), (recursionDepth - 1).ToString());
60                 return Task.FromResult(response);
61             });
62 
63             int maxRecursionDepth = Environment.ProcessorCount * 2;  // make sure we have more pending blocking calls than threads in GrpcThreadPool
64             Assert.AreEqual("SUCCESS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), maxRecursionDepth.ToString()));
65         }
66 
67         [Test]
HandlerDoesNotRunOnGrpcThread()68         public void HandlerDoesNotRunOnGrpcThread()
69         {
70             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
71             {
72                 if (IsRunningOnGrpcThreadPool()) {
73                     return Task.FromResult("Server handler should not run on gRPC threadpool thread.");
74                 }
75                 return Task.FromResult(request);
76             });
77 
78             Assert.AreEqual("ABC", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "ABC"));
79         }
80 
81         [Test]
ContinuationDoesNotRunOnGrpcThread()82         public async Task ContinuationDoesNotRunOnGrpcThread()
83         {
84             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
85             {
86                 return Task.FromResult(request);
87             });
88 
89             await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "ABC");
90             Assert.IsFalse(IsRunningOnGrpcThreadPool());
91         }
92 
IsRunningOnGrpcThreadPool()93         private static bool IsRunningOnGrpcThreadPool()
94         {
95             var threadName = Thread.CurrentThread.Name ?? "";
96             return threadName.Contains("grpc");
97         }
98     }
99 }
100