1 /*
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 /*******************************************************************************
20 * This test verifies that various stack configurations result in the set of
21 * filters that we expect.
22 *
23 * This is akin to a golden-file test, and suffers the same disadvantages and
24 * advantages: it reflects that the code as written has not been modified - and
25 * valid code modifications WILL break this test and it will need updating.
26 *
27 * The intent therefore is to allow code reviewers to more easily catch changes
28 * that perturb the generated list of channel filters in different
29 * configurations and assess whether such a change is correct and desirable.
30 */
31
32 #include <grpc/grpc.h>
33 #include <grpc/support/alloc.h>
34 #include <grpc/support/string_util.h>
35 #include <string.h>
36
37 #include "src/core/lib/channel/channel_stack_builder.h"
38 #include "src/core/lib/gpr/string.h"
39 #include "src/core/lib/surface/channel_init.h"
40 #include "src/core/lib/surface/channel_stack_type.h"
41 #include "src/core/lib/transport/transport_impl.h"
42 #include "test/core/util/test_config.h"
43
44 // use CHECK_STACK instead
45 static int check_stack(const char* file, int line, const char* transport_name,
46 grpc_channel_args* init_args,
47 unsigned channel_stack_type, ...);
48
49 // arguments: const char *transport_name - the name of the transport type to
50 // simulate
51 // grpc_channel_args *init_args - channel args to pass down
52 // grpc_channel_stack_type channel_stack_type - the archetype of
53 // channel stack to create
54 // variadic arguments - the (in-order) expected list of channel
55 // filters to instantiate, terminated with NULL
56 #define CHECK_STACK(...) check_stack(__FILE__, __LINE__, __VA_ARGS__)
57
main(int argc,char ** argv)58 int main(int argc, char** argv) {
59 grpc_test_init(argc, argv);
60 grpc_init();
61 int errors = 0;
62
63 // tests with a minimal stack
64 grpc_arg minimal_stack_arg;
65 minimal_stack_arg.type = GRPC_ARG_INTEGER;
66 minimal_stack_arg.key = const_cast<char*>(GRPC_ARG_MINIMAL_STACK);
67 minimal_stack_arg.value.integer = 1;
68 grpc_channel_args minimal_stack_args = {1, &minimal_stack_arg};
69 errors +=
70 CHECK_STACK("unknown", &minimal_stack_args, GRPC_CLIENT_DIRECT_CHANNEL,
71 "authority", "connected", NULL);
72 errors += CHECK_STACK("unknown", &minimal_stack_args, GRPC_CLIENT_SUBCHANNEL,
73 "authority", "connected", NULL);
74 errors += CHECK_STACK("unknown", &minimal_stack_args, GRPC_SERVER_CHANNEL,
75 "server", "connected", NULL);
76 errors +=
77 CHECK_STACK("chttp2", &minimal_stack_args, GRPC_CLIENT_DIRECT_CHANNEL,
78 "authority", "http-client", "connected", NULL);
79 errors += CHECK_STACK("chttp2", &minimal_stack_args, GRPC_CLIENT_SUBCHANNEL,
80 "authority", "http-client", "connected", NULL);
81 errors += CHECK_STACK("chttp2", &minimal_stack_args, GRPC_SERVER_CHANNEL,
82 "server", "http-server", "connected", NULL);
83 errors += CHECK_STACK(nullptr, &minimal_stack_args, GRPC_CLIENT_CHANNEL,
84 "client-channel", NULL);
85
86 // tests with a default stack
87 errors +=
88 CHECK_STACK("unknown", nullptr, GRPC_CLIENT_DIRECT_CHANNEL, "authority",
89 "message_size", "deadline", "connected", NULL);
90 errors += CHECK_STACK("unknown", nullptr, GRPC_CLIENT_SUBCHANNEL, "authority",
91 "message_size", "connected", NULL);
92 errors += CHECK_STACK("unknown", nullptr, GRPC_SERVER_CHANNEL, "server",
93 "message_size", "deadline", "connected", NULL);
94 errors += CHECK_STACK("chttp2", nullptr, GRPC_CLIENT_DIRECT_CHANNEL,
95 "authority", "message_size", "deadline", "http-client",
96 "message_compress", "connected", NULL);
97 errors += CHECK_STACK("chttp2", nullptr, GRPC_CLIENT_SUBCHANNEL, "authority",
98 "message_size", "http-client", "message_compress",
99 "connected", NULL);
100 errors += CHECK_STACK("chttp2", nullptr, GRPC_SERVER_CHANNEL, "server",
101 "message_size", "deadline", "http-server",
102 "message_compress", "connected", NULL);
103 errors += CHECK_STACK(nullptr, nullptr, GRPC_CLIENT_CHANNEL, "client-channel",
104 NULL);
105
106 GPR_ASSERT(errors == 0);
107 grpc_shutdown();
108 return 0;
109 }
110
111 /*******************************************************************************
112 * End of tests definitions, start of test infrastructure
113 */
114
check_stack(const char * file,int line,const char * transport_name,grpc_channel_args * init_args,unsigned channel_stack_type,...)115 static int check_stack(const char* file, int line, const char* transport_name,
116 grpc_channel_args* init_args,
117 unsigned channel_stack_type, ...) {
118 // create dummy channel stack
119 grpc_channel_stack_builder* builder = grpc_channel_stack_builder_create();
120 grpc_transport_vtable fake_transport_vtable;
121 memset(&fake_transport_vtable, 0, sizeof(grpc_transport_vtable));
122 fake_transport_vtable.name = transport_name;
123 grpc_transport fake_transport = {&fake_transport_vtable};
124 grpc_channel_stack_builder_set_target(builder, "foo.test.google.fr");
125 grpc_channel_args* channel_args = grpc_channel_args_copy(init_args);
126 if (transport_name != nullptr) {
127 grpc_channel_stack_builder_set_transport(builder, &fake_transport);
128 }
129 {
130 grpc_core::ExecCtx exec_ctx;
131 grpc_channel_stack_builder_set_channel_arguments(builder, channel_args);
132 GPR_ASSERT(grpc_channel_init_create_stack(
133 builder, (grpc_channel_stack_type)channel_stack_type));
134 }
135
136 // build up our expectation list
137 gpr_strvec v;
138 gpr_strvec_init(&v);
139 va_list args;
140 va_start(args, channel_stack_type);
141 for (;;) {
142 char* a = va_arg(args, char*);
143 if (a == nullptr) break;
144 if (v.count != 0) gpr_strvec_add(&v, gpr_strdup(", "));
145 gpr_strvec_add(&v, gpr_strdup(a));
146 }
147 va_end(args);
148 char* expect = gpr_strvec_flatten(&v, nullptr);
149 gpr_strvec_destroy(&v);
150
151 // build up our "got" list
152 gpr_strvec_init(&v);
153 grpc_channel_stack_builder_iterator* it =
154 grpc_channel_stack_builder_create_iterator_at_first(builder);
155 while (grpc_channel_stack_builder_move_next(it)) {
156 const char* name = grpc_channel_stack_builder_iterator_filter_name(it);
157 if (name == nullptr) continue;
158 if (v.count != 0) gpr_strvec_add(&v, gpr_strdup(", "));
159 gpr_strvec_add(&v, gpr_strdup(name));
160 }
161 char* got = gpr_strvec_flatten(&v, nullptr);
162 gpr_strvec_destroy(&v);
163 grpc_channel_stack_builder_iterator_destroy(it);
164
165 // figure out result, log if there's an error
166 int result = 0;
167 if (0 != strcmp(got, expect)) {
168 gpr_strvec_init(&v);
169 gpr_strvec_add(&v, gpr_strdup("{"));
170 for (size_t i = 0; i < channel_args->num_args; i++) {
171 if (i > 0) gpr_strvec_add(&v, gpr_strdup(", "));
172 gpr_strvec_add(&v, gpr_strdup(channel_args->args[i].key));
173 gpr_strvec_add(&v, gpr_strdup("="));
174 switch (channel_args->args[i].type) {
175 case GRPC_ARG_INTEGER: {
176 char* tmp;
177 gpr_asprintf(&tmp, "%d", channel_args->args[i].value.integer);
178 gpr_strvec_add(&v, tmp);
179 break;
180 }
181 case GRPC_ARG_STRING:
182 gpr_strvec_add(&v, gpr_strdup(channel_args->args[i].value.string));
183 break;
184 case GRPC_ARG_POINTER: {
185 char* tmp;
186 gpr_asprintf(&tmp, "%p", channel_args->args[i].value.pointer.p);
187 gpr_strvec_add(&v, tmp);
188 break;
189 }
190 }
191 }
192 gpr_strvec_add(&v, gpr_strdup("}"));
193 char* args_str = gpr_strvec_flatten(&v, nullptr);
194 gpr_strvec_destroy(&v);
195
196 gpr_log(file, line, GPR_LOG_SEVERITY_ERROR,
197 "**************************************************");
198 gpr_log(
199 file, line, GPR_LOG_SEVERITY_ERROR,
200 "FAILED transport=%s; stack_type=%s; channel_args=%s:", transport_name,
201 grpc_channel_stack_type_string(
202 static_cast<grpc_channel_stack_type>(channel_stack_type)),
203 args_str);
204 gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "EXPECTED: %s", expect);
205 gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "GOT: %s", got);
206 result = 1;
207
208 gpr_free(args_str);
209 }
210
211 gpr_free(got);
212 gpr_free(expect);
213
214 {
215 grpc_core::ExecCtx exec_ctx;
216 grpc_channel_stack_builder_destroy(builder);
217 grpc_channel_args_destroy(channel_args);
218 }
219
220 return result;
221 }
222