• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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