• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Collections.Generic;
21 using System.IO;
22 using System.Runtime.InteropServices;
23 using System.Threading.Tasks;
24 
25 using Grpc.Core.Internal;
26 using NUnit.Framework;
27 
28 namespace Grpc.Core.Internal.Tests
29 {
30     /// <summary>
31     /// Uses fake native call to test interaction of <c>AsyncCallServer</c> wrapping code with C core in different situations.
32     /// </summary>
33     public class AsyncCallServerTest
34     {
35         Server server;
36         FakeNativeCall fakeCall;
37         AsyncCallServer<string, string> asyncCallServer;
38         FakeBufferReaderManager fakeBufferReaderManager;
39 
40         [SetUp]
Init()41         public void Init()
42         {
43             // Create a fake server just so we have an instance to refer to.
44             // The server won't actually be used at all.
45             server = new Server()
46             {
47                 Ports = { { "localhost", 0, ServerCredentials.Insecure } }
48             };
49             server.Start();
50 
51             fakeCall = new FakeNativeCall();
52             asyncCallServer = new AsyncCallServer<string, string>(
53                 Marshallers.StringMarshaller.ContextualSerializer, Marshallers.StringMarshaller.ContextualDeserializer,
54                 server);
55             asyncCallServer.InitializeForTesting(fakeCall);
56             fakeBufferReaderManager = new FakeBufferReaderManager();
57         }
58 
59         [TearDown]
Cleanup()60         public void Cleanup()
61         {
62             fakeBufferReaderManager.Dispose();
63             server.ShutdownAsync().Wait();
64         }
65 
66         [Test]
CancelNotificationAfterStartDisposes()67         public void CancelNotificationAfterStartDisposes()
68         {
69             var finishedTask = asyncCallServer.ServerSideCallAsync();
70             fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
71             AssertFinished(asyncCallServer, fakeCall, finishedTask);
72         }
73 
74         [Test]
CancelNotificationAfterStartDisposesAfterPendingReadFinishes()75         public void CancelNotificationAfterStartDisposesAfterPendingReadFinishes()
76         {
77             var finishedTask = asyncCallServer.ServerSideCallAsync();
78             var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
79 
80             var moveNextTask = requestStream.MoveNext();
81 
82             fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
83             fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
84             Assert.IsFalse(moveNextTask.Result);
85 
86             AssertFinished(asyncCallServer, fakeCall, finishedTask);
87         }
88 
89         [Test]
ReadAfterCancelNotificationCanSucceed()90         public void ReadAfterCancelNotificationCanSucceed()
91         {
92             var finishedTask = asyncCallServer.ServerSideCallAsync();
93             var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
94 
95             fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
96 
97             // Check that starting a read after cancel notification has been processed is legal.
98             var moveNextTask = requestStream.MoveNext();
99             Assert.IsFalse(moveNextTask.Result);
100 
101             AssertFinished(asyncCallServer, fakeCall, finishedTask);
102         }
103 
104         [Test]
ReadCompletionFailureClosesRequestStream()105         public void ReadCompletionFailureClosesRequestStream()
106         {
107             var finishedTask = asyncCallServer.ServerSideCallAsync();
108             var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
109 
110             // if a read completion's success==false, the request stream will silently finish
111             // and we rely on C core cancelling the call.
112             var moveNextTask = requestStream.MoveNext();
113             fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, CreateNullResponse());
114             Assert.IsFalse(moveNextTask.Result);
115 
116             fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
117             AssertFinished(asyncCallServer, fakeCall, finishedTask);
118         }
119 
120         [Test]
WriteAfterCancelNotificationFails()121         public void WriteAfterCancelNotificationFails()
122         {
123             var finishedTask = asyncCallServer.ServerSideCallAsync();
124             var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
125 
126             fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
127 
128             // TODO(jtattermusch): should we throw a different exception type instead?
129             Assert.Throws(typeof(InvalidOperationException), () => responseStream.WriteAsync("request1"));
130             AssertFinished(asyncCallServer, fakeCall, finishedTask);
131         }
132 
133         [Test]
WriteCompletionFailureThrows()134         public void WriteCompletionFailureThrows()
135         {
136             var finishedTask = asyncCallServer.ServerSideCallAsync();
137             var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
138 
139             var writeTask = responseStream.WriteAsync("request1");
140             fakeCall.SendCompletionCallback.OnSendCompletion(false);
141             Assert.ThrowsAsync(typeof(IOException), async () => await writeTask);
142 
143             fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
144             AssertFinished(asyncCallServer, fakeCall, finishedTask);
145         }
146 
147         [Test]
WriteAndWriteStatusCanRunConcurrently()148         public void WriteAndWriteStatusCanRunConcurrently()
149         {
150             var finishedTask = asyncCallServer.ServerSideCallAsync();
151             var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
152 
153             var writeTask = responseStream.WriteAsync("request1");
154             var writeStatusTask = asyncCallServer.SendStatusFromServerAsync(Status.DefaultSuccess, new Metadata(), null);
155 
156             fakeCall.SendCompletionCallback.OnSendCompletion(true);
157             fakeCall.SendStatusFromServerCallback.OnSendStatusFromServerCompletion(true);
158 
159             Assert.DoesNotThrowAsync(async () => await writeTask);
160             Assert.DoesNotThrowAsync(async () => await writeStatusTask);
161 
162             fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
163 
164             AssertFinished(asyncCallServer, fakeCall, finishedTask);
165         }
166 
167         [Test]
WriteAfterWriteStatusThrowsInvalidOperationException()168         public void WriteAfterWriteStatusThrowsInvalidOperationException()
169         {
170             var finishedTask = asyncCallServer.ServerSideCallAsync();
171             var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
172 
173             asyncCallServer.SendStatusFromServerAsync(Status.DefaultSuccess, new Metadata(), null);
174             Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await responseStream.WriteAsync("request1"));
175 
176             fakeCall.SendStatusFromServerCallback.OnSendStatusFromServerCompletion(true);
177             fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
178 
179             AssertFinished(asyncCallServer, fakeCall, finishedTask);
180         }
181 
AssertFinished(AsyncCallServer<string, string> asyncCallServer, FakeNativeCall fakeCall, Task finishedTask)182         static void AssertFinished(AsyncCallServer<string, string> asyncCallServer, FakeNativeCall fakeCall, Task finishedTask)
183         {
184             Assert.IsTrue(fakeCall.IsDisposed);
185             Assert.IsTrue(finishedTask.IsCompleted);
186             Assert.DoesNotThrow(() => finishedTask.Wait());
187         }
188 
CreateNullResponse()189         IBufferReader CreateNullResponse()
190         {
191             return fakeBufferReaderManager.CreateNullPayloadBufferReader();
192         }
193     }
194 }
195