Commit 4e8ff1e5 authored by zhenren's avatar zhenren

Merge branch 'master' of https://github.com/brpc/brpc into chore/fix_bazel

parents e4e6ab1a 8e156bee
......@@ -133,22 +133,19 @@ if(NOT PROTOC_LIB)
message(FATAL_ERROR "Fail to find protoc lib")
endif()
find_path(SSL_INCLUDE_PATH NAMES openssl/ssl.h)
find_library(SSL_LIB NAMES ssl)
if ((NOT SSL_INCLUDE_PATH) OR (NOT SSL_LIB))
message(FATAL_ERROR "Fail to find ssl")
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(OPENSSL_ROOT_DIR
"/usr/local/opt/openssl" # Homebrew installed OpenSSL
)
endif()
find_library(CRYPTO_LIB NAMES crypto)
if (NOT CRYPTO_LIB)
message(FATAL_ERROR "Fail to find crypto")
endif()
include(FindOpenSSL)
include_directories(
${GFLAGS_INCLUDE_PATH}
${PROTOBUF_INCLUDE_DIRS}
${LEVELDB_INCLUDE_PATH}
${SSL_INCLUDE_PATH}
${OPENSSL_INCLUDE_DIR}
)
set(DYNAMIC_LIB
......@@ -158,12 +155,13 @@ set(DYNAMIC_LIB
${PROTOC_LIB}
${CMAKE_THREAD_LIBS_INIT}
${THRIFT_LIB}
${SSL_LIB}
${CRYPTO_LIB}
${OPENSSL_LIBRARIES}
${OPENSSL_CRYPTO_LIBRARY}
dl
z
)
set(BRPC_PRIVATE_LIBS "-lgflags -lprotobuf -lleveldb -lprotoc -lrt -lssl -lcrypto -ldl -lz")
set(BRPC_PRIVATE_LIBS "-lgflags -lprotobuf -lleveldb -lprotoc -lssl -lcrypto -ldl -lz")
if(BRPC_WITH_GLOG)
set(DYNAMIC_LIB ${DYNAMIC_LIB} ${GLOG_LIB})
set(BRPC_PRIVATE_LIBS "${BRPC_PRIVATE_LIBS} -lglog")
......@@ -171,6 +169,7 @@ endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(DYNAMIC_LIB ${DYNAMIC_LIB} rt)
set(BRPC_PRIVATE_LIBS "${BRPC_PRIVATE_LIBS} -lrt")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(DYNAMIC_LIB ${DYNAMIC_LIB}
pthread
......@@ -355,9 +354,9 @@ set(PROTO_FILES idl_options.proto
brpc/streaming_rpc_meta.proto)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/output/include/brpc)
set(PROTOC_FLAGS ${PROTOC_FLAGS} -I${PROTOBUF_INCLUDE_DIR})
compile_proto(PROTO_HDRS PROTO_SRCS ${CMAKE_BINARY_DIR}
compile_proto(PROTO_HDRS PROTO_SRCS ${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}/output/include
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src
"${PROTO_FILES}")
add_library(PROTO_LIB OBJECT ${PROTO_SRCS} ${PROTO_HDRS})
......@@ -377,7 +376,7 @@ add_subdirectory(tools)
file(COPY ${CMAKE_CURRENT_BINARY_DIR}/brpc/
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/output/include/brpc/
FILES_MATCHING
FILES_MATCHING
PATTERN "*.h"
PATTERN "*.hpp"
)
......
......@@ -218,6 +218,9 @@ To change compiler to clang, overwrite environment variable CC and CXX to clang
To not link debugging symbols, use `cmake -DWITH_DEBUG_SYMBOLS=OFF ..` and compiled binaries will be much smaller.
## MacOS
Note: In the same running environment, the performance of the current Mac version is about 2.5 times worse than the Linux version. If your service is performance-critical, do not use MacOS as your production environment.
### Prepare deps
Install common deps:
......
......@@ -22,7 +22,7 @@ brpc就是设计为可随时扩展新协议的,步骤如下:
[options.proto](https://github.com/brpc/brpc/blob/master/src/brpc/options.proto)的ProtocolType中增加新协议类型,如果你需要的话可以联系我们增加,以确保不会和其他人的需求重合。
目前的ProtocolType(16年底):
目前的ProtocolType(18年中):
```c++
enum ProtocolType {
PROTOCOL_UNKNOWN = 0;
......@@ -48,6 +48,10 @@ enum ProtocolType {
PROTOCOL_DISP_IDL = 20; // Client side only
PROTOCOL_ERSDA_CLIENT = 21; // Client side only
PROTOCOL_UBRPC_MCPACK2 = 22; // Client side only
// Reserve special protocol for cds-agent, which depends on FIFO right now
PROTOCOL_CDS_AGENT = 23; // Client side only
PROTOCOL_ESP = 24; // Client side only
PROTOCOL_THRIFT = 25; // Server side only
}
```
## 实现回调
......
......@@ -22,7 +22,7 @@ brpc is designed to add new protocols at any time, just proceed as follows:
Add new protocol type in ProtocolType in [options.proto](https://github.com/brpc/brpc/blob/master/src/brpc/options.proto). If you need to add new protocol, please contact us to add it for you to make sure there is no conflict with protocols of others.
Currently we support in ProtocolType(at the end of 2016):
Currently we support in ProtocolType(at the middle of 2018):
```c++
enum ProtocolType {
PROTOCOL_UNKNOWN = 0;
......@@ -48,6 +48,10 @@ enum ProtocolType {
PROTOCOL_DISP_IDL = 20; // Client side only
PROTOCOL_ERSDA_CLIENT = 21; // Client side only
PROTOCOL_UBRPC_MCPACK2 = 22; // Client side only
// Reserve special protocol for cds-agent, which depends on FIFO right now
PROTOCOL_CDS_AGENT = 23; // Client side only
PROTOCOL_ESP = 24; // Client side only
PROTOCOL_THRIFT = 25; // Server side only
}
```
## Implement Callbacks
......
// Copyright (c) 2015 Baidu, Inc.
//
//
// Licensed 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.
......@@ -17,7 +17,7 @@
#include <ostream>
#include <vector> // std::vector
#include <set>
#include <gflags/gflags.h> // GetAllFlags
#include <gflags/gflags.h> // GetAllFlags
// CommandLineFlagInfo
#include "butil/string_printf.h"
#include "butil/string_splitter.h"
......@@ -89,7 +89,7 @@ static void PrintFlag(std::ostream& os, const GFLAGS_NS::CommandLineFlagInfo& fl
if (flag.default_value != flag.current_value) {
os << " (default:" << (use_html ?
HtmlReplace(flag.default_value) :
flag.current_value) << ')';
flag.default_value) << ')';
}
if (use_html) {
os << "</span>";
......
......@@ -85,7 +85,7 @@ template <class T1, size_t BLOCK_SIZE> class PooledAllocator;
template <typename K, typename V, size_t BLOCK_SIZE = 512,
typename C = std::less<K> >
class PooledMap
: public std::map<K, V, C, details::PooledAllocator<int, BLOCK_SIZE> > {
: public std::map<K, V, C, details::PooledAllocator<std::pair<const K, V>, BLOCK_SIZE> > {
};
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This module provides a way to monitor a file or directory for changes.
#ifndef BUTIL_FILES_FILE_PATH_WATCHER_H_
#define BUTIL_FILES_FILE_PATH_WATCHER_H_
#include "butil/base_export.h"
#include "butil/basictypes.h"
#include "butil/callback.h"
#include "butil/files/file_path.h"
#include "butil/memory/ref_counted.h"
#include "butil/message_loop/message_loop_proxy.h"
namespace butil {
// This class lets you register interest in changes on a FilePath.
// The callback will get called whenever the file or directory referenced by the
// FilePath is changed, including created or deleted. Due to limitations in the
// underlying OS APIs, FilePathWatcher has slightly different semantics on OS X
// than on Windows or Linux. FilePathWatcher on Linux and Windows will detect
// modifications to files in a watched directory. FilePathWatcher on Mac will
// detect the creation and deletion of files in a watched directory, but will
// not detect modifications to those files. See file_path_watcher_kqueue.cc for
// details.
class BUTIL_EXPORT FilePathWatcher {
public:
// Callback type for Watch(). |path| points to the file that was updated,
// and |error| is true if the platform specific code detected an error. In
// that case, the callback won't be invoked again.
typedef butil::Callback<void(const FilePath& path, bool error)> Callback;
// Used internally to encapsulate different members on different platforms.
class PlatformDelegate : public butil::RefCountedThreadSafe<PlatformDelegate> {
public:
PlatformDelegate();
// Start watching for the given |path| and notify |delegate| about changes.
virtual bool Watch(const FilePath& path,
bool recursive,
const Callback& callback) WARN_UNUSED_RESULT = 0;
// Stop watching. This is called from FilePathWatcher's dtor in order to
// allow to shut down properly while the object is still alive.
// It can be called from any thread.
virtual void Cancel() = 0;
protected:
friend class butil::RefCountedThreadSafe<PlatformDelegate>;
friend class FilePathWatcher;
virtual ~PlatformDelegate();
// Stop watching. This is only called on the thread of the appropriate
// message loop. Since it can also be called more than once, it should
// check |is_cancelled()| to avoid duplicate work.
virtual void CancelOnMessageLoopThread() = 0;
scoped_refptr<butil::MessageLoopProxy> message_loop() const {
return message_loop_;
}
void set_message_loop(butil::MessageLoopProxy* loop) {
message_loop_ = loop;
}
// Must be called before the PlatformDelegate is deleted.
void set_cancelled() {
cancelled_ = true;
}
bool is_cancelled() const {
return cancelled_;
}
private:
scoped_refptr<butil::MessageLoopProxy> message_loop_;
bool cancelled_;
};
FilePathWatcher();
virtual ~FilePathWatcher();
// A callback that always cleans up the PlatformDelegate, either when executed
// or when deleted without having been executed at all, as can happen during
// shutdown.
static void CancelWatch(const scoped_refptr<PlatformDelegate>& delegate);
// Returns true if the platform and OS version support recursive watches.
static bool RecursiveWatchAvailable();
// Invokes |callback| whenever updates to |path| are detected. This should be
// called at most once, and from a MessageLoop of TYPE_IO. Set |recursive| to
// true, to watch |path| and its children. The callback will be invoked on
// the same loop. Returns true on success.
//
// Recursive watch is not supported on all platforms and file systems.
// Watch() will return false in the case of failure.
bool Watch(const FilePath& path, bool recursive, const Callback& callback);
private:
scoped_refptr<PlatformDelegate> impl_;
DISALLOW_COPY_AND_ASSIGN(FilePathWatcher);
};
} // namespace butil
#endif // BUTIL_FILES_FILE_PATH_WATCHER_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BUTIL_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
#define BUTIL_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
#include <CoreServices/CoreServices.h>
#include <vector>
#include "butil/files/file_path.h"
#include "butil/files/file_path_watcher.h"
namespace butil {
// Mac-specific file watcher implementation based on FSEvents.
// There are trade-offs between the FSEvents implementation and a kqueue
// implementation. The biggest issues are that FSEvents on 10.6 sometimes drops
// events and kqueue does not trigger for modifications to a file in a watched
// directory. See file_path_watcher_mac.cc for the code that decides when to
// use which one.
class FilePathWatcherFSEvents : public FilePathWatcher::PlatformDelegate {
public:
FilePathWatcherFSEvents();
// Called from the FSEvents callback whenever there is a change to the paths.
void OnFilePathsChanged(const std::vector<FilePath>& paths);
// (Re-)Initialize the event stream to start reporting events from
// |start_event|.
void UpdateEventStream(FSEventStreamEventId start_event);
// Returns true if resolving the target path got a different result than
// last time it was done.
bool ResolveTargetPath();
// FilePathWatcher::PlatformDelegate overrides.
virtual bool Watch(const FilePath& path,
bool recursive,
const FilePathWatcher::Callback& callback) OVERRIDE;
virtual void Cancel() OVERRIDE;
private:
virtual ~FilePathWatcherFSEvents();
// Destroy the event stream.
void DestroyEventStream();
// Start watching the FSEventStream.
void StartEventStream(FSEventStreamEventId start_event);
// Cleans up and stops the event stream.
virtual void CancelOnMessageLoopThread() OVERRIDE;
// Callback to notify upon changes.
FilePathWatcher::Callback callback_;
// Target path to watch (passed to callback).
FilePath target_;
// Target path with all symbolic links resolved.
FilePath resolved_target_;
// Backend stream we receive event callbacks from (strong reference).
FSEventStreamRef fsevent_stream_;
DISALLOW_COPY_AND_ASSIGN(FilePathWatcherFSEvents);
};
} // namespace butil
#endif // BUTIL_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BUTIL_FILES_FILE_PATH_WATCHER_KQUEUE_H_
#define BUTIL_FILES_FILE_PATH_WATCHER_KQUEUE_H_
#include <sys/event.h>
#include <vector>
#include "butil/files/file_path.h"
#include "butil/files/file_path_watcher.h"
#include "butil/message_loop/message_loop.h"
#include "butil/message_loop/message_loop_proxy.h"
namespace butil {
// Mac-specific file watcher implementation based on kqueue.
// The Linux and Windows versions are able to detect:
// - file creation/deletion/modification in a watched directory
// - file creation/deletion/modification for a watched file
// - modifications to the paths to a watched object that would affect the
// object such as renaming/attibute changes etc.
// The kqueue implementation will handle all of the items in the list above
// except for detecting modifications to files in a watched directory. It will
// detect the creation and deletion of files, just not the modification of
// files. It does however detect the attribute changes that the FSEvents impl
// would miss.
class FilePathWatcherKQueue : public FilePathWatcher::PlatformDelegate,
public MessageLoopForIO::Watcher,
public MessageLoop::DestructionObserver {
public:
FilePathWatcherKQueue();
// MessageLoopForIO::Watcher overrides.
virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
// MessageLoop::DestructionObserver overrides.
virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
// FilePathWatcher::PlatformDelegate overrides.
virtual bool Watch(const FilePath& path,
bool recursive,
const FilePathWatcher::Callback& callback) OVERRIDE;
virtual void Cancel() OVERRIDE;
protected:
virtual ~FilePathWatcherKQueue();
private:
class EventData {
public:
EventData(const FilePath& path, const FilePath::StringType& subdir)
: path_(path), subdir_(subdir) { }
FilePath path_; // Full path to this item.
FilePath::StringType subdir_; // Path to any sub item.
};
typedef std::vector<struct kevent> EventVector;
// Can only be called on |io_message_loop_|'s thread.
virtual void CancelOnMessageLoopThread() OVERRIDE;
// Returns true if the kevent values are error free.
bool AreKeventValuesValid(struct kevent* kevents, int count);
// Respond to a change of attributes of the path component represented by
// |event|. Sets |target_file_affected| to true if |target_| is affected.
// Sets |update_watches| to true if |events_| need to be updated.
void HandleAttributesChange(const EventVector::iterator& event,
bool* target_file_affected,
bool* update_watches);
// Respond to a move or deletion of the path component represented by
// |event|. Sets |target_file_affected| to true if |target_| is affected.
// Sets |update_watches| to true if |events_| need to be updated.
void HandleDeleteOrMoveChange(const EventVector::iterator& event,
bool* target_file_affected,
bool* update_watches);
// Respond to a creation of an item in the path component represented by
// |event|. Sets |target_file_affected| to true if |target_| is affected.
// Sets |update_watches| to true if |events_| need to be updated.
void HandleCreateItemChange(const EventVector::iterator& event,
bool* target_file_affected,
bool* update_watches);
// Update |events_| with the current status of the system.
// Sets |target_file_affected| to true if |target_| is affected.
// Returns false if an error occurs.
bool UpdateWatches(bool* target_file_affected);
// Fills |events| with one kevent per component in |path|.
// Returns the number of valid events created where a valid event is
// defined as one that has a ident (file descriptor) field != -1.
static int EventsForPath(FilePath path, EventVector *events);
// Release a kevent generated by EventsForPath.
static void ReleaseEvent(struct kevent& event);
// Returns a file descriptor that will not block the system from deleting
// the file it references.
static uintptr_t FileDescriptorForPath(const FilePath& path);
static const uintptr_t kNoFileDescriptor = static_cast<uintptr_t>(-1);
// Closes |*fd| and sets |*fd| to -1.
static void CloseFileDescriptor(uintptr_t* fd);
// Returns true if kevent has open file descriptor.
static bool IsKeventFileDescriptorOpen(const struct kevent& event) {
return event.ident != kNoFileDescriptor;
}
static EventData* EventDataForKevent(const struct kevent& event) {
return reinterpret_cast<EventData*>(event.udata);
}
EventVector events_;
scoped_refptr<butil::MessageLoopProxy> io_message_loop_;
MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_;
FilePathWatcher::Callback callback_;
FilePath target_;
int kqueue_;
DISALLOW_COPY_AND_ASSIGN(FilePathWatcherKQueue);
};
} // namespace butil
#endif // BUTIL_FILES_FILE_PATH_WATCHER_KQUEUE_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/files/file_path_watcher.h"
#include "butil/files/file_path_watcher_kqueue.h"
#if !defined(OS_IOS)
#include "butil/files/file_path_watcher_fsevents.h"
#endif
namespace butil {
namespace {
class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
public:
virtual bool Watch(const FilePath& path,
bool recursive,
const FilePathWatcher::Callback& callback) OVERRIDE {
// Use kqueue for non-recursive watches and FSEvents for recursive ones.
DCHECK(!impl_.get());
if (recursive) {
if (!FilePathWatcher::RecursiveWatchAvailable())
return false;
#if !defined(OS_IOS)
impl_ = new FilePathWatcherFSEvents();
#endif // OS_IOS
} else {
impl_ = new FilePathWatcherKQueue();
}
DCHECK(impl_.get());
return impl_->Watch(path, recursive, callback);
}
virtual void Cancel() OVERRIDE {
if (impl_)
impl_->Cancel();
set_cancelled();
}
virtual void CancelOnMessageLoopThread() OVERRIDE {
if (impl_)
impl_->Cancel();
set_cancelled();
}
protected:
virtual ~FilePathWatcherImpl() {}
scoped_refptr<PlatformDelegate> impl_;
};
} // namespace
FilePathWatcher::FilePathWatcher() {
impl_ = new FilePathWatcherImpl();
}
} // namespace butil
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BUTIL_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_
#define BUTIL_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_
#include "butil/location.h"
#include "butil/logging.h"
#include "butil/memory/ref_counted.h"
#include "butil/message_loop/message_loop_proxy.h"
namespace butil {
// RefCountedDeleteOnMessageLoop is similar to RefCountedThreadSafe, and ensures
// that the object will be deleted on a specified message loop.
//
// Sample usage:
// class Foo : public RefCountedDeleteOnMessageLoop<Foo> {
//
// Foo(const scoped_refptr<MessageLoopProxy>& loop)
// : RefCountedDeleteOnMessageLoop<Foo>(loop) {
// ...
// }
// ...
// private:
// friend class RefCountedDeleteOnMessageLoop<Foo>;
// friend class DeleteHelper<Foo>;
//
// ~Foo();
// };
template <class T>
class RefCountedDeleteOnMessageLoop : public subtle::RefCountedThreadSafeBase {
public:
RefCountedDeleteOnMessageLoop(
const scoped_refptr<MessageLoopProxy>& proxy) : proxy_(proxy) {
DCHECK(proxy_.get());
}
void AddRef() const {
subtle::RefCountedThreadSafeBase::AddRef();
}
void Release() const {
if (subtle::RefCountedThreadSafeBase::Release())
DestructOnMessageLoop();
}
protected:
friend class DeleteHelper<RefCountedDeleteOnMessageLoop>;
~RefCountedDeleteOnMessageLoop() {}
void DestructOnMessageLoop() const {
const T* t = static_cast<const T*>(this);
if (proxy_->BelongsToCurrentThread())
delete t;
else
proxy_->DeleteSoon(FROM_HERE, t);
}
scoped_refptr<MessageLoopProxy> proxy_;
private:
DISALLOW_COPY_AND_ASSIGN(RefCountedDeleteOnMessageLoop);
};
} // namespace butil
#endif // BUTIL_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_
// Copyright (c) 2014 Baidu, Inc.
// Date: Thu Jun 11 14:30:07 CST 2015
#ifdef BAIDU_INTERNAL
#include <iostream>
#include "butil/time.h"
#include "butil/logging.h"
......@@ -22,53 +20,91 @@ int main(int argc, char* argv[]) {
namespace {
static pthread_once_t download_memcached_once = PTHREAD_ONCE_INIT;
static pid_t g_mc_pid = -1;
static void RemoveMemcached() {
puts("Removing memcached...");
system("rm -rf memcached_for_test");
puts("[Stopping memcached]");
char cmd[256];
#if defined(BAIDU_INTERNAL)
snprintf(cmd, sizeof(cmd), "kill %d; rm -rf memcached_for_test", g_mc_pid);
#else
snprintf(cmd, sizeof(cmd), "kill %d", g_mc_pid);
#endif
CHECK(0 == system(cmd));
// Wait for mc to stop
usleep(50000);
}
static void DownloadMemcached() {
#define MEMCACHED_BIN "memcached"
#define MEMCACHED_PORT "11211"
static void RunMemcached() {
#if defined(BAIDU_INTERNAL)
puts("Downloading memcached...");
system("pkill memcached; mkdir -p memcached_for_test && cd memcached_for_test && svn co https://svn.baidu.com/third-64/tags/memcached/memcached_1-4-15-100_PD_BL/bin");
if (system("mkdir -p memcached_for_test && cd memcached_for_test && svn co https://svn.baidu.com/third-64/tags/memcached/memcached_1-4-15-100_PD_BL/bin") != 0) {
puts("Fail to get memcached from svn");
return;
}
# undef MEMCACHED_BIN
# define MEMCACHED_BIN "memcached_for_test/bin/memcached";
#else
if (system("which " MEMCACHED_BIN) != 0) {
puts("Fail to find " MEMCACHED_BIN ", following tests will be skipped");
return;
}
#endif
atexit(RemoveMemcached);
g_mc_pid = fork();
if (g_mc_pid < 0) {
puts("Fail to fork");
exit(1);
} else if (g_mc_pid == 0) {
puts("[Starting memcached]");
char* const argv[] = { (char*)MEMCACHED_BIN,
(char*)"--port", (char*)MEMCACHED_PORT,
NULL };
if (execvp(MEMCACHED_BIN, argv) < 0) {
puts("Fail to run " MEMCACHED_BIN);
exit(1);
}
}
// Wait for memcached to start.
usleep(50000);
}
class MemcacheTest : public testing::Test {
protected:
MemcacheTest() : _pid(-1) {}
MemcacheTest() {}
void SetUp() {
pthread_once(&download_memcached_once, DownloadMemcached);
_pid = fork();
if (_pid < 0) {
puts("Fail to fork");
exit(1);
} else if (_pid == 0) {
puts("[Starting memcached]");
char* const argv[] = { (char*)"memcached_for_test/bin/memcached", NULL };
execv("memcached_for_test/bin/memcached", argv);
}
usleep(10000);
pthread_once(&download_memcached_once, RunMemcached);
}
void TearDown() {
puts("[Stopping memcached]");
char cmd[64];
snprintf(cmd, sizeof(cmd), "kill %d", _pid);
CHECK(0 == system(cmd));
}
private:
pid_t _pid;
};
TEST_F(MemcacheTest, sanity) {
if (g_mc_pid < 0) {
puts("Skipped due to absence of memcached");
return;
}
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_MEMCACHE;
brpc::Channel channel;
ASSERT_EQ(0, channel.Init("0.0.0.0:11211", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" MEMCACHED_PORT, &options));
brpc::MemcacheRequest request;
brpc::MemcacheResponse response;
brpc::Controller cntl;
// Clear all contents in MC which is still holding older data after
// restarting in Ubuntu 18.04 (mc=1.5.6)
request.Flush(0);
channel.CallMethod(NULL, &cntl, &request, &response, NULL);
ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText();
ASSERT_TRUE(response.PopFlush());
cntl.Reset();
request.Clear();
request.Get("hello");
channel.CallMethod(NULL, &cntl, &request, &response, NULL);
ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText();
......@@ -119,10 +155,14 @@ TEST_F(MemcacheTest, sanity) {
}
TEST_F(MemcacheTest, incr_and_decr) {
if (g_mc_pid < 0) {
puts("Skipped due to absence of memcached");
return;
}
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_MEMCACHE;
brpc::Channel channel;
ASSERT_EQ(0, channel.Init("0.0.0.0:11211", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" MEMCACHED_PORT, &options));
brpc::MemcacheRequest request;
brpc::MemcacheResponse response;
brpc::Controller cntl;
......@@ -150,10 +190,14 @@ TEST_F(MemcacheTest, incr_and_decr) {
}
TEST_F(MemcacheTest, version) {
if (g_mc_pid < 0) {
puts("Skipped due to absence of memcached");
return;
}
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_MEMCACHE;
brpc::Channel channel;
ASSERT_EQ(0, channel.Init("0.0.0.0:11211", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" MEMCACHED_PORT, &options));
brpc::MemcacheRequest request;
brpc::MemcacheResponse response;
brpc::Controller cntl;
......@@ -165,5 +209,3 @@ TEST_F(MemcacheTest, version) {
std::cout << "version=" << version << std::endl;
}
} //namespace
#endif // BAIDU_INTERNAL
......@@ -23,44 +23,67 @@ int main(int argc, char* argv[]) {
namespace {
static pthread_once_t download_redis_server_once = PTHREAD_ONCE_INIT;
static pid_t redis_pid = -1;
static pid_t g_redis_pid = -1;
static void RemoveRedisServer() {
if (redis_pid > 0) {
if (g_redis_pid > 0) {
puts("[Stopping redis-server]");
char cmd[256];
snprintf(cmd, sizeof(cmd), "kill %d; rm -rf redis_server_for_test", redis_pid);
#if defined(BAIDU_INTERNAL)
snprintf(cmd, sizeof(cmd), "kill %d; rm -rf redis_server_for_test", g_redis_pid);
#else
snprintf(cmd, sizeof(cmd), "kill %d", g_redis_pid);
#endif
CHECK(0 == system(cmd));
// Wait for redis to stop
usleep(50000);
}
}
static void DownloadRedisServer() {
#define REDIS_SERVER_BIN "redis-server"
#define REDIS_SERVER_PORT "6479"
static void RunRedisServer() {
#if defined(BAIDU_INTERNAL)
puts("Downloading redis-server...");
system("pkill redis-server; mkdir -p redis_server_for_test && cd redis_server_for_test && svn co https://svn.baidu.com/third-64/tags/redis/redis_2-6-14-100_PD_BL/bin");
if (system("mkdir -p redis_server_for_test && cd redis_server_for_test && svn co https://svn.baidu.com/third-64/tags/redis/redis_2-6-14-100_PD_BL/bin") != 0) {
puts("Fail to get redis-server from svn");
return;
}
# undef REDIS_SERVER_BIN
# define REDIS_SERVER_BIN "redis_server_for_test/bin/redis-server";
#else
if (system("which " REDIS_SERVER_BIN) != 0) {
puts("Fail to find " REDIS_SERVER_BIN ", following tests will be skipped");
return;
}
#endif
atexit(RemoveRedisServer);
redis_pid = fork();
if (redis_pid < 0) {
g_redis_pid = fork();
if (g_redis_pid < 0) {
puts("Fail to fork");
exit(1);
} else if (redis_pid == 0) {
} else if (g_redis_pid == 0) {
puts("[Starting redis-server]");
char* const argv[] = { (char*)"redis_server_for_test/bin/redis-server",
(char*)"--port", (char*)"6479",
char* const argv[] = { (char*)REDIS_SERVER_BIN,
(char*)"--port", (char*)REDIS_SERVER_PORT,
NULL };
unlink("dump.rdb");
execv("redis_server_for_test/bin/redis-server", argv);
if (execvp(REDIS_SERVER_BIN, argv) < 0) {
puts("Fail to run " REDIS_SERVER_BIN);
exit(1);
}
}
usleep(10000);
// Wait for redis to start.
usleep(50000);
}
class RedisTest : public testing::Test {
protected:
RedisTest() {}
void SetUp() {
#if defined(BAIDU_INTERNAL)
pthread_once(&download_redis_server_once, DownloadRedisServer);
#endif
pthread_once(&download_redis_server_once, RunRedisServer);
}
void TearDown() {}
};
......@@ -113,12 +136,15 @@ void AssertResponseEqual(const brpc::RedisResponse& r1,
}
}
#if defined(BAIDU_INTERNAL)
TEST_F(RedisTest, sanity) {
if (g_redis_pid < 0) {
puts("Skipped due to absence of redis-server");
return;
}
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_REDIS;
brpc::Channel channel;
ASSERT_EQ(0, channel.Init("0.0.0.0:6479", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" REDIS_SERVER_PORT, &options));
brpc::RedisRequest request;
brpc::RedisResponse response;
brpc::Controller cntl;
......@@ -190,10 +216,14 @@ TEST_F(RedisTest, sanity) {
}
TEST_F(RedisTest, keys_with_spaces) {
if (g_redis_pid < 0) {
puts("Skipped due to absence of redis-server");
return;
}
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_REDIS;
brpc::Channel channel;
ASSERT_EQ(0, channel.Init("0.0.0.0:6479", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" REDIS_SERVER_PORT, &options));
brpc::RedisRequest request;
brpc::RedisResponse response;
brpc::Controller cntl;
......@@ -234,10 +264,14 @@ TEST_F(RedisTest, keys_with_spaces) {
}
TEST_F(RedisTest, incr_and_decr) {
if (g_redis_pid < 0) {
puts("Skipped due to absence of redis-server");
return;
}
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_REDIS;
brpc::Channel channel;
ASSERT_EQ(0, channel.Init("0.0.0.0:6479", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" REDIS_SERVER_PORT, &options));
brpc::RedisRequest request;
brpc::RedisResponse response;
brpc::Controller cntl;
......@@ -265,10 +299,14 @@ TEST_F(RedisTest, incr_and_decr) {
}
TEST_F(RedisTest, by_components) {
if (g_redis_pid < 0) {
puts("Skipped due to absence of redis-server");
return;
}
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_REDIS;
brpc::Channel channel;
ASSERT_EQ(0, channel.Init("0.0.0.0:6479", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" REDIS_SERVER_PORT, &options));
brpc::RedisRequest request;
brpc::RedisResponse response;
brpc::Controller cntl;
......@@ -302,12 +340,16 @@ TEST_F(RedisTest, by_components) {
}
TEST_F(RedisTest, auth) {
if (g_redis_pid < 0) {
puts("Skipped due to absence of redis-server");
return;
}
// config auth
{
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_REDIS;
brpc::Channel channel;
ASSERT_EQ(0, channel.Init("0.0.0.0:6479", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" REDIS_SERVER_PORT, &options));
brpc::RedisRequest request;
brpc::RedisResponse response;
brpc::Controller cntl;
......@@ -340,7 +382,7 @@ TEST_F(RedisTest, auth) {
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_REDIS;
brpc::Channel channel;
ASSERT_EQ(0, channel.Init("0.0.0.0:6479", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" REDIS_SERVER_PORT, &options));
brpc::RedisRequest request;
brpc::RedisResponse response;
brpc::Controller cntl;
......@@ -363,7 +405,7 @@ TEST_F(RedisTest, auth) {
brpc::policy::RedisAuthenticator* auth =
new brpc::policy::RedisAuthenticator("my_redis");
options.auth = auth;
ASSERT_EQ(0, channel.Init("0.0.0.0:6479", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" REDIS_SERVER_PORT, &options));
brpc::RedisRequest request;
brpc::RedisResponse response;
brpc::Controller cntl;
......@@ -388,7 +430,7 @@ TEST_F(RedisTest, auth) {
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_REDIS;
brpc::Channel channel;
ASSERT_EQ(0, channel.Init("0.0.0.0:6479", &options));
ASSERT_EQ(0, channel.Init("0.0.0.0:" REDIS_SERVER_PORT, &options));
brpc::RedisRequest request;
brpc::RedisResponse response;
brpc::Controller cntl;
......@@ -405,9 +447,11 @@ TEST_F(RedisTest, auth) {
}
}
#endif // BAIDU_INTERNAL
TEST_F(RedisTest, cmd_format) {
if (g_redis_pid < 0) {
puts("Skipped due to absence of redis-server");
return;
}
brpc::RedisRequest request;
// set empty string
request.AddCommand("set a ''");
......
......@@ -56,8 +56,9 @@ TEST(VersionTest, GetVersionFromString) {
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
Version version(cases[i].input);
EXPECT_EQ(cases[i].success, version.IsValid());
if (cases[i].success)
if (cases[i].success) {
EXPECT_EQ(cases[i].parts, version.components().size());
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment