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 <grpcpp/support/channel_arguments.h> 20 21 #include <grpc/grpc.h> 22 #include <grpcpp/grpcpp.h> 23 #include <gtest/gtest.h> 24 25 #include "src/core/lib/gpr/useful.h" 26 #include "src/core/lib/iomgr/exec_ctx.h" 27 #include "src/core/lib/iomgr/socket_mutator.h" 28 29 namespace grpc { 30 namespace testing { 31 32 namespace { 33 34 // A simple grpc_socket_mutator to be used to test SetSocketMutator 35 class TestSocketMutator : public grpc_socket_mutator { 36 public: 37 TestSocketMutator(); 38 39 bool MutateFd(int fd) { 40 // Do nothing on the fd 41 return true; 42 } 43 }; 44 45 // 46 // C API for TestSocketMutator 47 // 48 49 bool test_mutator_mutate_fd(int fd, grpc_socket_mutator* mutator) { 50 TestSocketMutator* tsm = (TestSocketMutator*)mutator; 51 return tsm->MutateFd(fd); 52 } 53 54 int test_mutator_compare(grpc_socket_mutator* a, grpc_socket_mutator* b) { 55 return GPR_ICMP(a, b); 56 } 57 58 void test_mutator_destroy(grpc_socket_mutator* mutator) { 59 TestSocketMutator* tsm = (TestSocketMutator*)mutator; 60 delete tsm; 61 } 62 63 grpc_socket_mutator_vtable test_mutator_vtable = { 64 test_mutator_mutate_fd, test_mutator_compare, test_mutator_destroy}; 65 66 // 67 // TestSocketMutator implementation 68 // 69 70 TestSocketMutator::TestSocketMutator() { 71 grpc_socket_mutator_init(this, &test_mutator_vtable); 72 } 73 } // namespace 74 75 class ChannelArgumentsTest : public ::testing::Test { 76 protected: 77 ChannelArgumentsTest() 78 : pointer_vtable_({&ChannelArguments::PointerVtableMembers::Copy, 79 &ChannelArguments::PointerVtableMembers::Destroy, 80 &ChannelArguments::PointerVtableMembers::Compare}) {} 81 82 void SetChannelArgs(const ChannelArguments& channel_args, 83 grpc_channel_args* args) { 84 channel_args.SetChannelArgs(args); 85 } 86 87 grpc::string GetDefaultUserAgentPrefix() { 88 std::ostringstream user_agent_prefix; 89 user_agent_prefix << "grpc-c++/" << Version(); 90 return user_agent_prefix.str(); 91 } 92 93 void VerifyDefaultChannelArgs() { 94 grpc_channel_args args; 95 SetChannelArgs(channel_args_, &args); 96 EXPECT_EQ(static_cast<size_t>(1), args.num_args); 97 EXPECT_STREQ(GRPC_ARG_PRIMARY_USER_AGENT_STRING, args.args[0].key); 98 EXPECT_EQ(GetDefaultUserAgentPrefix(), 99 grpc::string(args.args[0].value.string)); 100 } 101 102 bool HasArg(grpc_arg expected_arg) { 103 grpc_channel_args args; 104 SetChannelArgs(channel_args_, &args); 105 for (size_t i = 0; i < args.num_args; i++) { 106 const grpc_arg& arg = args.args[i]; 107 if (arg.type == expected_arg.type && 108 grpc::string(arg.key) == expected_arg.key) { 109 if (arg.type == GRPC_ARG_INTEGER) { 110 return arg.value.integer == expected_arg.value.integer; 111 } else if (arg.type == GRPC_ARG_STRING) { 112 return grpc::string(arg.value.string) == expected_arg.value.string; 113 } else if (arg.type == GRPC_ARG_POINTER) { 114 return arg.value.pointer.p == expected_arg.value.pointer.p && 115 arg.value.pointer.vtable->copy == 116 expected_arg.value.pointer.vtable->copy && 117 arg.value.pointer.vtable->destroy == 118 expected_arg.value.pointer.vtable->destroy; 119 } 120 } 121 } 122 return false; 123 } 124 grpc_arg_pointer_vtable pointer_vtable_; 125 ChannelArguments channel_args_; 126 }; 127 128 TEST_F(ChannelArgumentsTest, SetInt) { 129 VerifyDefaultChannelArgs(); 130 grpc::string key0("key0"); 131 grpc_arg arg0; 132 arg0.type = GRPC_ARG_INTEGER; 133 arg0.key = const_cast<char*>(key0.c_str()); 134 arg0.value.integer = 0; 135 grpc::string key1("key1"); 136 grpc_arg arg1; 137 arg1.type = GRPC_ARG_INTEGER; 138 arg1.key = const_cast<char*>(key1.c_str()); 139 arg1.value.integer = 1; 140 141 grpc::string arg_key0(key0); 142 channel_args_.SetInt(arg_key0, arg0.value.integer); 143 // Clear key early to make sure channel_args takes a copy 144 arg_key0.clear(); 145 EXPECT_TRUE(HasArg(arg0)); 146 147 grpc::string arg_key1(key1); 148 channel_args_.SetInt(arg_key1, arg1.value.integer); 149 arg_key1.clear(); 150 EXPECT_TRUE(HasArg(arg0)); 151 EXPECT_TRUE(HasArg(arg1)); 152 } 153 154 TEST_F(ChannelArgumentsTest, SetString) { 155 VerifyDefaultChannelArgs(); 156 grpc::string key0("key0"); 157 grpc::string val0("val0"); 158 grpc_arg arg0; 159 arg0.type = GRPC_ARG_STRING; 160 arg0.key = const_cast<char*>(key0.c_str()); 161 arg0.value.string = const_cast<char*>(val0.c_str()); 162 grpc::string key1("key1"); 163 grpc::string val1("val1"); 164 grpc_arg arg1; 165 arg1.type = GRPC_ARG_STRING; 166 arg1.key = const_cast<char*>(key1.c_str()); 167 arg1.value.string = const_cast<char*>(val1.c_str()); 168 169 grpc::string key(key0); 170 grpc::string val(val0); 171 channel_args_.SetString(key, val); 172 // Clear key/val early to make sure channel_args takes a copy 173 key = ""; 174 val = ""; 175 EXPECT_TRUE(HasArg(arg0)); 176 177 key = key1; 178 val = val1; 179 channel_args_.SetString(key, val); 180 // Clear key/val early to make sure channel_args takes a copy 181 key = ""; 182 val = ""; 183 EXPECT_TRUE(HasArg(arg0)); 184 EXPECT_TRUE(HasArg(arg1)); 185 } 186 187 TEST_F(ChannelArgumentsTest, SetPointer) { 188 VerifyDefaultChannelArgs(); 189 grpc::string key0("key0"); 190 grpc_arg arg0; 191 arg0.type = GRPC_ARG_POINTER; 192 arg0.key = const_cast<char*>(key0.c_str()); 193 arg0.value.pointer.p = &key0; 194 arg0.value.pointer.vtable = &pointer_vtable_; 195 196 grpc::string key(key0); 197 channel_args_.SetPointer(key, arg0.value.pointer.p); 198 EXPECT_TRUE(HasArg(arg0)); 199 } 200 201 TEST_F(ChannelArgumentsTest, SetSocketMutator) { 202 VerifyDefaultChannelArgs(); 203 grpc_arg arg0, arg1; 204 TestSocketMutator* mutator0 = new TestSocketMutator(); 205 TestSocketMutator* mutator1 = new TestSocketMutator(); 206 arg0 = grpc_socket_mutator_to_arg(mutator0); 207 arg1 = grpc_socket_mutator_to_arg(mutator1); 208 209 channel_args_.SetSocketMutator(mutator0); 210 EXPECT_TRUE(HasArg(arg0)); 211 212 channel_args_.SetSocketMutator(mutator1); 213 EXPECT_TRUE(HasArg(arg1)); 214 // arg0 is replaced by arg1 215 EXPECT_FALSE(HasArg(arg0)); 216 } 217 218 TEST_F(ChannelArgumentsTest, SetUserAgentPrefix) { 219 VerifyDefaultChannelArgs(); 220 grpc::string prefix("prefix"); 221 grpc::string whole_prefix = prefix + " " + GetDefaultUserAgentPrefix(); 222 grpc_arg arg0; 223 arg0.type = GRPC_ARG_STRING; 224 arg0.key = const_cast<char*>(GRPC_ARG_PRIMARY_USER_AGENT_STRING); 225 arg0.value.string = const_cast<char*>(whole_prefix.c_str()); 226 227 channel_args_.SetUserAgentPrefix(prefix); 228 EXPECT_TRUE(HasArg(arg0)); 229 230 // Test if the user agent string is copied correctly 231 ChannelArguments new_channel_args(channel_args_); 232 grpc_channel_args args; 233 SetChannelArgs(new_channel_args, &args); 234 bool found = false; 235 for (size_t i = 0; i < args.num_args; i++) { 236 const grpc_arg& arg = args.args[i]; 237 if (arg.type == GRPC_ARG_STRING && 238 grpc::string(arg.key) == GRPC_ARG_PRIMARY_USER_AGENT_STRING) { 239 EXPECT_FALSE(found); 240 EXPECT_EQ(0, strcmp(arg.value.string, arg0.value.string)); 241 found = true; 242 } 243 } 244 EXPECT_TRUE(found); 245 } 246 247 } // namespace testing 248 } // namespace grpc 249 250 int main(int argc, char** argv) { 251 ::testing::InitGoogleTest(&argc, argv); 252 grpc_init(); 253 int ret = RUN_ALL_TESTS(); 254 grpc_shutdown(); 255 return ret; 256 } 257