| 
					
				 | 
			
			
				@@ -75,7 +75,6 @@ namespace Grpc.Core.Internal.Tests 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var finishedTask = asyncCallServer.ServerSideCallAsync(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var requestStream = new ServerRequestStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var responseStream = new ServerResponseStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Finishing requestStream is needed for dispose to happen. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var moveNextTask = requestStream.MoveNext(); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -91,7 +90,6 @@ namespace Grpc.Core.Internal.Tests 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var finishedTask = asyncCallServer.ServerSideCallAsync(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var requestStream = new ServerRequestStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var responseStream = new ServerResponseStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -103,24 +101,89 @@ namespace Grpc.Core.Internal.Tests 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             AssertFinished(asyncCallServer, fakeCall, finishedTask); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [Test] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void ReadCompletionFailureClosesRequestStream() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var finishedTask = asyncCallServer.ServerSideCallAsync(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var requestStream = new ServerRequestStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // if a read completion's success==false, the request stream will silently finish 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // and we rely on C core cancelling the call. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var moveNextTask = requestStream.MoveNext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.ReceivedMessageHandler(false, null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Assert.IsFalse(moveNextTask.Result); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            AssertFinished(asyncCallServer, fakeCall, finishedTask); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [Test] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void WriteAfterCancelNotificationFails() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var finishedTask = asyncCallServer.ServerSideCallAsync(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var requestStream = new ServerRequestStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var responseStream = new ServerResponseStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // TODO(jtattermusch): should we throw a different exception type instead? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Assert.Throws(typeof(InvalidOperationException), () => responseStream.WriteAsync("request1")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Finishing requestStream is needed for dispose to happen. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var moveNextTask = requestStream.MoveNext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.ReceivedMessageHandler(true, null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Assert.IsFalse(moveNextTask.Result); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            AssertFinished(asyncCallServer, fakeCall, finishedTask); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [Test] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void WriteCompletionFailureThrows() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var finishedTask = asyncCallServer.ServerSideCallAsync(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var requestStream = new ServerRequestStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var responseStream = new ServerResponseStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var writeTask = responseStream.WriteAsync("request1"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.SendCompletionHandler(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // TODO(jtattermusch): should we throw a different exception type instead? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await writeTask); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // TODO: read completion failure ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Finishing requestStream is needed for dispose to happen. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var moveNextTask = requestStream.MoveNext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.ReceivedMessageHandler(true, null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Assert.IsFalse(moveNextTask.Result); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            AssertFinished(asyncCallServer, fakeCall, finishedTask); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // TODO: write fails... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [Test] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void WriteAndWriteStatusCanRunConcurrently() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var finishedTask = asyncCallServer.ServerSideCallAsync(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var requestStream = new ServerRequestStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var responseStream = new ServerResponseStream<string, string>(asyncCallServer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // TODO: write completion fails... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var writeTask = responseStream.WriteAsync("request1"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var writeStatusTask = asyncCallServer.SendStatusFromServerAsync(Status.DefaultSuccess, new Metadata()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // TODO: cancellation delivered... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.SendCompletionHandler(true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.SendStatusFromServerHandler(true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // TODO: cancel notification in the middle of a read... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Assert.DoesNotThrowAsync(async () => await writeTask); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Assert.DoesNotThrowAsync(async () => await writeStatusTask); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // TODO: cancel notification in the middle of a write... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Finishing requestStream is needed for dispose to happen. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var moveNextTask = requestStream.MoveNext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.ReceivedMessageHandler(true, null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Assert.IsFalse(moveNextTask.Result); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // TODO: cancellation delivered... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // TODO: what does writing status do to reads? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            AssertFinished(asyncCallServer, fakeCall, finishedTask); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         static void AssertFinished(AsyncCallServer<string, string> asyncCallServer, FakeNativeCall fakeCall, Task finishedTask) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 |