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.Diagnostics; 22 using System.Linq; 23 using System.Threading; 24 using System.Threading.Tasks; 25 26 using Grpc.Core; 27 using Grpc.Core.Internal; 28 using Grpc.Core.Utils; 29 30 using NUnit.Framework; 31 32 namespace Grpc.Core.Tests 33 { 34 /// <summary> 35 /// Tests for response headers support. 36 /// </summary> 37 public class ResponseHeadersTest 38 { 39 MockServiceHelper helper; 40 Server server; 41 Channel channel; 42 43 Metadata headers; 44 45 [SetUp] Init()46 public void Init() 47 { 48 helper = new MockServiceHelper(); 49 50 server = helper.GetServer(); 51 server.Start(); 52 channel = helper.GetChannel(); 53 54 headers = new Metadata { { "ascii-header", "abcdefg" } }; 55 } 56 57 [TearDown] Cleanup()58 public void Cleanup() 59 { 60 channel.ShutdownAsync().Wait(); 61 server.ShutdownAsync().Wait(); 62 } 63 64 [Test] ResponseHeadersAsync_UnaryCall()65 public async Task ResponseHeadersAsync_UnaryCall() 66 { 67 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) => 68 { 69 await context.WriteResponseHeadersAsync(headers); 70 return "PASS"; 71 }); 72 73 var call = Calls.AsyncUnaryCall(helper.CreateUnaryCall(), ""); 74 var responseHeaders = await call.ResponseHeadersAsync; 75 76 Assert.AreEqual(headers.Count, responseHeaders.Count); 77 Assert.AreEqual("ascii-header", responseHeaders[0].Key); 78 Assert.AreEqual("abcdefg", responseHeaders[0].Value); 79 80 Assert.AreEqual("PASS", await call.ResponseAsync); 81 } 82 83 [Test] ResponseHeadersAsync_ClientStreamingCall()84 public async Task ResponseHeadersAsync_ClientStreamingCall() 85 { 86 helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) => 87 { 88 await context.WriteResponseHeadersAsync(headers); 89 return "PASS"; 90 }); 91 92 var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); 93 await call.RequestStream.CompleteAsync(); 94 var responseHeaders = await call.ResponseHeadersAsync; 95 96 Assert.AreEqual("ascii-header", responseHeaders[0].Key); 97 Assert.AreEqual("PASS", await call.ResponseAsync); 98 } 99 100 [Test] ResponseHeadersAsync_ServerStreamingCall()101 public async Task ResponseHeadersAsync_ServerStreamingCall() 102 { 103 helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) => 104 { 105 await context.WriteResponseHeadersAsync(headers); 106 await responseStream.WriteAsync("PASS"); 107 }); 108 109 var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), ""); 110 var responseHeaders = await call.ResponseHeadersAsync; 111 112 Assert.AreEqual("ascii-header", responseHeaders[0].Key); 113 CollectionAssert.AreEqual(new[] { "PASS" }, await call.ResponseStream.ToListAsync()); 114 } 115 116 [Test] ResponseHeadersAsync_DuplexStreamingCall()117 public async Task ResponseHeadersAsync_DuplexStreamingCall() 118 { 119 helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) => 120 { 121 await context.WriteResponseHeadersAsync(headers); 122 while (await requestStream.MoveNext()) 123 { 124 await responseStream.WriteAsync(requestStream.Current); 125 } 126 }); 127 128 var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall()); 129 var responseHeaders = await call.ResponseHeadersAsync; 130 131 var messages = new[] { "PASS" }; 132 await call.RequestStream.WriteAllAsync(messages); 133 134 Assert.AreEqual("ascii-header", responseHeaders[0].Key); 135 CollectionAssert.AreEqual(messages, await call.ResponseStream.ToListAsync()); 136 } 137 138 [Test] WriteResponseHeaders_NullNotAllowed()139 public void WriteResponseHeaders_NullNotAllowed() 140 { 141 helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => 142 { 143 Assert.ThrowsAsync(typeof(ArgumentNullException), async () => await context.WriteResponseHeadersAsync(null)); 144 return Task.FromResult("PASS"); 145 }); 146 147 Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "")); 148 } 149 150 [Test] WriteResponseHeaders_AllowedOnlyOnce()151 public void WriteResponseHeaders_AllowedOnlyOnce() 152 { 153 helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) => 154 { 155 await context.WriteResponseHeadersAsync(headers); 156 try 157 { 158 await context.WriteResponseHeadersAsync(headers); 159 Assert.Fail(); 160 } 161 catch (InvalidOperationException) 162 { 163 } 164 return "PASS"; 165 }); 166 167 Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "")); 168 } 169 170 [Test] WriteResponseHeaders_NotAllowedAfterWrite()171 public async Task WriteResponseHeaders_NotAllowedAfterWrite() 172 { 173 helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) => 174 { 175 await responseStream.WriteAsync("A"); 176 try 177 { 178 await context.WriteResponseHeadersAsync(headers); 179 Assert.Fail(); 180 } 181 catch (InvalidOperationException) 182 { 183 } 184 await responseStream.WriteAsync("B"); 185 }); 186 187 var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), ""); 188 var responses = await call.ResponseStream.ToListAsync(); 189 CollectionAssert.AreEqual(new[] { "A", "B" }, responses); 190 } 191 } 192 } 193