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