blob: 61c658b95ade2bde5b66b9ba9a2d2178752341ea [file] [log] [blame]
Ken Paysonb3532972018-01-11 20:25:30 -08001/*
2 *
3 * Copyright 2017 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 */
18
19#include "test/core/end2end/end2end_tests.h"
20
21#include <limits.h>
22#include <stdbool.h>
23#include <stdio.h>
24#include <string.h>
25
26#include <grpc/byte_buffer.h>
27#include <grpc/support/alloc.h>
28#include <grpc/support/log.h>
29#include <grpc/support/time.h>
30#include <grpc/support/useful.h>
31
32#include "src/core/lib/channel/channel_stack_builder.h"
Ken Payson5ca71f22018-01-11 20:24:06 -080033#include "src/core/lib/surface/call.h"
Ken Paysonb3532972018-01-11 20:25:30 -080034#include "src/core/lib/surface/channel_init.h"
35#include "test/core/end2end/cq_verifier.h"
36
37static bool g_enable_filter = false;
38static gpr_mu g_mu;
Ken Payson5ca71f22018-01-11 20:24:06 -080039static grpc_call_stack* g_client_call_stack;
40static grpc_call_stack* g_server_call_stack;
Ken Paysonb3532972018-01-11 20:25:30 -080041static bool g_client_code_recv;
42static bool g_server_code_recv;
43static gpr_cv g_client_code_cv;
44static gpr_cv g_server_code_cv;
45static grpc_status_code g_client_status_code;
46static grpc_status_code g_server_status_code;
47
48static void* tag(intptr_t t) { return (void*)t; }
49
50static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
51 const char* test_name,
52 grpc_channel_args* client_args,
53 grpc_channel_args* server_args) {
54 grpc_end2end_test_fixture f;
55 gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
56 f = config.create_fixture(client_args, server_args);
57 config.init_server(&f, server_args);
58 config.init_client(&f, client_args);
59 return f;
60}
61
62static gpr_timespec n_seconds_from_now(int n) {
63 return grpc_timeout_seconds_to_deadline(n);
64}
65
66static gpr_timespec five_seconds_from_now(void) {
67 return n_seconds_from_now(5);
68}
69
70static void drain_cq(grpc_completion_queue* cq) {
71 grpc_event ev;
72 do {
73 ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
74 } while (ev.type != GRPC_QUEUE_SHUTDOWN);
75}
76
77static void shutdown_server(grpc_end2end_test_fixture* f) {
78 if (!f->server) return;
79 grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
80 GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
81 grpc_timeout_seconds_to_deadline(5),
82 nullptr)
83 .type == GRPC_OP_COMPLETE);
84 grpc_server_destroy(f->server);
85 f->server = nullptr;
86}
87
88static void shutdown_client(grpc_end2end_test_fixture* f) {
89 if (!f->client) return;
90 grpc_channel_destroy(f->client);
91 f->client = nullptr;
92}
93
94static void end_test(grpc_end2end_test_fixture* f) {
95 shutdown_server(f);
96 shutdown_client(f);
97
98 grpc_completion_queue_shutdown(f->cq);
99 drain_cq(f->cq);
100 grpc_completion_queue_destroy(f->cq);
101 grpc_completion_queue_destroy(f->shutdown_cq);
102}
103
104// Simple request via a server filter that saves the reported status code.
105static void test_request(grpc_end2end_test_config config) {
106 grpc_call* c;
107 grpc_call* s;
108 grpc_end2end_test_fixture f =
109 begin_test(config, "filter_status_code", nullptr, nullptr);
110 cq_verifier* cqv = cq_verifier_create(f.cq);
111 grpc_op ops[6];
112 grpc_op* op;
113 grpc_metadata_array initial_metadata_recv;
114 grpc_metadata_array trailing_metadata_recv;
115 grpc_metadata_array request_metadata_recv;
116 grpc_call_details call_details;
117 grpc_status_code status;
118 grpc_call_error error;
119 grpc_slice details;
120 int was_cancelled = 2;
121
122 gpr_mu_lock(&g_mu);
Ken Payson5ca71f22018-01-11 20:24:06 -0800123 g_client_call_stack = nullptr;
124 g_server_call_stack = nullptr;
Ken Paysonb3532972018-01-11 20:25:30 -0800125 g_client_status_code = GRPC_STATUS_OK;
126 g_server_status_code = GRPC_STATUS_OK;
127 gpr_mu_unlock(&g_mu);
128
129 gpr_timespec deadline = five_seconds_from_now();
130 c = grpc_channel_create_call(
131 f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
132 grpc_slice_from_static_string("/foo"),
133 get_host_override_slice("foo.test.google.fr", config), deadline, nullptr);
134 GPR_ASSERT(c);
Ken Payson5ca71f22018-01-11 20:24:06 -0800135 gpr_mu_lock(&g_mu);
136 g_client_call_stack = grpc_call_get_call_stack(c);
137 gpr_mu_unlock(&g_mu);
Ken Paysonb3532972018-01-11 20:25:30 -0800138
139 grpc_metadata_array_init(&initial_metadata_recv);
140 grpc_metadata_array_init(&trailing_metadata_recv);
141 grpc_metadata_array_init(&request_metadata_recv);
142 grpc_call_details_init(&call_details);
143
144 memset(ops, 0, sizeof(ops));
145 op = ops;
146 op->op = GRPC_OP_SEND_INITIAL_METADATA;
147 op->data.send_initial_metadata.count = 0;
148 op->data.send_initial_metadata.metadata = nullptr;
149 op->flags = 0;
150 op->reserved = nullptr;
151 op++;
152 op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
153 op->flags = 0;
154 op->reserved = nullptr;
155 op++;
156 op->op = GRPC_OP_RECV_INITIAL_METADATA;
157 op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
158 op->flags = 0;
159 op->reserved = nullptr;
160 op++;
161 op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
162 op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
163 op->data.recv_status_on_client.status = &status;
164 op->data.recv_status_on_client.status_details = &details;
165 op->flags = 0;
166 op->reserved = nullptr;
167 op++;
168 error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
169 GPR_ASSERT(GRPC_CALL_OK == error);
170
171 error =
172 grpc_server_request_call(f.server, &s, &call_details,
173 &request_metadata_recv, f.cq, f.cq, tag(101));
174 GPR_ASSERT(GRPC_CALL_OK == error);
175
176 CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
177 cq_verify(cqv);
178
Ken Payson5ca71f22018-01-11 20:24:06 -0800179 gpr_mu_lock(&g_mu);
180 g_server_call_stack = grpc_call_get_call_stack(s);
181 gpr_mu_unlock(&g_mu);
182
Ken Paysonb3532972018-01-11 20:25:30 -0800183 memset(ops, 0, sizeof(ops));
184 op = ops;
185 op->op = GRPC_OP_SEND_INITIAL_METADATA;
186 op->data.send_initial_metadata.count = 0;
187 op->flags = 0;
188 op->reserved = nullptr;
189 op++;
190 op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
191 op->data.send_status_from_server.trailing_metadata_count = 0;
192 op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
193 grpc_slice status_string = grpc_slice_from_static_string("xyz");
194 op->data.send_status_from_server.status_details = &status_string;
195 op->flags = 0;
196 op->reserved = nullptr;
197 op++;
198 op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
199 op->data.recv_close_on_server.cancelled = &was_cancelled;
200 op->flags = 0;
201 op->reserved = nullptr;
202 op++;
203 error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
204 GPR_ASSERT(GRPC_CALL_OK == error);
205
206 CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
207 CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
208 cq_verify(cqv);
209
210 GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
211 GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
212
213 grpc_slice_unref(details);
214 grpc_metadata_array_destroy(&initial_metadata_recv);
215 grpc_metadata_array_destroy(&trailing_metadata_recv);
216 grpc_metadata_array_destroy(&request_metadata_recv);
217 grpc_call_details_destroy(&call_details);
218
219 grpc_call_unref(s);
220 grpc_call_unref(c);
221
222 cq_verifier_destroy(cqv);
223
224 end_test(&f);
225 config.tear_down_data(&f);
226
227 // Perform checks after test tear-down
228 // Guards against the case that there's outstanding channel-related work on a
229 // call prior to verification
Ken Paysonb3532972018-01-11 20:25:30 -0800230 gpr_mu_lock(&g_mu);
231 if (!g_client_code_recv) {
232 GPR_ASSERT(gpr_cv_wait(&g_client_code_cv, &g_mu,
Ken Payson5ca71f22018-01-11 20:24:06 -0800233 grpc_timeout_seconds_to_deadline(3)) == 0);
Ken Paysonb3532972018-01-11 20:25:30 -0800234 }
235 if (!g_server_code_recv) {
Ken Payson5ca71f22018-01-11 20:24:06 -0800236 GPR_ASSERT(gpr_cv_wait(&g_server_code_cv, &g_mu,
237 grpc_timeout_seconds_to_deadline(3)) == 0);
Ken Paysonb3532972018-01-11 20:25:30 -0800238 }
239 GPR_ASSERT(g_client_status_code == GRPC_STATUS_UNIMPLEMENTED);
240 GPR_ASSERT(g_server_status_code == GRPC_STATUS_UNIMPLEMENTED);
241 gpr_mu_unlock(&g_mu);
Ken Paysonb3532972018-01-11 20:25:30 -0800242}
243
244/*******************************************************************************
245 * Test status_code filter
246 */
247
Ken Payson5ca71f22018-01-11 20:24:06 -0800248typedef struct final_status_data {
249 grpc_call_stack* call;
250} final_status_data;
251
Ken Paysonb3532972018-01-11 20:25:30 -0800252static grpc_error* init_call_elem(grpc_call_element* elem,
253 const grpc_call_element_args* args) {
Ken Payson5ca71f22018-01-11 20:24:06 -0800254 final_status_data* data = (final_status_data*)elem->call_data;
255 data->call = args->call_stack;
Ken Paysonb3532972018-01-11 20:25:30 -0800256 return GRPC_ERROR_NONE;
257}
258
259static void client_destroy_call_elem(grpc_call_element* elem,
260 const grpc_call_final_info* final_info,
261 grpc_closure* ignored) {
Ken Payson5ca71f22018-01-11 20:24:06 -0800262 final_status_data* data = (final_status_data*)elem->call_data;
Ken Paysonb3532972018-01-11 20:25:30 -0800263 gpr_mu_lock(&g_mu);
Ken Payson5ca71f22018-01-11 20:24:06 -0800264 // Some fixtures, like proxies, will spawn intermidiate calls
265 // We only want the results from our explicit calls
266 if (data->call == g_client_call_stack) {
267 g_client_status_code = final_info->final_status;
268 g_client_code_recv = true;
269 gpr_cv_signal(&g_client_code_cv);
270 }
Ken Paysonb3532972018-01-11 20:25:30 -0800271 gpr_mu_unlock(&g_mu);
272}
273
274static void server_destroy_call_elem(grpc_call_element* elem,
275 const grpc_call_final_info* final_info,
276 grpc_closure* ignored) {
Ken Payson5ca71f22018-01-11 20:24:06 -0800277 final_status_data* data = (final_status_data*)elem->call_data;
Ken Paysonb3532972018-01-11 20:25:30 -0800278 gpr_mu_lock(&g_mu);
Ken Payson5ca71f22018-01-11 20:24:06 -0800279 // Some fixtures, like proxies, will spawn intermidiate calls
280 // We only want the results from our explicit calls
281 if (data->call == g_server_call_stack) {
282 g_server_status_code = final_info->final_status;
283 g_server_code_recv = true;
284 gpr_cv_signal(&g_server_code_cv);
285 }
Ken Paysonb3532972018-01-11 20:25:30 -0800286 gpr_mu_unlock(&g_mu);
287}
288
289static grpc_error* init_channel_elem(grpc_channel_element* elem,
290 grpc_channel_element_args* args) {
291 return GRPC_ERROR_NONE;
292}
293
294static void destroy_channel_elem(grpc_channel_element* elem) {}
295
296static const grpc_channel_filter test_client_filter = {
297 grpc_call_next_op,
298 grpc_channel_next_op,
Ken Payson5ca71f22018-01-11 20:24:06 -0800299 sizeof(final_status_data),
Ken Paysonb3532972018-01-11 20:25:30 -0800300 init_call_elem,
301 grpc_call_stack_ignore_set_pollset_or_pollset_set,
302 client_destroy_call_elem,
303 0,
304 init_channel_elem,
305 destroy_channel_elem,
306 grpc_channel_next_get_info,
307 "client_filter_status_code"};
308
309static const grpc_channel_filter test_server_filter = {
310 grpc_call_next_op,
311 grpc_channel_next_op,
Ken Payson5ca71f22018-01-11 20:24:06 -0800312 sizeof(final_status_data),
Ken Paysonb3532972018-01-11 20:25:30 -0800313 init_call_elem,
314 grpc_call_stack_ignore_set_pollset_or_pollset_set,
315 server_destroy_call_elem,
316 0,
317 init_channel_elem,
318 destroy_channel_elem,
319 grpc_channel_next_get_info,
320 "server_filter_status_code"};
321
322/*******************************************************************************
323 * Registration
324 */
325
326static bool maybe_add_filter(grpc_channel_stack_builder* builder, void* arg) {
327 grpc_channel_filter* filter = (grpc_channel_filter*)arg;
328 if (g_enable_filter) {
329 // Want to add the filter as close to the end as possible, to make
330 // sure that all of the filters work well together. However, we
331 // can't add it at the very end, because the
332 // connected_channel/client_channel filter must be the last one.
333 // So we add it right before the last one.
334 grpc_channel_stack_builder_iterator* it =
335 grpc_channel_stack_builder_create_iterator_at_last(builder);
336 GPR_ASSERT(grpc_channel_stack_builder_move_prev(it));
337 const bool retval = grpc_channel_stack_builder_add_filter_before(
338 it, filter, nullptr, nullptr);
339 grpc_channel_stack_builder_iterator_destroy(it);
340 return retval;
341 } else {
342 return true;
343 }
344}
345
346static void init_plugin(void) {
347 gpr_mu_init(&g_mu);
348 gpr_cv_init(&g_client_code_cv);
349 gpr_cv_init(&g_server_code_cv);
350 g_client_code_recv = false;
351 g_server_code_recv = false;
352
353 grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX,
354 maybe_add_filter,
355 (void*)&test_client_filter);
356 grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX,
357 maybe_add_filter,
358 (void*)&test_client_filter);
359 grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
360 maybe_add_filter,
361 (void*)&test_server_filter);
362}
363
364static void destroy_plugin(void) {
365 gpr_cv_destroy(&g_client_code_cv);
366 gpr_cv_destroy(&g_server_code_cv);
367 gpr_mu_destroy(&g_mu);
368}
369
370void filter_status_code(grpc_end2end_test_config config) {
371 g_enable_filter = true;
372 test_request(config);
373 g_enable_filter = false;
374}
375
376void filter_status_code_pre_init(void) {
377 grpc_register_plugin(init_plugin, destroy_plugin);
378}