blob: a70f50af988674bec50998185f294faa430705cd [file] [log] [blame]
Mark D. Roth5d11e432016-06-23 13:14:05 -07001/*
2 *
3 * Copyright 2016, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include "test/core/end2end/end2end_tests.h"
35
Mark D. Roth44a2f252016-07-18 14:13:31 -070036#include <limits.h>
Mark D. Roth5d11e432016-06-23 13:14:05 -070037#include <stdbool.h>
38#include <stdio.h>
39#include <string.h>
40
41#include <grpc/byte_buffer.h>
42#include <grpc/support/alloc.h>
43#include <grpc/support/log.h>
44#include <grpc/support/time.h>
45#include <grpc/support/useful.h>
46#include "src/core/lib/channel/channel_stack_builder.h"
47#include "src/core/lib/surface/channel_init.h"
48#include "test/core/end2end/cq_verifier.h"
49
50enum { TIMEOUT = 200000 };
51
52static bool g_enable_filter = false;
53
54static void *tag(intptr_t t) { return (void *)t; }
55
56static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
57 const char *test_name,
58 grpc_channel_args *client_args,
59 grpc_channel_args *server_args) {
60 grpc_end2end_test_fixture f;
61 gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
62 f = config.create_fixture(client_args, server_args);
63 config.init_server(&f, server_args);
64 config.init_client(&f, client_args);
65 return f;
66}
67
68static gpr_timespec n_seconds_time(int n) {
69 return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n);
70}
71
72static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
73
74static void drain_cq(grpc_completion_queue *cq) {
75 grpc_event ev;
76 do {
77 ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
78 } while (ev.type != GRPC_QUEUE_SHUTDOWN);
79}
80
81static void shutdown_server(grpc_end2end_test_fixture *f) {
82 if (!f->server) return;
83 grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
84 GPR_ASSERT(grpc_completion_queue_pluck(
85 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
86 .type == GRPC_OP_COMPLETE);
87 grpc_server_destroy(f->server);
88 f->server = NULL;
89}
90
91static void shutdown_client(grpc_end2end_test_fixture *f) {
92 if (!f->client) return;
93 grpc_channel_destroy(f->client);
94 f->client = NULL;
95}
96
97static void end_test(grpc_end2end_test_fixture *f) {
98 shutdown_server(f);
99 shutdown_client(f);
100
101 grpc_completion_queue_shutdown(f->cq);
102 drain_cq(f->cq);
103 grpc_completion_queue_destroy(f->cq);
104}
105
106// Simple request via a server filter that always fails to initialize
107// the call.
108static void test_request(grpc_end2end_test_config config) {
109 grpc_call *c;
110 grpc_call *s;
111 gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
112 grpc_byte_buffer *request_payload =
113 grpc_raw_byte_buffer_create(&request_payload_slice, 1);
114 gpr_timespec deadline = five_seconds_time();
115 grpc_end2end_test_fixture f =
116 begin_test(config, "filter_call_init_fails", NULL, NULL);
117 cq_verifier *cqv = cq_verifier_create(f.cq);
118 grpc_op ops[6];
119 grpc_op *op;
120 grpc_metadata_array initial_metadata_recv;
121 grpc_metadata_array trailing_metadata_recv;
122 grpc_metadata_array request_metadata_recv;
123 grpc_byte_buffer *request_payload_recv = NULL;
124 grpc_call_details call_details;
125 grpc_status_code status;
126 grpc_call_error error;
127 char *details = NULL;
128 size_t details_capacity = 0;
129
130 c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
131 "/foo", "foo.test.google.fr", deadline, NULL);
132 GPR_ASSERT(c);
133
134 grpc_metadata_array_init(&initial_metadata_recv);
135 grpc_metadata_array_init(&trailing_metadata_recv);
136 grpc_metadata_array_init(&request_metadata_recv);
137 grpc_call_details_init(&call_details);
138
139 memset(ops, 0, sizeof(ops));
140 op = ops;
141 op->op = GRPC_OP_SEND_INITIAL_METADATA;
142 op->data.send_initial_metadata.count = 0;
143 op->data.send_initial_metadata.metadata = NULL;
144 op->flags = 0;
145 op->reserved = NULL;
146 op++;
147 op->op = GRPC_OP_SEND_MESSAGE;
148 op->data.send_message = request_payload;
149 op->flags = 0;
150 op->reserved = NULL;
151 op++;
152 op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
153 op->flags = 0;
154 op->reserved = NULL;
155 op++;
156 op->op = GRPC_OP_RECV_INITIAL_METADATA;
157 op->data.recv_initial_metadata = &initial_metadata_recv;
158 op->flags = 0;
159 op->reserved = NULL;
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->data.recv_status_on_client.status_details_capacity = &details_capacity;
166 op->flags = 0;
167 op->reserved = NULL;
168 op++;
169 error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
170 GPR_ASSERT(GRPC_CALL_OK == error);
171
172 error =
173 grpc_server_request_call(f.server, &s, &call_details,
174 &request_metadata_recv, f.cq, f.cq, tag(101));
175 GPR_ASSERT(GRPC_CALL_OK == error);
176
Mark D. Roth7f9bba82016-08-25 08:35:42 -0700177 CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
Mark D. Roth5d11e432016-06-23 13:14:05 -0700178 cq_verify(cqv);
179
180 GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
181 GPR_ASSERT(0 == strcmp(details, "access denied"));
182
183 gpr_free(details);
184 grpc_metadata_array_destroy(&initial_metadata_recv);
185 grpc_metadata_array_destroy(&trailing_metadata_recv);
186 grpc_metadata_array_destroy(&request_metadata_recv);
187 grpc_call_details_destroy(&call_details);
188
189 grpc_call_destroy(c);
190
191 cq_verifier_destroy(cqv);
192
193 grpc_byte_buffer_destroy(request_payload);
194 grpc_byte_buffer_destroy(request_payload_recv);
195
196 end_test(&f);
197 config.tear_down_data(&f);
198}
199
200/*******************************************************************************
201 * Test filter - always fails to initialize a call
202 */
203
Mark D. Roth76d24422016-06-23 13:22:10 -0700204static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
Mark D. Roth5d11e432016-06-23 13:14:05 -0700205 grpc_call_element *elem,
206 grpc_call_element_args *args) {
207 return grpc_error_set_int(GRPC_ERROR_CREATE("access denied"),
208 GRPC_ERROR_INT_GRPC_STATUS,
209 GRPC_STATUS_PERMISSION_DENIED);
210}
211
212static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
Mark D. Rothcca4a192016-08-02 10:36:53 -0700213 const grpc_call_final_info *final_info,
Mark D. Roth5d11e432016-06-23 13:14:05 -0700214 void *and_free_memory) {}
215
216static void init_channel_elem(grpc_exec_ctx *exec_ctx,
217 grpc_channel_element *elem,
218 grpc_channel_element_args *args) {}
219
220static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
221 grpc_channel_element *elem) {}
222
223static const grpc_channel_filter test_filter = {
224 grpc_call_next_op,
225 grpc_channel_next_op,
226 0,
227 init_call_elem,
228 grpc_call_stack_ignore_set_pollset_or_pollset_set,
229 destroy_call_elem,
230 0,
231 init_channel_elem,
232 destroy_channel_elem,
233 grpc_call_next_get_peer,
234 "filter_call_init_fails"};
235
236/*******************************************************************************
237 * Registration
238 */
239
240static bool maybe_add_filter(grpc_channel_stack_builder *builder, void *arg) {
241 if (g_enable_filter) {
Mark D. Rothb5f32f02016-07-19 08:36:52 -0700242 // Want to add the filter as close to the end as possible, to make
243 // sure that all of the filters work well together. However, we
244 // can't add it at the very end, because the connected channel filter
245 // must be the last one. So we add it right before the last one.
246 grpc_channel_stack_builder_iterator *it =
247 grpc_channel_stack_builder_create_iterator_at_last(builder);
248 GPR_ASSERT(grpc_channel_stack_builder_move_prev(it));
Mark D. Roth05d73af2016-07-27 15:52:46 +0000249 const bool retval = grpc_channel_stack_builder_add_filter_before(
250 it, &test_filter, NULL, NULL);
251 grpc_channel_stack_builder_iterator_destroy(it);
252 return retval;
Mark D. Roth5d11e432016-06-23 13:14:05 -0700253 } else {
254 return true;
255 }
256}
257
258static void init_plugin(void) {
Mark D. Roth44a2f252016-07-18 14:13:31 -0700259 grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
Mark D. Roth51d00222016-07-15 09:12:26 -0700260 maybe_add_filter, NULL);
Mark D. Roth5d11e432016-06-23 13:14:05 -0700261}
262
263static void destroy_plugin(void) {}
264
265void filter_call_init_fails(grpc_end2end_test_config config) {
266 g_enable_filter = true;
267 test_request(config);
268 g_enable_filter = false;
269}
270
271void filter_call_init_fails_pre_init(void) {
272 grpc_register_plugin(init_plugin, destroy_plugin);
273}