| // 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. |
| |
| // brpc - A framework to host and access services throughout Baidu. |
| |
| // Date: Sun Jul 13 15:04:18 CST 2014 |
| |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <fstream> |
| #include <gtest/gtest.h> |
| #include <gflags/gflags.h> |
| #include <google/protobuf/descriptor.h> |
| #include "butil/gperftools_profiler.h" |
| #include "butil/time.h" |
| #include "butil/macros.h" |
| #include "brpc/socket.h" |
| #include "brpc/server.h" |
| #include "brpc/channel.h" |
| #include "brpc/controller.h" |
| #include "brpc/span.h" |
| #include "brpc/reloadable_flags.h" |
| #include "brpc/builtin/version_service.h" |
| #include "brpc/builtin/health_service.h" |
| #include "brpc/builtin/list_service.h" |
| #include "brpc/builtin/status_service.h" |
| #include "brpc/builtin/threads_service.h" |
| #include "brpc/builtin/vlog_service.h" |
| #include "brpc/builtin/index_service.h" // IndexService |
| #include "brpc/builtin/connections_service.h" // ConnectionsService |
| #include "brpc/builtin/flags_service.h" // FlagsService |
| #include "brpc/builtin/vars_service.h" // VarsService |
| #include "brpc/builtin/rpcz_service.h" // RpczService |
| #include "brpc/builtin/dir_service.h" // DirService |
| #include "brpc/builtin/pprof_service.h" // PProfService |
| #include "brpc/builtin/bthreads_service.h" // BthreadsService |
| #include "brpc/builtin/ids_service.h" // IdsService |
| #include "brpc/builtin/sockets_service.h" // SocketsService |
| #include "brpc/builtin/memory_service.h" |
| #include "brpc/builtin/common.h" |
| #include "brpc/builtin/bad_method_service.h" |
| #include "echo.pb.h" |
| #include "brpc/grpc_health_check.pb.h" |
| #include "json2pb/pb_to_json.h" |
| |
| DEFINE_bool(foo, false, "Flags for UT"); |
| BRPC_VALIDATE_GFLAG(foo, brpc::PassValidate); |
| |
| namespace brpc { |
| DECLARE_bool(enable_rpcz); |
| DECLARE_bool(rpcz_hex_log_id); |
| DECLARE_int32(idle_timeout_second); |
| } // namespace rpc |
| |
| int main(int argc, char* argv[]) { |
| brpc::FLAGS_idle_timeout_second = 0; |
| testing::InitGoogleTest(&argc, argv); |
| return RUN_ALL_TESTS(); |
| } |
| |
| class EchoServiceImpl : public test::EchoService { |
| public: |
| EchoServiceImpl() {} |
| virtual ~EchoServiceImpl() {} |
| virtual void Echo(google::protobuf::RpcController* cntl_base, |
| const test::EchoRequest* req, |
| test::EchoResponse* res, |
| google::protobuf::Closure* done) { |
| brpc::Controller* cntl = |
| static_cast<brpc::Controller*>(cntl_base); |
| brpc::ClosureGuard done_guard(done); |
| TRACEPRINTF("MyAnnotation: %ld", cntl->log_id()); |
| if (req->sleep_us() > 0) { |
| bthread_usleep(req->sleep_us()); |
| } |
| char buf[32]; |
| snprintf(buf, sizeof(buf), "%" PRIu64, cntl->trace_id()); |
| res->set_message(buf); |
| } |
| }; |
| |
| class ClosureChecker : public google::protobuf::Closure { |
| public: |
| ClosureChecker() : _count(1) {} |
| ~ClosureChecker() { EXPECT_EQ(0, _count); } |
| |
| void Run() { |
| --_count; |
| } |
| |
| private: |
| int _count; |
| }; |
| |
| void MyVLogSite() { |
| VLOG(3) << "This is a VLOG!"; |
| } |
| |
| void CheckContent(const brpc::Controller& cntl, const char* name) { |
| const std::string& content = cntl.response_attachment().to_string(); |
| std::size_t pos = content.find(name); |
| ASSERT_TRUE(pos != std::string::npos) << "name=" << name; |
| } |
| |
| void CheckErrorText(const brpc::Controller& cntl, const char* error) { |
| std::size_t pos = cntl.ErrorText().find(error); |
| ASSERT_TRUE(pos != std::string::npos) << "error=" << error; |
| } |
| |
| void CheckFieldInContent(const brpc::Controller& cntl, |
| const char* name, int32_t expect) { |
| const std::string& content = cntl.response_attachment().to_string(); |
| std::size_t pos = content.find(name); |
| ASSERT_TRUE(pos != std::string::npos); |
| |
| int32_t val = 0; |
| ASSERT_EQ(1, sscanf(content.c_str() + pos + strlen(name), "%d", &val)); |
| ASSERT_EQ(expect, val) << "name=" << name; |
| } |
| |
| void CheckAnnotation(const brpc::Controller& cntl, int64_t expect) { |
| const std::string& content = cntl.response_attachment().to_string(); |
| std::string expect_str; |
| butil::string_printf(&expect_str, "MyAnnotation: %" PRId64, expect); |
| std::size_t pos = content.find(expect_str); |
| ASSERT_TRUE(pos != std::string::npos) << expect; |
| } |
| |
| void CheckTraceId(const brpc::Controller& cntl, |
| const std::string& expect_id_str) { |
| const std::string& content = cntl.response_attachment().to_string(); |
| std::string expect_str = std::string(brpc::TRACE_ID_STR) + "=" + expect_id_str; |
| std::size_t pos = content.find(expect_str); |
| ASSERT_TRUE(pos != std::string::npos) << expect_str; |
| } |
| |
| class BuiltinServiceTest : public ::testing::Test{ |
| protected: |
| BuiltinServiceTest(){}; |
| virtual ~BuiltinServiceTest(){}; |
| virtual void SetUp() { EXPECT_EQ(0, _server.AddBuiltinServices()); } |
| virtual void TearDown() { StopAndJoin(); } |
| |
| void StopAndJoin() { |
| _server.Stop(0); |
| _server.Join(); |
| _server.ClearServices(); |
| } |
| |
| void SetUpController(brpc::Controller* cntl, bool use_html) const { |
| cntl->_server = &_server; |
| if (use_html) { |
| cntl->http_request().SetHeader( |
| brpc::USER_AGENT_STR, "just keep user agent non-empty"); |
| } |
| } |
| |
| void TestIndex(bool use_html) { |
| std::string expect_type = (use_html ? "text/html" : "text/plain"); |
| brpc::IndexService service; |
| brpc::IndexRequest req; |
| brpc::IndexResponse res; |
| brpc::Controller cntl; |
| ClosureChecker done; |
| SetUpController(&cntl, use_html); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| } |
| |
| void TestStatus(bool use_html) { |
| std::string expect_type = (use_html ? "text/html" : "text/plain"); |
| brpc::StatusService service; |
| brpc::StatusRequest req; |
| brpc::StatusResponse res; |
| brpc::Controller cntl; |
| ClosureChecker done; |
| SetUpController(&cntl, use_html); |
| EchoServiceImpl echo_svc; |
| ASSERT_EQ(0, _server.AddService( |
| &echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE)); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| ASSERT_EQ(0, _server.RemoveService(&echo_svc)); |
| } |
| |
| void TestVLog(bool use_html) { |
| #if !BRPC_WITH_GLOG |
| std::string expect_type = (use_html ? "text/html" : "text/plain"); |
| brpc::VLogService service; |
| brpc::VLogRequest req; |
| brpc::VLogResponse res; |
| brpc::Controller cntl; |
| ClosureChecker done; |
| SetUpController(&cntl, use_html); |
| MyVLogSite(); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| CheckContent(cntl, "brpc_builtin_service_unittest"); |
| #endif |
| } |
| |
| void TestConnections(bool use_html) { |
| std::string expect_type = (use_html ? "text/html" : "text/plain"); |
| brpc::ConnectionsService service; |
| brpc::ConnectionsRequest req; |
| brpc::ConnectionsResponse res; |
| brpc::Controller cntl; |
| ClosureChecker done; |
| SetUpController(&cntl, use_html); |
| butil::EndPoint ep; |
| ASSERT_EQ(0, str2endpoint("127.0.0.1:9798", &ep)); |
| ASSERT_EQ(0, _server.Start(ep, NULL)); |
| int self_port = -1; |
| const int cfd = tcp_connect(ep, &self_port); |
| ASSERT_GT(cfd, 0); |
| char buf[64]; |
| snprintf(buf, sizeof(buf), "127.0.0.1:%d", self_port); |
| usleep(100000); |
| |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| CheckContent(cntl, buf); |
| CheckFieldInContent(cntl, "channel_connection_count: ", 0); |
| |
| close(cfd); |
| StopAndJoin(); |
| } |
| |
| void TestBadMethod(bool use_html) { |
| std::string expect_type = (use_html ? "text/html" : "text/plain"); |
| brpc::BadMethodService service; |
| brpc::BadMethodResponse res; |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| brpc::BadMethodRequest req; |
| req.set_service_name( |
| brpc::PProfService::descriptor()->full_name()); |
| service.no_method(&cntl, &req, &res, &done); |
| EXPECT_EQ(brpc::ENOMETHOD, cntl.ErrorCode()); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| CheckErrorText(cntl, "growth"); |
| } |
| } |
| |
| void TestFlags(bool use_html) { |
| std::string expect_type = (use_html ? "text/html" : "text/plain"); |
| brpc::FlagsService service; |
| brpc::FlagsRequest req; |
| brpc::FlagsResponse res; |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| CheckContent(cntl, "bthread_concurrency"); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| cntl.http_request()._unresolved_path = "foo"; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| CheckContent(cntl, "false"); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| cntl.http_request()._unresolved_path = "foo"; |
| cntl.http_request().uri() |
| .SetQuery(brpc::SETVALUE_STR, "true"); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| cntl.http_request()._unresolved_path = "foo"; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| CheckContent(cntl, "true"); |
| } |
| } |
| |
| void TestRpcz(bool enable, bool hex, bool use_html) { |
| std::string expect_type = (use_html ? "text/html" : "text/plain"); |
| brpc::RpczService service; |
| brpc::RpczRequest req; |
| brpc::RpczResponse res; |
| if (!enable) { |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| service.disable(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_FALSE(brpc::FLAGS_enable_rpcz); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(expect_type, |
| cntl.http_response().content_type()); |
| if (!use_html) { |
| CheckContent(cntl, "rpcz is not enabled"); |
| } |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| service.stats(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| if (!use_html) { |
| CheckContent(cntl, "rpcz is not enabled"); |
| } |
| } |
| return; |
| } |
| |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| service.enable(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| EXPECT_TRUE(brpc::FLAGS_enable_rpcz); |
| } |
| |
| if (hex) { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| service.hex_log_id(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_TRUE(brpc::FLAGS_rpcz_hex_log_id); |
| } else { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| service.dec_log_id(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_FALSE(brpc::FLAGS_rpcz_hex_log_id); |
| } |
| |
| ASSERT_EQ(0, _server.AddService(new EchoServiceImpl(), |
| brpc::SERVER_OWNS_SERVICE)); |
| butil::EndPoint ep; |
| ASSERT_EQ(0, str2endpoint("127.0.0.1:9748", &ep)); |
| ASSERT_EQ(0, _server.Start(ep, NULL)); |
| brpc::Channel channel; |
| ASSERT_EQ(0, channel.Init(ep, NULL)); |
| test::EchoService_Stub stub(&channel); |
| int64_t log_id = 1234567890; |
| char querystr_buf[128]; |
| // Since LevelDB is unstable on jerkins, disable all the assertions here |
| { |
| // Find by trace_id |
| test::EchoRequest echo_req; |
| test::EchoResponse echo_res; |
| brpc::Controller echo_cntl; |
| echo_req.set_message("hello"); |
| echo_cntl.set_log_id(++log_id); |
| stub.Echo(&echo_cntl, &echo_req, &echo_res, NULL); |
| EXPECT_FALSE(echo_cntl.Failed()); |
| |
| // Wait for level db to commit span information |
| usleep(500000); |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| cntl.http_request().uri() |
| .SetQuery(brpc::TRACE_ID_STR, echo_res.message()); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()) << cntl.ErrorText(); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| // CheckAnnotation(cntl, log_id); |
| } |
| |
| { |
| // Find by latency |
| test::EchoRequest echo_req; |
| test::EchoResponse echo_res; |
| brpc::Controller echo_cntl; |
| echo_req.set_message("hello"); |
| echo_req.set_sleep_us(150000); |
| echo_cntl.set_log_id(++log_id); |
| stub.Echo(&echo_cntl, &echo_req, &echo_res, NULL); |
| EXPECT_FALSE(echo_cntl.Failed()); |
| |
| // Wait for level db to commit span information |
| usleep(500000); |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| cntl.http_request().uri() |
| .SetQuery(brpc::MIN_LATENCY_STR, "100000"); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()) << cntl.ErrorText(); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| // CheckTraceId(cntl, echo_res.message()); |
| } |
| |
| { |
| // Find by request size |
| test::EchoRequest echo_req; |
| test::EchoResponse echo_res; |
| brpc::Controller echo_cntl; |
| std::string request_str(1500, 'a'); |
| echo_req.set_message(request_str); |
| echo_cntl.set_log_id(++log_id); |
| stub.Echo(&echo_cntl, &echo_req, &echo_res, NULL); |
| EXPECT_FALSE(echo_cntl.Failed()); |
| |
| // Wait for level db to commit span information |
| usleep(500000); |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| cntl.http_request().uri() |
| .SetQuery(brpc::MIN_REQUEST_SIZE_STR, "1024"); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()) << cntl.ErrorText(); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| // CheckTraceId(cntl, echo_res.message()); |
| } |
| |
| { |
| // Find by log id |
| test::EchoRequest echo_req; |
| test::EchoResponse echo_res; |
| brpc::Controller echo_cntl; |
| echo_req.set_message("hello"); |
| echo_cntl.set_log_id(++log_id); |
| stub.Echo(&echo_cntl, &echo_req, &echo_res, NULL); |
| EXPECT_FALSE(echo_cntl.Failed()); |
| |
| // Wait for level db to commit span information |
| usleep(500000); |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| snprintf(querystr_buf, sizeof(querystr_buf), "%" PRId64, log_id); |
| cntl.http_request().uri() |
| .SetQuery(brpc::LOG_ID_STR, querystr_buf); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()) << cntl.ErrorText(); |
| EXPECT_EQ(expect_type, cntl.http_response().content_type()); |
| // CheckTraceId(cntl, echo_res.message()); |
| } |
| |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, use_html); |
| service.stats(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| // CheckContent(cntl, "rpcz.id_db"); |
| // CheckContent(cntl, "rpcz.time_db"); |
| } |
| |
| StopAndJoin(); |
| } |
| |
| private: |
| brpc::Server _server; |
| }; |
| |
| TEST_F(BuiltinServiceTest, index) { |
| TestIndex(false); |
| TestIndex(true); |
| } |
| |
| TEST_F(BuiltinServiceTest, version) { |
| const std::string VERSION = "test_version"; |
| brpc::VersionService service(&_server); |
| brpc::VersionRequest req; |
| brpc::VersionResponse res; |
| brpc::Controller cntl; |
| ClosureChecker done; |
| _server.set_version(VERSION); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(VERSION, cntl.response_attachment().to_string()); |
| } |
| |
| TEST_F(BuiltinServiceTest, health) { |
| const std::string HEALTH_STR = "OK"; |
| brpc::HealthService service; |
| brpc::HealthRequest req; |
| brpc::HealthResponse res; |
| brpc::Controller cntl; |
| SetUpController(&cntl, false); |
| ClosureChecker done; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| EXPECT_EQ(HEALTH_STR, cntl.response_attachment().to_string()); |
| } |
| |
| class MyHealthReporter : public brpc::HealthReporter { |
| public: |
| void GenerateReport(brpc::Controller* cntl, |
| google::protobuf::Closure* done) { |
| cntl->response_attachment().append("i'm ok"); |
| done->Run(); |
| } |
| }; |
| |
| TEST_F(BuiltinServiceTest, customized_health) { |
| brpc::ServerOptions opt; |
| MyHealthReporter hr; |
| opt.health_reporter = &hr; |
| ASSERT_EQ(0, _server.Start(9798, &opt)); |
| brpc::HealthRequest req; |
| brpc::HealthResponse res; |
| brpc::ChannelOptions copt; |
| copt.protocol = brpc::PROTOCOL_HTTP; |
| brpc::Channel chan; |
| ASSERT_EQ(0, chan.Init("127.0.0.1:9798", &copt)); |
| brpc::Controller cntl; |
| cntl.http_request().uri() = "/health"; |
| chan.CallMethod(NULL, &cntl, &req, &res, NULL); |
| EXPECT_FALSE(cntl.Failed()) << cntl.ErrorText(); |
| EXPECT_EQ("i'm ok", cntl.response_attachment()); |
| } |
| |
| class MyGrpcHealthReporter : public brpc::HealthReporter { |
| public: |
| void GenerateReport(brpc::Controller* cntl, |
| google::protobuf::Closure* done) { |
| grpc::health::v1::HealthCheckResponse response; |
| response.set_status(grpc::health::v1::HealthCheckResponse_ServingStatus_UNKNOWN); |
| |
| if (cntl->response()) { |
| cntl->response()->CopyFrom(response); |
| } else { |
| std::string json; |
| json2pb::ProtoMessageToJson(response, &json); |
| cntl->http_response().set_content_type("application/json"); |
| cntl->response_attachment().append(json); |
| } |
| done->Run(); |
| } |
| }; |
| |
| TEST_F(BuiltinServiceTest, normal_grpc_health) { |
| brpc::ServerOptions opt; |
| ASSERT_EQ(0, _server.Start(9798, &opt)); |
| |
| grpc::health::v1::HealthCheckResponse response; |
| grpc::health::v1::HealthCheckRequest request; |
| request.set_service("grpc_req_from_brpc"); |
| brpc::Controller cntl; |
| brpc::ChannelOptions copt; |
| copt.protocol = "h2:grpc"; |
| brpc::Channel chan; |
| ASSERT_EQ(0, chan.Init("127.0.0.1:9798", &copt)); |
| grpc::health::v1::Health_Stub stub(&chan); |
| stub.Check(&cntl, &request, &response, NULL); |
| EXPECT_FALSE(cntl.Failed()) << cntl.ErrorText(); |
| EXPECT_EQ(response.status(), grpc::health::v1::HealthCheckResponse_ServingStatus_SERVING); |
| |
| response.Clear(); |
| brpc::Controller cntl1; |
| cntl1.http_request().uri() = "/grpc.health.v1.Health/Check"; |
| chan.CallMethod(NULL, &cntl1, &request, &response, NULL); |
| EXPECT_FALSE(cntl.Failed()) << cntl.ErrorText(); |
| EXPECT_EQ(response.status(), grpc::health::v1::HealthCheckResponse_ServingStatus_SERVING); |
| } |
| |
| TEST_F(BuiltinServiceTest, customized_grpc_health) { |
| brpc::ServerOptions opt; |
| MyGrpcHealthReporter hr; |
| opt.health_reporter = &hr; |
| ASSERT_EQ(0, _server.Start(9798, &opt)); |
| |
| grpc::health::v1::HealthCheckResponse response; |
| grpc::health::v1::HealthCheckRequest request; |
| request.set_service("grpc_req_from_brpc"); |
| brpc::Controller cntl; |
| |
| brpc::ChannelOptions copt; |
| copt.protocol = "h2:grpc"; |
| brpc::Channel chan; |
| ASSERT_EQ(0, chan.Init("127.0.0.1:9798", &copt)); |
| |
| grpc::health::v1::Health_Stub stub(&chan); |
| stub.Check(&cntl, &request, &response, NULL); |
| |
| EXPECT_FALSE(cntl.Failed()) << cntl.ErrorText(); |
| EXPECT_EQ(response.status(), grpc::health::v1::HealthCheckResponse_ServingStatus_UNKNOWN); |
| } |
| |
| TEST_F(BuiltinServiceTest, status) { |
| TestStatus(false); |
| TestStatus(true); |
| } |
| |
| TEST_F(BuiltinServiceTest, list) { |
| brpc::ListService service(&_server); |
| brpc::ListRequest req; |
| brpc::ListResponse res; |
| brpc::Controller cntl; |
| ClosureChecker done; |
| ASSERT_EQ(0, _server.AddService(new EchoServiceImpl(), |
| brpc::SERVER_OWNS_SERVICE)); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| ASSERT_EQ(1, res.service_size()); |
| EXPECT_EQ(test::EchoService::descriptor()->name(), res.service(0).name()); |
| } |
| |
| void* sleep_thread(void*) { |
| sleep(1); |
| return NULL; |
| } |
| |
| TEST_F(BuiltinServiceTest, threads) { |
| brpc::ThreadsService service; |
| brpc::ThreadsRequest req; |
| brpc::ThreadsResponse res; |
| brpc::Controller cntl; |
| ClosureChecker done; |
| pthread_t tid; |
| ASSERT_EQ(0, pthread_create(&tid, NULL, sleep_thread, NULL)); |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| // Doesn't work under gcc 4.8.2 |
| // CheckContent(cntl, "sleep_thread"); |
| pthread_join(tid, NULL); |
| } |
| |
| TEST_F(BuiltinServiceTest, vlog) { |
| TestVLog(false); |
| TestVLog(true); |
| } |
| |
| TEST_F(BuiltinServiceTest, connections) { |
| TestConnections(false); |
| TestConnections(true); |
| } |
| |
| TEST_F(BuiltinServiceTest, flags) { |
| TestFlags(false); |
| TestFlags(true); |
| } |
| |
| TEST_F(BuiltinServiceTest, bad_method) { |
| TestBadMethod(false); |
| TestBadMethod(true); |
| } |
| |
| TEST_F(BuiltinServiceTest, vars) { |
| // Start server to show bvars inside |
| ASSERT_EQ(0, _server.Start("127.0.0.1:9798", NULL)); |
| brpc::VarsService service; |
| brpc::VarsRequest req; |
| brpc::VarsResponse res; |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| bvar::Adder<int64_t> myvar; |
| myvar.expose("myvar"); |
| myvar << 9; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckFieldInContent(cntl, "myvar : ", 9); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| cntl.http_request()._unresolved_path = "iobuf*"; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "iobuf_block_count"); |
| } |
| } |
| |
| TEST_F(BuiltinServiceTest, rpcz) { |
| for (int i = 0; i <= 1; ++i) { // enable rpcz |
| for (int j = 0; j <= 1; ++j) { // hex log id |
| for (int k = 0; k <= 1; ++k) { // use html |
| TestRpcz(i, j, k); |
| } |
| } |
| } |
| } |
| |
| TEST_F(BuiltinServiceTest, pprof) { |
| brpc::PProfService service; |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| cntl.http_request().uri().SetQuery("seconds", "1"); |
| service.profile(&cntl, NULL, NULL, &done); |
| // Just for loading symbols in gperftools/profiler.h |
| ProfilerFlush(); |
| EXPECT_FALSE(cntl.Failed()) << cntl.ErrorText(); |
| EXPECT_GT(cntl.response_attachment().length(), 0ul); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| service.heap(&cntl, NULL, NULL, &done); |
| const int rc = getenv("TCMALLOC_SAMPLE_PARAMETER") != nullptr ? 0 : brpc::ENOMETHOD; |
| EXPECT_EQ(rc, cntl.ErrorCode()) << cntl.ErrorText(); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| service.growth(&cntl, NULL, NULL, &done); |
| // linked tcmalloc in UT |
| EXPECT_EQ(0, cntl.ErrorCode()) << cntl.ErrorText(); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| service.symbol(&cntl, NULL, NULL, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "num_symbols"); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| service.cmdline(&cntl, NULL, NULL, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "brpc_builtin_service_unittest"); |
| } |
| } |
| |
| TEST_F(BuiltinServiceTest, dir) { |
| brpc::DirService service; |
| brpc::DirRequest req; |
| brpc::DirResponse res; |
| { |
| // Open root path |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, true); |
| cntl.http_request()._unresolved_path = ""; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "tmp"); |
| } |
| { |
| // Open a specific file |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, false); |
| cntl.http_request()._unresolved_path = "/usr/include/errno.h"; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| #if defined(OS_LINUX) |
| CheckContent(cntl, "ERRNO_H"); |
| #elif defined(OS_MACOSX) |
| CheckContent(cntl, "sys/errno.h"); |
| #endif |
| } |
| { |
| // Open a file that doesn't exist |
| ClosureChecker done; |
| brpc::Controller cntl; |
| SetUpController(&cntl, false); |
| cntl.http_request()._unresolved_path = "file_not_exist"; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_TRUE(cntl.Failed()); |
| CheckErrorText(cntl, "Cannot open"); |
| } |
| } |
| |
| TEST_F(BuiltinServiceTest, ids) { |
| brpc::IdsService service; |
| brpc::IdsRequest req; |
| brpc::IdsResponse res; |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "Use /ids/<call_id>"); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| cntl.http_request()._unresolved_path = "not_valid"; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_TRUE(cntl.Failed()); |
| CheckErrorText(cntl, "is not a bthread_id"); |
| } |
| { |
| bthread_id_t id; |
| EXPECT_EQ(0, bthread_id_create(&id, NULL, NULL)); |
| ClosureChecker done; |
| brpc::Controller cntl; |
| std::string id_string; |
| butil::string_printf(&id_string, "%llu", (unsigned long long)id.value); |
| cntl.http_request()._unresolved_path = id_string; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "Status: UNLOCKED"); |
| } |
| } |
| |
| void* dummy_bthread(void*) { |
| bthread_usleep(1000000); |
| return NULL; |
| } |
| |
| TEST_F(BuiltinServiceTest, bthreads) { |
| brpc::BthreadsService service; |
| brpc::BthreadsRequest req; |
| brpc::BthreadsResponse res; |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "Use /bthreads/<bthread_id>"); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| cntl.http_request()._unresolved_path = "not_valid"; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_TRUE(cntl.Failed()); |
| CheckErrorText(cntl, "is not a bthread id"); |
| } |
| { |
| bthread_t th; |
| EXPECT_EQ(0, bthread_start_background(&th, NULL, dummy_bthread, NULL)); |
| ClosureChecker done; |
| brpc::Controller cntl; |
| std::string id_string; |
| butil::string_printf(&id_string, "%llu", (unsigned long long)th); |
| cntl.http_request()._unresolved_path = id_string; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "stop=0"); |
| } |
| } |
| |
| TEST_F(BuiltinServiceTest, sockets) { |
| brpc::SocketsService service; |
| brpc::SocketsRequest req; |
| brpc::SocketsResponse res; |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "Use /sockets/<SocketId>"); |
| } |
| { |
| ClosureChecker done; |
| brpc::Controller cntl; |
| cntl.http_request()._unresolved_path = "not_valid"; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_TRUE(cntl.Failed()); |
| CheckErrorText(cntl, "is not a SocketId"); |
| } |
| { |
| brpc::SocketId id; |
| brpc::SocketOptions options; |
| EXPECT_EQ(0, brpc::Socket::Create(options, &id)); |
| ClosureChecker done; |
| brpc::Controller cntl; |
| std::string id_string; |
| butil::string_printf(&id_string, "%llu", (unsigned long long)id); |
| cntl.http_request()._unresolved_path = id_string; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "fd=-1"); |
| } |
| } |
| |
| TEST_F(BuiltinServiceTest, memory) { |
| brpc::MemoryService service; |
| brpc::MemoryRequest req; |
| brpc::MemoryResponse res; |
| brpc::Controller cntl; |
| ClosureChecker done; |
| service.default_method(&cntl, &req, &res, &done); |
| EXPECT_FALSE(cntl.Failed()); |
| CheckContent(cntl, "generic.current_allocated_bytes"); |
| CheckContent(cntl, "generic.heap_size"); |
| CheckContent(cntl, "tcmalloc.current_total_thread_cache_bytes"); |
| CheckContent(cntl, "tcmalloc.central_cache_free_bytes"); |
| CheckContent(cntl, "tcmalloc.transfer_cache_free_bytes"); |
| CheckContent(cntl, "tcmalloc.thread_cache_free_bytes"); |
| CheckContent(cntl, "tcmalloc.pageheap_free_bytes"); |
| CheckContent(cntl, "tcmalloc.pageheap_unmapped_bytes"); |
| } |