xref: /aosp_15_r20/external/grpc-grpc/test/core/channel/channel_args_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 //
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 //
18 
19 #include "src/core/lib/channel/channel_args.h"
20 
21 #include <string.h>
22 
23 #include "gtest/gtest.h"
24 
25 #include <grpc/grpc.h>
26 #include <grpc/grpc_security.h>
27 #include <grpc/impl/channel_arg_names.h>
28 #include <grpc/support/alloc.h>
29 #include <grpc/support/log.h>
30 
31 #include "src/core/lib/gpr/useful.h"
32 #include "src/core/lib/gprpp/notification.h"
33 #include "src/core/lib/gprpp/ref_counted.h"
34 #include "src/core/lib/gprpp/ref_counted_ptr.h"
35 #include "src/core/lib/iomgr/exec_ctx.h"
36 #include "test/core/util/test_config.h"
37 
38 namespace grpc_core {
39 
40 using ::grpc_event_engine::experimental::CreateEventEngine;
41 using ::grpc_event_engine::experimental::EventEngine;
42 
TEST(ChannelArgsTest,Noop)43 TEST(ChannelArgsTest, Noop) { ChannelArgs(); }
44 
TEST(ChannelArgsTest,SetGetRemove)45 TEST(ChannelArgsTest, SetGetRemove) {
46   const grpc_arg_pointer_vtable malloc_vtable = {
47       // copy
48       [](void* p) { return p; },
49       // destroy
50       [](void*) {},
51       // equal
52       [](void* p1, void* p2) { return QsortCompare(p1, p2); },
53   };
54   void* ptr = gpr_malloc(42);
55 
56   ChannelArgs a;
57   ChannelArgs b = a.Set("answer", 42);
58   ChannelArgs c = b.Set("foo", "bar");
59   ChannelArgs d = c.Set("ptr", ChannelArgs::Pointer(ptr, &malloc_vtable));
60   ChannelArgs e = d.Set("alpha", "beta");
61   ChannelArgs f = e.Remove("answer");
62   EXPECT_EQ(a.Get("answer"), nullptr);
63   EXPECT_EQ(*b.Get("answer"), ChannelArgs::Value(42));
64   EXPECT_EQ(*c.Get("answer"), ChannelArgs::Value(42));
65   EXPECT_EQ(c.GetInt("answer"), 42);
66   EXPECT_EQ(c.GetString("answer"), absl::nullopt);
67   EXPECT_EQ(f.Get("answer"), nullptr);
68   EXPECT_EQ(*c.Get("foo"), ChannelArgs::Value("bar"));
69   EXPECT_EQ(c.GetString("foo"), "bar");
70   EXPECT_EQ(c.GetString("answer"), absl::nullopt);
71   EXPECT_EQ(*d.Get("ptr"),
72             ChannelArgs::Value(ChannelArgs::Pointer(ptr, &malloc_vtable)));
73   EXPECT_EQ(*e.Get("alpha"), ChannelArgs::Value("beta"));
74   gpr_free(ptr);
75 }
76 
TEST(ChannelArgsTest,RemoveAllKeysWithPrefix)77 TEST(ChannelArgsTest, RemoveAllKeysWithPrefix) {
78   ChannelArgs args;
79   args = args.Set("foo", 1);
80   args = args.Set("foo.bar", 2);
81   args = args.Set("foo.baz", 3);
82   args = args.Set("bar", 4);
83   ChannelArgs modified = args.RemoveAllKeysWithPrefix("foo.");
84   EXPECT_EQ(modified.GetInt("foo"), 1);
85   EXPECT_EQ(modified.GetInt("foo.bar"), absl::nullopt);
86   EXPECT_EQ(modified.GetInt("foo.baz"), absl::nullopt);
87   EXPECT_EQ(modified.GetInt("bar"), 4);
88 }
89 
TEST(ChannelArgsTest,StoreRefCountedPtr)90 TEST(ChannelArgsTest, StoreRefCountedPtr) {
91   struct Test : public RefCounted<Test> {
92     explicit Test(int n) : n(n) {}
93     int n;
94     static int ChannelArgsCompare(const Test* a, const Test* b) {
95       return a->n - b->n;
96     }
97   };
98   auto p = MakeRefCounted<Test>(123);
99 
100   ChannelArgs a;
101   a = a.Set("test", p);
102   EXPECT_EQ(a.GetPointer<Test>("test")->n, 123);
103 }
104 
TEST(ChannelArgsTest,ObjectApi)105 TEST(ChannelArgsTest, ObjectApi) {
106   struct MyFancyObject : public RefCounted<MyFancyObject> {
107     explicit MyFancyObject(int n) : n(n) {}
108     static absl::string_view ChannelArgName() {
109       return "grpc.internal.my-fancy-object";
110     }
111     int n;
112     static int ChannelArgsCompare(const MyFancyObject* a,
113                                   const MyFancyObject* b) {
114       return a->n - b->n;
115     }
116   };
117   auto p = MakeRefCounted<MyFancyObject>(42);
118   ChannelArgs a;
119   a = a.SetObject(std::move(p));
120   EXPECT_EQ(a.GetObject<MyFancyObject>()->n, 42);
121 }
122 
TEST(ChannelArgsTest,ToAndFromC)123 TEST(ChannelArgsTest, ToAndFromC) {
124   const grpc_arg_pointer_vtable malloc_vtable = {
125       // copy
126       [](void* p) { return p; },
127       // destroy
128       [](void*) {},
129       // equal
130       [](void* p1, void* p2) { return QsortCompare(p1, p2); },
131   };
132   void* ptr = gpr_malloc(42);
133   ChannelArgs a = ChannelArgs()
134                       .Set("answer", 42)
135                       .Set("foo", "bar")
136                       .Set("ptr", ChannelArgs::Pointer(ptr, &malloc_vtable))
137                       .Set("alpha", "beta");
138   ChannelArgs b = ChannelArgs::FromC(a.ToC().get());
139   EXPECT_EQ(a, b);
140   gpr_free(ptr);
141 }
142 
143 // shared_ptrs in ChannelArgs must support enable_shared_from_this
144 class ShareableObject : public std::enable_shared_from_this<ShareableObject> {
145  public:
ShareableObject(int n)146   explicit ShareableObject(int n) : n(n) {}
147   int n;
ChannelArgsCompare(const ShareableObject * a,const ShareableObject * b)148   static int ChannelArgsCompare(const ShareableObject* a,
149                                 const ShareableObject* b) {
150     return a->n - b->n;
151   }
ChannelArgName()152   static absl::string_view ChannelArgName() { return "grpc.test"; }
153 };
154 
TEST(ChannelArgsTest,StoreAndRetrieveSharedPtr)155 TEST(ChannelArgsTest, StoreAndRetrieveSharedPtr) {
156   std::shared_ptr<ShareableObject> copied_obj;
157   {
158     ChannelArgs channel_args;
159     auto shared_obj = std::make_shared<ShareableObject>(42);
160     EXPECT_TRUE(shared_obj.unique());
161     channel_args = channel_args.SetObject(shared_obj);
162     EXPECT_FALSE(shared_obj.unique());
163     copied_obj = channel_args.GetObjectRef<ShareableObject>();
164     EXPECT_EQ(copied_obj->n, 42);
165     // Refs: p, copied_obj, and ChannelArgs
166     EXPECT_EQ(3, copied_obj.use_count());
167   }
168   // The p and ChannelArgs are deleted.
169   EXPECT_TRUE(copied_obj.unique());
170   EXPECT_EQ(copied_obj->n, 42);
171 }
172 
TEST(ChannelArgsTest,RetrieveRawPointerFromStoredSharedPtr)173 TEST(ChannelArgsTest, RetrieveRawPointerFromStoredSharedPtr) {
174   ChannelArgs channel_args;
175   auto shared_obj = std::make_shared<ShareableObject>(42);
176   EXPECT_TRUE(shared_obj.unique());
177   channel_args = channel_args.SetObject(shared_obj);
178   EXPECT_FALSE(shared_obj.unique());
179   ShareableObject* raw_obj = channel_args.GetObject<ShareableObject>();
180   EXPECT_EQ(raw_obj->n, 42);
181   // Refs: p and ChannelArgs
182   EXPECT_EQ(2, shared_obj.use_count());
183 }
184 
TEST(ChannelArgsTest,StoreSharedPtrEventEngine)185 TEST(ChannelArgsTest, StoreSharedPtrEventEngine) {
186   auto p = std::shared_ptr<EventEngine>(CreateEventEngine());
187   ChannelArgs a;
188   a = a.SetObject(p);
189   Notification signal;
190   bool triggered = false;
191   a.GetObjectRef<EventEngine>()->Run([&triggered, &signal] {
192     triggered = true;
193     signal.Notify();
194   });
195   signal.WaitForNotification();
196   ASSERT_TRUE(triggered);
197 }
198 
TEST(ChannelArgsTest,GetNonOwningEventEngine)199 TEST(ChannelArgsTest, GetNonOwningEventEngine) {
200   auto p = std::shared_ptr<EventEngine>(CreateEventEngine());
201   ASSERT_TRUE(p.unique());
202   ChannelArgs a;
203   a = a.SetObject(p);
204   ASSERT_FALSE(p.unique());
205   ASSERT_EQ(p.use_count(), 2);
206   EventEngine* engine = a.GetObject<EventEngine>();
207   (void)engine;
208   // p and the channel args
209   ASSERT_EQ(p.use_count(), 2);
210 }
211 
212 struct MutableValue : public RefCounted<MutableValue> {
ChannelArgNamegrpc_core::MutableValue213   static constexpr absl::string_view ChannelArgName() {
214     return "grpc.test.mutable_value";
215   }
ChannelArgsComparegrpc_core::MutableValue216   static int ChannelArgsCompare(const MutableValue* a, const MutableValue* b) {
217     return a->i - b->i;
218   }
219   int i = 42;
220 };
221 
222 struct ConstValue : public RefCounted<ConstValue> {
ChannelArgNamegrpc_core::ConstValue223   static constexpr absl::string_view ChannelArgName() {
224     return "grpc.test.const_value";
225   }
ChannelArgUseConstPtrgrpc_core::ConstValue226   static constexpr bool ChannelArgUseConstPtr() { return true; };
ChannelArgsComparegrpc_core::ConstValue227   static int ChannelArgsCompare(const ConstValue* a, const ConstValue* b) {
228     return a->i - b->i;
229   }
230   int i = 42;
231 };
232 
TEST(ChannelArgsTest,SetObjectRespectsMutabilityConstraints)233 TEST(ChannelArgsTest, SetObjectRespectsMutabilityConstraints) {
234   auto m = MakeRefCounted<MutableValue>();
235   auto c = MakeRefCounted<const ConstValue>();
236   auto args = ChannelArgs().SetObject(m).SetObject(c);
237   RefCountedPtr<MutableValue> m1 = args.GetObjectRef<MutableValue>();
238   RefCountedPtr<const ConstValue> c1 = args.GetObjectRef<ConstValue>();
239   EXPECT_EQ(m1.get(), m.get());
240   EXPECT_EQ(c1.get(), c.get());
241 }
242 
243 }  // namespace grpc_core
244 
TEST(GrpcChannelArgsTest,Create)245 TEST(GrpcChannelArgsTest, Create) {
246   grpc_core::ExecCtx exec_ctx;
247   grpc_arg to_add[2];
248   grpc_channel_args* ch_args;
249 
250   to_add[0] =
251       grpc_channel_arg_integer_create(const_cast<char*>("int_arg"), 123);
252   to_add[1] = grpc_channel_arg_string_create(const_cast<char*>("str key"),
253                                              const_cast<char*>("str value"));
254   ch_args = grpc_channel_args_copy_and_add(nullptr, to_add, 2);
255 
256   GPR_ASSERT(ch_args->num_args == 2);
257   GPR_ASSERT(strcmp(ch_args->args[0].key, to_add[0].key) == 0);
258   GPR_ASSERT(ch_args->args[0].type == to_add[0].type);
259   GPR_ASSERT(ch_args->args[0].value.integer == to_add[0].value.integer);
260 
261   GPR_ASSERT(strcmp(ch_args->args[1].key, to_add[1].key) == 0);
262   GPR_ASSERT(ch_args->args[1].type == to_add[1].type);
263   GPR_ASSERT(strcmp(ch_args->args[1].value.string, to_add[1].value.string) ==
264              0);
265 
266   grpc_channel_args_destroy(ch_args);
267 }
268 
269 struct fake_class {
270   int foo;
271 };
272 
fake_pointer_arg_copy(void * arg)273 static void* fake_pointer_arg_copy(void* arg) {
274   gpr_log(GPR_DEBUG, "fake_pointer_arg_copy");
275   fake_class* fc = static_cast<fake_class*>(arg);
276   fake_class* new_fc = static_cast<fake_class*>(gpr_malloc(sizeof(fake_class)));
277   new_fc->foo = fc->foo;
278   return new_fc;
279 }
280 
fake_pointer_arg_destroy(void * arg)281 static void fake_pointer_arg_destroy(void* arg) {
282   gpr_log(GPR_DEBUG, "fake_pointer_arg_destroy");
283   fake_class* fc = static_cast<fake_class*>(arg);
284   gpr_free(fc);
285 }
286 
fake_pointer_cmp(void * a,void * b)287 static int fake_pointer_cmp(void* a, void* b) {
288   return grpc_core::QsortCompare(a, b);
289 }
290 
291 static const grpc_arg_pointer_vtable fake_pointer_arg_vtable = {
292     fake_pointer_arg_copy, fake_pointer_arg_destroy, fake_pointer_cmp};
293 
TEST(GrpcChannelArgsTest,ChannelCreateWithArgs)294 TEST(GrpcChannelArgsTest, ChannelCreateWithArgs) {
295   grpc_arg client_a[3];
296 
297   client_a[0] =
298       grpc_channel_arg_integer_create(const_cast<char*>("arg_int"), 0);
299   client_a[1] = grpc_channel_arg_string_create(
300       const_cast<char*>("arg_str"), const_cast<char*>("arg_str_val"));
301   // allocated and adds custom pointer arg
302   fake_class* fc = static_cast<fake_class*>(gpr_malloc(sizeof(fake_class)));
303   fc->foo = 42;
304   client_a[2] = grpc_channel_arg_pointer_create(
305       const_cast<char*>("arg_pointer"), fc, &fake_pointer_arg_vtable);
306 
307   // creates channel
308   grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
309   grpc_channel_credentials* creds = grpc_insecure_credentials_create();
310   grpc_channel* c = grpc_channel_create("fake_target", creds, &client_args);
311   grpc_channel_credentials_release(creds);
312   // user is can free the memory they allocated here
313   gpr_free(fc);
314   grpc_channel_destroy(c);
315 }
316 
mutate_channel_args(const char * target,grpc_channel_args * old_args,grpc_channel_stack_type)317 grpc_channel_args* mutate_channel_args(const char* target,
318                                        grpc_channel_args* old_args,
319                                        grpc_channel_stack_type /*type*/) {
320   GPR_ASSERT(old_args != nullptr);
321   GPR_ASSERT(grpc_channel_args_find(old_args, "arg_int")->value.integer == 0);
322   GPR_ASSERT(strcmp(grpc_channel_args_find(old_args, "arg_str")->value.string,
323                     "arg_str_val") == 0);
324   GPR_ASSERT(
325       grpc_channel_args_find(old_args, "arg_pointer")->value.pointer.vtable ==
326       &fake_pointer_arg_vtable);
327 
328   if (strcmp(target, "no_op_mutator") == 0) {
329     return old_args;
330   }
331 
332   GPR_ASSERT(strcmp(target, "minimal_stack_mutator") == 0);
333   const char* args_to_remove[] = {"arg_int", "arg_str", "arg_pointer"};
334 
335   grpc_arg no_deadline_filter_arg = grpc_channel_arg_integer_create(
336       const_cast<char*>(GRPC_ARG_MINIMAL_STACK), 1);
337   grpc_channel_args* new_args = nullptr;
338   new_args = grpc_channel_args_copy_and_add_and_remove(
339       old_args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove),
340       &no_deadline_filter_arg, 1);
341   grpc_channel_args_destroy(old_args);
342   return new_args;
343 }
344 
TEST(GrpcChannelArgsTest,TestServerCreateWithArgs)345 TEST(GrpcChannelArgsTest, TestServerCreateWithArgs) {
346   grpc_arg server_a[3];
347 
348   // adds integer arg
349   server_a[0].type = GRPC_ARG_INTEGER;
350   server_a[0].key = const_cast<char*>("arg_int");
351   server_a[0].value.integer = 0;
352 
353   // adds const str arg
354   server_a[1].type = GRPC_ARG_STRING;
355   server_a[1].key = const_cast<char*>("arg_str");
356   server_a[1].value.string = const_cast<char*>("arg_str_val");
357 
358   // allocated and adds custom pointer arg
359   fake_class* fc = static_cast<fake_class*>(gpr_malloc(sizeof(fake_class)));
360   fc->foo = 42;
361   server_a[2].type = GRPC_ARG_POINTER;
362   server_a[2].key = const_cast<char*>("arg_pointer");
363   server_a[2].value.pointer.vtable = &fake_pointer_arg_vtable;
364   server_a[2].value.pointer.p = fc;
365 
366   // creates server
367   grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a};
368   grpc_server* s = grpc_server_create(&server_args, nullptr);
369   // user is can free the memory they allocated here
370   gpr_free(fc);
371   grpc_server_destroy(s);
372 }
373 
main(int argc,char ** argv)374 int main(int argc, char** argv) {
375   ::testing::InitGoogleTest(&argc, argv);
376   grpc::testing::TestEnvironment env(&argc, argv);
377   grpc_init();
378   auto r = RUN_ALL_TESTS();
379   grpc_shutdown();
380   return r;
381 }
382