// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #include #include #include #include "butil/string_printf.h" #include "butil/strings/string_split.h" #include "butil/files/temp_file.h" #include "bthread/bthread.h" #include "brpc/http_status_code.h" #ifdef BAIDU_INTERNAL #include "brpc/policy/baidu_naming_service.h" #endif #include "brpc/policy/consul_naming_service.h" #include "brpc/policy/domain_naming_service.h" #include "brpc/policy/file_naming_service.h" #include "brpc/policy/list_naming_service.h" #include "brpc/policy/remote_file_naming_service.h" #include "brpc/policy/discovery_naming_service.h" #include "brpc/policy/nacos_naming_service.h" #include "echo.pb.h" #include "brpc/server.h" namespace brpc { DECLARE_int32(health_check_interval); namespace policy { DECLARE_bool(consul_enable_degrade_to_file_naming_service); DECLARE_string(consul_file_naming_service_dir); DECLARE_string(consul_service_discovery_url); DECLARE_string(discovery_api_addr); DECLARE_string(discovery_env); DECLARE_int32(discovery_renew_interval_s); DECLARE_string(nacos_address); DECLARE_string(nacos_username); DECLARE_string(nacos_password); } // policy } // brpc namespace { bool IsIPListEqual(const std::set& s1, const std::set& s2) { if (s1.size() != s2.size()) { return false; } for (auto it1 = s1.begin(), it2 = s2.begin(); it1 != s1.end(); ++it1, ++it2) { if (*it1 != *it2) { return false; } } return true; } TEST(NamingServiceTest, sanity) { std::vector servers; #ifdef BAIDU_INTERNAL brpc::policy::BaiduNamingService bns; ASSERT_EQ(0, bns.GetServers("qa-pbrpc.SAT.tjyx", &servers)); #endif brpc::policy::DomainNamingService dns; ASSERT_EQ(0, dns.GetServers("baidu.com:1234", &servers)); ASSERT_EQ(2u, servers.size()); ASSERT_EQ(1234, servers[0].addr.port); ASSERT_EQ(1234, servers[1].addr.port); const std::set expected_ips{servers[0].addr.ip, servers[1].addr.ip}; ASSERT_EQ(0, dns.GetServers("baidu.com", &servers)); ASSERT_EQ(2u, servers.size()); const std::set ip_list1{servers[0].addr.ip, servers[1].addr.ip}; ASSERT_TRUE(IsIPListEqual(expected_ips, ip_list1)); ASSERT_EQ(80, servers[0].addr.port); ASSERT_EQ(80, servers[1].addr.port); ASSERT_EQ(0, dns.GetServers("baidu.com:1234/useless1/useless2", &servers)); ASSERT_EQ(2u, servers.size()); const std::set ip_list2{servers[0].addr.ip, servers[1].addr.ip}; ASSERT_TRUE(IsIPListEqual(expected_ips, ip_list2)); ASSERT_EQ(1234, servers[0].addr.port); ASSERT_EQ(1234, servers[1].addr.port); ASSERT_EQ(0, dns.GetServers("baidu.com/useless1/useless2", &servers)); ASSERT_EQ(2u, servers.size()); const std::set ip_list3{servers[0].addr.ip, servers[1].addr.ip}; ASSERT_TRUE(IsIPListEqual(expected_ips, ip_list3)); ASSERT_EQ(80, servers[0].addr.port); ASSERT_EQ(80, servers[1].addr.port); const char *address_list[] = { "10.127.0.1:1234", "10.128.0.1:1234", "10.129.0.1:1234", "localhost:1234", "baidu.com:1234" }; butil::TempFile tmp_file; { FILE* fp = fopen(tmp_file.fname(), "w"); for (size_t i = 0; i < ARRAY_SIZE(address_list); ++i) { ASSERT_TRUE(fprintf(fp, "%s\n", address_list[i])); } fclose(fp); } brpc::policy::FileNamingService fns; ASSERT_EQ(0, fns.GetServers(tmp_file.fname(), &servers)); ASSERT_EQ(ARRAY_SIZE(address_list), servers.size()); for (size_t i = 0; i < ARRAY_SIZE(address_list) - 2; ++i) { std::ostringstream oss; oss << servers[i]; ASSERT_EQ(address_list[i], oss.str()) << "i=" << i; } std::string s; for (size_t i = 0; i < ARRAY_SIZE(address_list); ++i) { ASSERT_EQ(0, butil::string_appendf(&s, "%s,", address_list[i])); } brpc::policy::ListNamingService lns; ASSERT_EQ(0, lns.GetServers(s.c_str(), &servers)); ASSERT_EQ(ARRAY_SIZE(address_list), servers.size()); for (size_t i = 0; i < ARRAY_SIZE(address_list) - 2; ++i) { std::ostringstream oss; oss << servers[i]; ASSERT_EQ(address_list[i], oss.str()) << "i=" << i; } } TEST(NamingServiceTest, invalid_port) { std::vector servers; #ifdef BAIDU_INTERNAL brpc::policy::BaiduNamingService bns; ASSERT_EQ(0, bns.GetServers("qa-pbrpc.SAT.tjyx:main", &servers)); #endif brpc::policy::DomainNamingService dns; ASSERT_EQ(-1, dns.GetServers("baidu.com:", &servers)); ASSERT_EQ(-1, dns.GetServers("baidu.com:123a", &servers)); ASSERT_EQ(-1, dns.GetServers("baidu.com:99999", &servers)); } TEST(NamingServiceTest, wrong_name) { std::vector servers; #ifdef BAIDU_INTERNAL brpc::policy::BaiduNamingService bns; ASSERT_EQ(-1, bns.GetServers("Wrong", &servers)); #endif const char *address_list[] = { "10.127.0.1:1234", "10.128.0.1:12302344", "10.129.0.1:1234", "10.128.0.1:", "10.128.0.1", "localhost:1234", "baidu.com:1234", "LOCAL:1234" }; butil::TempFile tmp_file; { FILE *fp = fopen(tmp_file.fname(), "w"); for (size_t i = 0; i < ARRAY_SIZE(address_list); ++i) { ASSERT_TRUE(fprintf(fp, "%s\n", address_list[i])); } fclose(fp); } brpc::policy::FileNamingService fns; ASSERT_EQ(0, fns.GetServers(tmp_file.fname(), &servers)); ASSERT_EQ(ARRAY_SIZE(address_list) - 4, servers.size()); std::string s; for (size_t i = 0; i < ARRAY_SIZE(address_list); ++i) { ASSERT_EQ(0, butil::string_appendf(&s, ", %s", address_list[i])); } brpc::policy::ListNamingService lns; ASSERT_EQ(0, lns.GetServers(s.c_str(), &servers)); ASSERT_EQ(ARRAY_SIZE(address_list) - 4, servers.size()); } class UserNamingServiceImpl : public test::UserNamingService { public: UserNamingServiceImpl() : list_names_count(0), touch_count(0) {} ~UserNamingServiceImpl() { } void ListNames(google::protobuf::RpcController* cntl_base, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); brpc::Controller* cntl = (brpc::Controller*)cntl_base; cntl->http_response().set_content_type("text/plain"); cntl->response_attachment().append( "0.0.0.0:8635 tag1\r\n0.0.0.0:8636 tag2\n" "0.0.0.0:8635 tag3\r\n0.0.0.0:8636\r\n"); list_names_count.fetch_add(1); } void Touch(google::protobuf::RpcController*, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); touch_count.fetch_add(1); } butil::atomic list_names_count; butil::atomic touch_count; }; TEST(NamingServiceTest, remotefile) { brpc::Server server1; UserNamingServiceImpl svc1; ASSERT_EQ(0, server1.AddService(&svc1, brpc::SERVER_DOESNT_OWN_SERVICE)); ASSERT_EQ(0, server1.Start("localhost:8635", NULL)); brpc::Server server2; UserNamingServiceImpl svc2; ASSERT_EQ(0, server2.AddService(&svc2, brpc::SERVER_DOESNT_OWN_SERVICE)); ASSERT_EQ(0, server2.Start("localhost:8636", NULL)); butil::EndPoint n1; ASSERT_EQ(0, butil::str2endpoint("0.0.0.0:8635", &n1)); butil::EndPoint n2; ASSERT_EQ(0, butil::str2endpoint("0.0.0.0:8636", &n2)); std::vector expected_servers; expected_servers.push_back(brpc::ServerNode(n1, "tag1")); expected_servers.push_back(brpc::ServerNode(n2, "tag2")); expected_servers.push_back(brpc::ServerNode(n1, "tag3")); expected_servers.push_back(brpc::ServerNode(n2)); std::sort(expected_servers.begin(), expected_servers.end()); std::vector servers; brpc::policy::RemoteFileNamingService rfns; ASSERT_EQ(0, rfns.GetServers("0.0.0.0:8635/UserNamingService/ListNames", &servers)); ASSERT_EQ(expected_servers.size(), servers.size()); std::sort(servers.begin(), servers.end()); for (size_t i = 0; i < expected_servers.size(); ++i) { ASSERT_EQ(expected_servers[i], servers[i]); } ASSERT_EQ(0, rfns.GetServers("http://0.0.0.0:8635/UserNamingService/ListNames", &servers)); ASSERT_EQ(expected_servers.size(), servers.size()); std::sort(servers.begin(), servers.end()); for (size_t i = 0; i < expected_servers.size(); ++i) { ASSERT_EQ(expected_servers[i], servers[i]); } } class ConsulNamingServiceImpl : public test::UserNamingService { public: ConsulNamingServiceImpl() : list_names_count(0), touch_count(0) { } ~ConsulNamingServiceImpl() { } void ListNames(google::protobuf::RpcController* cntl_base, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); brpc::Controller* cntl = (brpc::Controller*)cntl_base; cntl->http_response().SetHeader("X-Consul-Index", "1"); cntl->response_attachment().append( R"([ { "Node": { "ID": "44454c4c-4e00-1050-8052-b7c04f4b5931", "Node": "sh-qs-10.121.36.189", "Address": "10.121.36.189", "Datacenter": "shjj", "TaggedAddresses": { "lan": "10.121.36.189", "wan": "10.121.36.189" }, "Meta": { "consul-network-segment": "" }, "CreateIndex": 4820296, "ModifyIndex": 4823818 }, "Service": { "ID": "10.121.36.189_8003_qs_show_leaf", "Service": "qs_show_leaf", "Tags": ["1"], "Address": "10.121.36.189", "Port": 8003, "EnableTagOverride": false, "CreateIndex": 6515285, "ModifyIndex": 6515285 }, "Checks": [ { "Node": "sh-qs-10.121.36.189", "CheckID": "serfHealth", "Name": "Serf Health Status", "Status": "passing", "Notes": "", "Output": "Agent alive and reachable", "ServiceID": "", "ServiceName": "", "ServiceTags": [ ], "CreateIndex": 4820296, "ModifyIndex": 4820296 }, { "Node": "sh-qs-10.121.36.189", "CheckID": "service:10.121.36.189_8003_qs_show_leaf", "Name": "Service 'qs_show_leaf' check", "Status": "passing", "Notes": "", "Output": "TCP connect 10.121.36.189:8003: Success", "ServiceID": "10.121.36.189_8003_qs_show_leaf", "ServiceName": "qs_show_leaf", "ServiceTags": [ ], "CreateIndex": 6515285, "ModifyIndex": 6702198 } ] }, { "Node": { "ID": "44454c4c-4b00-1050-8052-b6c04f4b5931", "Node": "sh-qs-10.121.36.190", "Address": "10.121.36.190", "Datacenter": "shjj", "TaggedAddresses": { "lan": "10.121.36.190", "wan": "10.121.36.190" }, "Meta": { "consul-network-segment": "" }, "CreateIndex": 4820296, "ModifyIndex": 4823751 }, "Service": { "ID": "10.121.36.190_8003_qs_show_leaf", "Service": "qs_show_leaf", "Tags": ["2"], "Address": "10.121.36.190", "Port": 8003, "EnableTagOverride": false, "CreateIndex": 6515635, "ModifyIndex": 6515635 }, "Checks": [ { "Node": "sh-qs-10.121.36.190", "CheckID": "serfHealth", "Name": "Serf Health Status", "Status": "passing", "Notes": "", "Output": "Agent alive and reachable", "ServiceID": "", "ServiceName": "", "ServiceTags": [ ], "CreateIndex": 4820296, "ModifyIndex": 4820296 }, { "Node": "sh-qs-10.121.36.190", "CheckID": "service:10.121.36.190_8003_qs_show_leaf", "Name": "Service 'qs_show_leaf' check", "Status": "passing", "Notes": "", "Output": "TCP connect 10.121.36.190:8003: Success", "ServiceID": "10.121.36.190_8003_qs_show_leaf", "ServiceName": "qs_show_leaf", "ServiceTags": [ ], "CreateIndex": 6515635, "ModifyIndex": 6705515 } ] } ])"); list_names_count.fetch_add(1); } void Touch(google::protobuf::RpcController*, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); touch_count.fetch_add(1); } butil::atomic list_names_count; butil::atomic touch_count; }; TEST(NamingServiceTest, consul_with_backup_file) { brpc::policy::FLAGS_consul_enable_degrade_to_file_naming_service = true; const int saved_hc_interval = brpc::FLAGS_health_check_interval; brpc::FLAGS_health_check_interval = 1; const char *address_list[] = { "10.127.0.1:1234", "10.128.0.1:1234", "10.129.0.1:1234", }; butil::TempFile tmp_file; const char * service_name = tmp_file.fname(); { FILE* fp = fopen(tmp_file.fname(), "w"); for (size_t i = 0; i < ARRAY_SIZE(address_list); ++i) { ASSERT_TRUE(fprintf(fp, "%s\n", address_list[i])); } fclose(fp); } std::cout << tmp_file.fname() << std::endl; std::vector servers; brpc::policy::ConsulNamingService cns; ASSERT_EQ(0, cns.GetServers(service_name, &servers)); ASSERT_EQ(ARRAY_SIZE(address_list), servers.size()); for (size_t i = 0; i < ARRAY_SIZE(address_list); ++i) { std::ostringstream oss; oss << servers[i]; ASSERT_EQ(address_list[i], oss.str()) << "i=" << i; } brpc::Server server; ConsulNamingServiceImpl svc; std::string restful_map(brpc::policy::FLAGS_consul_service_discovery_url); restful_map.append("/"); restful_map.append(service_name); restful_map.append(" => ListNames"); ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE, restful_map.c_str())); ASSERT_EQ(0, server.Start("localhost:8500", NULL)); bthread_usleep(5000000); butil::EndPoint n1; ASSERT_EQ(0, butil::str2endpoint("10.121.36.189:8003", &n1)); butil::EndPoint n2; ASSERT_EQ(0, butil::str2endpoint("10.121.36.190:8003", &n2)); std::vector expected_servers; expected_servers.push_back(brpc::ServerNode(n1, "1")); expected_servers.push_back(brpc::ServerNode(n2, "2")); std::sort(expected_servers.begin(), expected_servers.end()); servers.clear(); ASSERT_EQ(0, cns.GetServers(service_name, &servers)); ASSERT_EQ(expected_servers.size(), servers.size()); std::sort(servers.begin(), servers.end()); for (size_t i = 0; i < expected_servers.size(); ++i) { ASSERT_EQ(expected_servers[i], servers[i]); } brpc::FLAGS_health_check_interval = saved_hc_interval; } static const std::string s_fetchs_result = R"({ "code":0, "message":"0", "ttl":1, "data":{ "admin.test":{ "instances":[ { "region":"", "zone":"sh001", "env":"uat", "appid":"admin.test", "treeid":0, "hostname":"host123", "http":"", "rpc":"", "version":"123", "metadata":{ "weight": "10", "cluster": "" }, "addrs":[ "http://127.0.0.1:8999", "grpc://127.0.1.1:9000" ], "status":1, "reg_timestamp":1539001034551496412, "up_timestamp":1539001034551496412, "renew_timestamp":1539001034551496412, "dirty_timestamp":1539001034551496412, "latest_timestamp":1539001034551496412 } ], "zone_instances":{ "sh001":[ { "region":"", "zone":"sh001", "env":"uat", "appid":"admin.test", "treeid":0, "hostname":"host123", "http":"", "rpc":"", "version":"123", "metadata":{ "weight": "10", "cluster": "" }, "addrs":[ "http://127.0.0.1:8999", "grpc://127.0.1.1:9000" ], "status":1, "reg_timestamp":1539001034551496412, "up_timestamp":1539001034551496412, "renew_timestamp":1539001034551496412, "dirty_timestamp":1539001034551496412, "latest_timestamp":1539001034551496412 } ] }, "latest_timestamp":1539001034551496412, "latest_timestamp_str":"1539001034" } } })"; static std::string s_nodes_result = R"({ "code": 0, "message": "0", "ttl": 1, "data": [ { "addr": "127.0.0.1:8635", "status": 0, "zone": "" }, { "addr": "172.18.33.51:7171", "status": 0, "zone": "" }, { "addr": "172.18.33.52:7171", "status": 0, "zone": "" } ] })"; class DiscoveryNamingServiceImpl : public test::DiscoveryNamingService { public: DiscoveryNamingServiceImpl() : _renew_count(0) , _cancel_count(0) {} virtual ~DiscoveryNamingServiceImpl() {} void Nodes(google::protobuf::RpcController* cntl_base, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); brpc::Controller* cntl = static_cast(cntl_base); cntl->response_attachment().append(s_nodes_result); } void Fetchs(google::protobuf::RpcController* cntl_base, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); brpc::Controller* cntl = static_cast(cntl_base); cntl->response_attachment().append(s_fetchs_result); } void Register(google::protobuf::RpcController* cntl_base, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); brpc::Controller* cntl = static_cast(cntl_base); auto body = cntl->request_attachment().to_string(); for (brpc::QuerySplitter sp(body); sp; ++sp) { if (sp.key() == "addrs") { _addrs.insert(sp.value().as_string()); } } cntl->response_attachment().append(R"({ "code": 0, "message": "0" })"); return; } void Renew(google::protobuf::RpcController* cntl_base, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); brpc::Controller* cntl = static_cast(cntl_base); cntl->response_attachment().append(R"({ "code": 0, "message": "0" })"); _renew_count++; return; } void Cancel(google::protobuf::RpcController* cntl_base, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); brpc::Controller* cntl = static_cast(cntl_base); cntl->response_attachment().append(R"({ "code": 0, "message": "0" })"); _cancel_count++; _addrs.clear(); return; } int RenewCount() const { return _renew_count; } int CancelCount() const { return _cancel_count; } bool HasAddr(const std::string& addr) const { return _addrs.find(addr) != _addrs.end(); } int AddrCount() const { return _addrs.size(); } private: int _renew_count; int _cancel_count; std::set _addrs; }; TEST(NamingServiceTest, discovery_sanity) { brpc::policy::FLAGS_discovery_api_addr = "http://127.0.0.1:8635/discovery/nodes"; brpc::policy::FLAGS_discovery_renew_interval_s = 1; brpc::Server server; DiscoveryNamingServiceImpl svc; std::string rest_mapping = "/discovery/nodes => Nodes, " "/discovery/fetchs => Fetchs, " "/discovery/register => Register, " "/discovery/renew => Renew, " "/discovery/cancel => Cancel"; ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE, rest_mapping.c_str())); ASSERT_EQ(0, server.Start("localhost:8635", NULL)); brpc::policy::DiscoveryNamingService dcns; std::vector servers; ASSERT_EQ(0, dcns.GetServers("admin.test", &servers)); ASSERT_EQ((size_t)1, servers.size()); brpc::policy::DiscoveryRegisterParam dparam; dparam.appid = "main.test"; dparam.hostname = "hostname"; dparam.addrs = "grpc://10.0.0.1:8000"; dparam.env = "dev"; dparam.zone = "sh001"; dparam.status = 1; dparam.version = "v1"; { brpc::policy::DiscoveryClient dc; } // Cancel is called iff Register is called ASSERT_EQ(svc.CancelCount(), 0); { brpc::policy::DiscoveryClient dc; // Two Register should start one Renew task , and make // svc.RenewCount() be one. ASSERT_EQ(0, dc.Register(dparam)); ASSERT_EQ(0, dc.Register(dparam)); bthread_usleep(100000); ASSERT_TRUE(svc.HasAddr("grpc://10.0.0.1:8000")); ASSERT_FALSE(svc.HasAddr("http://10.0.0.1:8000")); } ASSERT_EQ(svc.RenewCount(), 1); ASSERT_EQ(svc.CancelCount(), 1); ASSERT_FALSE(svc.HasAddr("grpc://10.0.0.1:8000")); ASSERT_FALSE(svc.HasAddr("http://10.0.0.1:8000")); // addrs splitted by `,' dparam.addrs = ",grpc://10.0.0.1:8000,,http://10.0.0.1:8000,"; { brpc::policy::DiscoveryClient dc; ASSERT_EQ(0, dc.Register(dparam)); ASSERT_TRUE(svc.HasAddr("grpc://10.0.0.1:8000")); ASSERT_TRUE(svc.HasAddr("http://10.0.0.1:8000")); ASSERT_FALSE(svc.HasAddr(std::string())); ASSERT_EQ(2, svc.AddrCount()); } } class NacosNamingServiceImpl : public test::NacosNamingService { public: void Login(google::protobuf::RpcController* cntl_base, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) override { brpc::ClosureGuard done_guard(done); brpc::Controller* cntl = static_cast(cntl_base); butil::StringPairs user; butil::SplitStringIntoKeyValuePairs( cntl->request_attachment().to_string(), '=', '&', &user); const auto expected_user = butil::StringPairs{{"username", "nacos"}, {"password", "nacos"}}; if (user == expected_user) { cntl->http_response().set_content_type("application/json"); cntl->response_attachment().append( R"({ "accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY2MzAwODMzNn0.YKJJwzHT4v9cpC7kVqWroeJK1WioOYe0JZy4KX8nExs", "tokenTtl": 18000, "globalAdmin": true, "username": "nacos" })"); } else { cntl->http_response().set_status_code(brpc::HTTP_STATUS_FORBIDDEN); cntl->response_attachment().append("unknow user!"); } } void List(google::protobuf::RpcController* cntl_base, const test::HttpRequest*, test::HttpResponse*, google::protobuf::Closure* done) override { brpc::ClosureGuard done_guard(done); brpc::Controller* cntl = (brpc::Controller*)cntl_base; auto token = cntl->http_request().uri().GetQuery("accessToken"); if (token == nullptr || *token != "eyJhbGciOiJIUzI1NiJ9." "eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY2MzAwODMzNn0." "YKJJwzHT4v9cpC7kVqWroeJK1WioOYe0JZy4KX8nExs") { cntl->http_response().set_status_code(brpc::HTTP_STATUS_FORBIDDEN); cntl->response_attachment().append( R"({ "timestamp": "2022-09-12T22:56:02.730+08:00", "status": 403, "error": "Forbidden", "path": "/nacos/v1/ns/instance/list" })"); return; } auto service_name = cntl->http_request().uri().GetQuery("serviceName"); auto group_name = cntl->http_request().uri().GetQuery("groupName"); auto namespace_id = cntl->http_request().uri().GetQuery("namespaceId"); auto clusters = cntl->http_request().uri().GetQuery("clusters"); if (service_name == nullptr || *service_name != "test" || group_name == nullptr || *group_name != "g1" || namespace_id == nullptr || *namespace_id != "n1" || clusters == nullptr || *clusters != "wx") { cntl->http_response().set_status_code(brpc::HTTP_STATUS_NOT_FOUND); return; } cntl->http_response().set_content_type("application/json"); cntl->response_attachment().append( R"({ "name": "g1@@test", "groupName": "g1", "clusters": "wx", "cacheMillis": 10000, "hosts": [ { "instanceId": "127.0.0.1#8888#wx#g1@@test", "ip": "127.0.0.1", "port": 8888, "weight": 10.0, "healthy": true, "enabled": true, "ephemeral": true, "clusterName": "wx", "serviceName": "g1@@test", "metadata": {}, "instanceHeartBeatInterval": 5000, "instanceHeartBeatTimeOut": 15000, "ipDeleteTimeout": 30000, "instanceIdGenerator": "simple" } ], "lastRefTime": 1662990336712, "checksum": "", "allIPs": false, "reachProtectionThreshold": false, "valid": true })"); } }; TEST(NamingServiceTest, nacos) { brpc::Server server; NacosNamingServiceImpl svc; ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE, "/nacos/v1/auth/login => Login, " "/nacos/v1/ns/instance/list => List")); ASSERT_EQ(0, server.Start("localhost:8848", nullptr)); bthread_usleep(5000000); butil::EndPoint ep; ASSERT_EQ(0, butil::str2endpoint("127.0.0.1:8888", &ep)); const auto expected_node = brpc::ServerNode(ep, "10"); const char* service_name = "serviceName=test&groupName=g1&namespaceId=n1&clusters=wx"; brpc::policy::FLAGS_nacos_address = "http://localhost:8848"; brpc::policy::FLAGS_nacos_username = "nacos"; brpc::policy::FLAGS_nacos_password = "nacos"; { brpc::policy::NacosNamingService nns; std::vector nodes; ASSERT_EQ(0, nns.GetServers(service_name, &nodes)); ASSERT_EQ(nodes.size(), 1); ASSERT_EQ(expected_node, nodes[0]); } { brpc::policy::FLAGS_nacos_password = "invalid_password"; brpc::policy::NacosNamingService nns; std::vector nodes; ASSERT_NE(0, nns.GetServers(service_name, &nodes)); } } } //namespace