blob: 21f6f5025921ae4453adb139ad79f92b449648c0 [file] [log] [blame]
// 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/common.h"
#include "brpc/builtin/bad_method_service.h"
#include "echo.pb.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());
}
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");
}
}