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