Commit e51d7b992ab79a89b7d26487ec7e89641a0209ed
1 parent
cb37f24f
GTest suite for unit testing, improved CMakeLists
Added GTest under test/. Great for unit testing commands. Added some nice helper functions to make writing tests easy. Added options to CMakeLists to build the library, tests, and examples separately, configurable through ccmake. Also default the build type to RelWithDebInfo, but don't override user settings.
Showing
3 changed files
with
170 additions
and
26 deletions
CMakeLists.txt
| 1 | 1 | cmake_minimum_required(VERSION 2.8.4) |
| 2 | 2 | project(redox) |
| 3 | 3 | |
| 4 | -#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -Wall -O3") | |
| 5 | -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -Wall -g -fno-omit-frame-pointer") | |
| 6 | -# set(CMAKE_VERBOSE_MAKEFILE ON) | |
| 4 | +option(library "Build Redox as a library." ON) | |
| 5 | +option(tests "Build all tests." ON) | |
| 6 | +option(examples "Build all examples." ON) | |
| 7 | + | |
| 8 | +# Use RelWithDebInfo if no configuration specified | |
| 9 | +if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) | |
| 10 | + set(CMAKE_BUILD_TYPE RelWithDebInfo) | |
| 11 | +endif(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) | |
| 12 | + | |
| 13 | +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -Wall") | |
| 14 | + | |
| 15 | +# Print out compiler commands | |
| 16 | +set(CMAKE_VERBOSE_MAKEFILE ON) | |
| 7 | 17 | |
| 8 | 18 | # --------------------------------------------------------- |
| 9 | 19 | # Source files |
| ... | ... | @@ -23,35 +33,55 @@ set(SRC_ALL ${SRC_CORE}) |
| 23 | 33 | # --------------------------------------------------------- |
| 24 | 34 | |
| 25 | 35 | set(LIB_REDIS hiredis ev pthread) |
| 26 | -set(LIB_ALL ${LIB_REDIS}) | |
| 36 | + | |
| 37 | +# --------------------------------------------------------- | |
| 38 | +# Test suite | |
| 39 | +# --------------------------------------------------------- | |
| 40 | +if (tests) | |
| 41 | + | |
| 42 | + enable_testing() | |
| 43 | + find_package(GTest REQUIRED) | |
| 44 | + include_directories(${GTEST_INCLUDE_DIRS}) | |
| 45 | + | |
| 46 | + add_executable(test_redox test/test.cpp ${SRC_ALL}) | |
| 47 | + | |
| 48 | + target_link_libraries(test_redox ${LIB_REDIS} gtest) | |
| 49 | + | |
| 50 | + # So that we can run 'make test' | |
| 51 | + add_test(test_redox test_redox) | |
| 52 | + | |
| 53 | +endif() | |
| 27 | 54 | |
| 28 | 55 | # --------------------------------------------------------- |
| 29 | 56 | # Examples |
| 30 | 57 | # --------------------------------------------------------- |
| 58 | +if (examples) | |
| 59 | + | |
| 60 | + add_executable(basic examples/basic.cpp ${SRC_ALL}) | |
| 61 | + target_link_libraries(basic ${LIB_REDIS}) | |
| 31 | 62 | |
| 32 | -add_executable(basic examples/basic.cpp ${SRC_ALL}) | |
| 33 | -target_link_libraries(basic ${LIB_REDIS}) | |
| 63 | + add_executable(basic_threaded examples/basic_threaded.cpp ${SRC_ALL}) | |
| 64 | + target_link_libraries(basic_threaded ${LIB_REDIS}) | |
| 34 | 65 | |
| 35 | -add_executable(basic_threaded examples/basic_threaded.cpp ${SRC_ALL}) | |
| 36 | -target_link_libraries(basic_threaded ${LIB_REDIS}) | |
| 66 | + add_executable(lpush_benchmark examples/lpush_benchmark.cpp ${SRC_ALL}) | |
| 67 | + target_link_libraries(lpush_benchmark ${LIB_REDIS}) | |
| 37 | 68 | |
| 38 | -add_executable(lpush_benchmark examples/lpush_benchmark.cpp ${SRC_ALL}) | |
| 39 | -target_link_libraries(lpush_benchmark ${LIB_REDIS}) | |
| 69 | + add_executable(speed_test_async examples/speed_test_async.cpp ${SRC_ALL}) | |
| 70 | + target_link_libraries(speed_test_async ${LIB_REDIS}) | |
| 40 | 71 | |
| 41 | -add_executable(speed_test_async examples/speed_test_async.cpp ${SRC_ALL}) | |
| 42 | -target_link_libraries(speed_test_async ${LIB_REDIS}) | |
| 72 | + add_executable(speed_test_sync examples/speed_test_sync.cpp ${SRC_ALL}) | |
| 73 | + target_link_libraries(speed_test_sync ${LIB_REDIS}) | |
| 43 | 74 | |
| 44 | -add_executable(speed_test_sync examples/speed_test_sync.cpp ${SRC_ALL}) | |
| 45 | -target_link_libraries(speed_test_sync ${LIB_REDIS}) | |
| 75 | + add_executable(speed_test_async_multi examples/speed_test_async_multi.cpp ${SRC_ALL}) | |
| 76 | + target_link_libraries(speed_test_async_multi ${LIB_REDIS}) | |
| 46 | 77 | |
| 47 | -add_executable(speed_test_async_multi examples/speed_test_async_multi.cpp ${SRC_ALL}) | |
| 48 | -target_link_libraries(speed_test_async_multi ${LIB_REDIS}) | |
| 78 | + add_executable(data_types examples/data_types.cpp ${SRC_ALL}) | |
| 79 | + target_link_libraries(data_types ${LIB_REDIS}) | |
| 49 | 80 | |
| 50 | -add_executable(data_types examples/data_types.cpp ${SRC_ALL}) | |
| 51 | -target_link_libraries(data_types ${LIB_REDIS}) | |
| 81 | + add_executable(string_v_char examples/string_vs_charp.cpp ${SRC_ALL}) | |
| 82 | + target_link_libraries(string_v_char ${LIB_REDIS}) | |
| 52 | 83 | |
| 53 | -add_executable(string_v_char examples/string_vs_charp.cpp ${SRC_ALL}) | |
| 54 | -target_link_libraries(string_v_char ${LIB_REDIS}) | |
| 84 | + add_executable(multi_client examples/multi-client.cpp ${SRC_ALL}) | |
| 85 | + target_link_libraries(multi_client ${LIB_REDIS}) | |
| 55 | 86 | |
| 56 | -add_executable(multi_client examples/multi-client.cpp ${SRC_ALL}) | |
| 57 | -target_link_libraries(multi_client ${LIB_REDIS}) | |
| 87 | +endif() | ... | ... |
README.md
| ... | ... | @@ -40,6 +40,10 @@ Get the dependencies: |
| 40 | 40 | |
| 41 | 41 | sudo apt-get install libhiredis-dev libev-dev |
| 42 | 42 | |
| 43 | +For testing: | |
| 44 | + | |
| 45 | + sudo apt-get install libgtest-dev | |
| 46 | + | |
| 43 | 47 | Build Redox and examples using CMake (a helper script is provided): |
| 44 | 48 | |
| 45 | 49 | cd redox |
| ... | ... | @@ -53,14 +57,14 @@ Basic synchronous usage: |
| 53 | 57 | |
| 54 | 58 | redox::Redox rdx = {"localhost", 6379}; // Initialize Redox |
| 55 | 59 | rdx.start(); // Start the event loop |
| 56 | - | |
| 60 | + | |
| 57 | 61 | rdx.del("occupation"); |
| 58 | - | |
| 62 | + | |
| 59 | 63 | if(!rdx.set("occupation", "carpenter")) // Set a key, check if succeeded |
| 60 | 64 | cerr << "Failed to set key!" << endl; |
| 61 | - | |
| 65 | + | |
| 62 | 66 | cout << "key = occupation, value = \"" << rdx.get("occupation") << "\"" << endl; |
| 63 | - | |
| 67 | + | |
| 64 | 68 | rdx.stop(); // Shut down the event loop |
| 65 | 69 | |
| 66 | 70 | Output: `key = occupation, value = "carpenter"` | ... | ... |
test/test.cpp
0 → 100644
| 1 | +/** | |
| 2 | +* Test suite for Redox using GTest. | |
| 3 | +*/ | |
| 4 | + | |
| 5 | +#include <iostream> | |
| 6 | + | |
| 7 | +#include "../src/redox.hpp" | |
| 8 | +#include "gtest/gtest.h" | |
| 9 | + | |
| 10 | +namespace { | |
| 11 | + | |
| 12 | +using namespace redox; | |
| 13 | +using namespace std; | |
| 14 | + | |
| 15 | +// ------------------------------------------ | |
| 16 | +// The fixture for testing class Redox. | |
| 17 | +// ------------------------------------------ | |
| 18 | +class RedoxTest : public ::testing::Test { | |
| 19 | +protected: | |
| 20 | + | |
| 21 | + Redox rdx = {"localhost", 6379}; | |
| 22 | + | |
| 23 | + RedoxTest() { | |
| 24 | + rdx.start(); | |
| 25 | + } | |
| 26 | + | |
| 27 | + virtual ~RedoxTest() { | |
| 28 | + rdx.block(); | |
| 29 | + } | |
| 30 | + | |
| 31 | + // CV and counter to wait for async commands to complete | |
| 32 | + atomic_int cmd_count = {0}; | |
| 33 | + condition_variable cmd_waiter; | |
| 34 | + mutex cmd_waiter_lock; | |
| 35 | + | |
| 36 | + // To make the callback code nicer | |
| 37 | + template <class ReplyT> | |
| 38 | + using Callback = std::function<void(const std::string&, const ReplyT&)>; | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * Helper function that returns a command callback to print out the | |
| 42 | + * command/reply and to test the reply against the provided value. | |
| 43 | + */ | |
| 44 | + template<class ReplyT> | |
| 45 | + Callback<ReplyT> check(const ReplyT& value) { | |
| 46 | + cmd_count++; | |
| 47 | + return [this, value](const string& cmd, const ReplyT& reply) { | |
| 48 | + EXPECT_EQ(reply, value); | |
| 49 | + cmd_count--; | |
| 50 | + cmd_waiter.notify_all(); | |
| 51 | + }; | |
| 52 | + } | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Wrapper for the callback that also prints out the command. | |
| 56 | + */ | |
| 57 | + template<class ReplyT> | |
| 58 | + Callback<ReplyT> print(Callback<ReplyT> callback) { | |
| 59 | + return [callback](const string& cmd, const ReplyT& reply) { | |
| 60 | + cout << cmd << ": " << reply << endl; | |
| 61 | + callback(cmd, reply); | |
| 62 | + }; | |
| 63 | + } | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * Combination of print and check for simplicity. | |
| 67 | + */ | |
| 68 | + template<class ReplyT> | |
| 69 | + Callback<ReplyT> print_and_check(const ReplyT& value) { | |
| 70 | + return print(check<ReplyT>(value)); | |
| 71 | + } | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * Wait until all async commands that used check() as a callback | |
| 75 | + * complete. | |
| 76 | + */ | |
| 77 | + void wait_and_stop() { | |
| 78 | + unique_lock<mutex> ul(cmd_waiter_lock); | |
| 79 | + cmd_waiter.wait(ul, [this] { return (cmd_count == 0); }); | |
| 80 | + rdx.stop_signal(); | |
| 81 | + }; | |
| 82 | +}; | |
| 83 | + | |
| 84 | +// ------------------------------------------- | |
| 85 | +// Unit tests - asynchronous | |
| 86 | +// ------------------------------------------- | |
| 87 | + | |
| 88 | +TEST_F(RedoxTest, GetSet) { | |
| 89 | + rdx.command<string>("SET redox_test:a apple", print_and_check<string>("OK")); | |
| 90 | + rdx.command<string>("GET redox_test:a", print_and_check<string>("apple")); | |
| 91 | + wait_and_stop(); | |
| 92 | +} | |
| 93 | + | |
| 94 | +TEST_F(RedoxTest, Delete) { | |
| 95 | + rdx.command<string>("SET redox_test:b banana", print_and_check<string>("OK")); | |
| 96 | + rdx.command<int>("DEL redox_test:b", print_and_check(1)); | |
| 97 | + rdx.command<nullptr_t>("GET redox_test:b", check(nullptr)); | |
| 98 | + wait_and_stop(); | |
| 99 | +} | |
| 100 | + | |
| 101 | +// ------------------------------------------- | |
| 102 | +// End tests | |
| 103 | +// ------------------------------------------- | |
| 104 | + | |
| 105 | +} // namespace | |
| 106 | + | |
| 107 | +int main(int argc, char **argv) { | |
| 108 | + ::testing::InitGoogleTest(&argc, argv); | |
| 109 | + return RUN_ALL_TESTS(); | |
| 110 | +} | ... | ... |