Skip to content

Commit

Permalink
Merge pull request #4 from cblauvelt:cblauvelt/issue3
Browse files Browse the repository at this point in the history
Add support for Auth
  • Loading branch information
cblauvelt authored Feb 9, 2022
2 parents 5a6c764 + cabc1ca commit 05bcb0f
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 16 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ build/**
*.app

# Testing
Testing/
Testing/
.env
6 changes: 6 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,11 @@
"command": "rm -rf build/*",
"problemMatcher": []
},
{
"label": "Conan Create",
"type": "shell",
"command": "conan create .",
"problemMatcher": []
},
]
}
2 changes: 1 addition & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class RedisClientConan(ConanFile):
exports_sources = ["CMakeLists.txt", "conan.cmake", "conanfile.py", "include/*", "src/*", "test/*"]
generators = "cmake"
settings = "os", "arch", "compiler", "build_type"
requires = "cpool/0.9.4", "boost/1.78.0", "openssl/1.1.1m", "fmt/8.1.1"
requires = "cpool/0.9.5", "boost/1.78.0", "openssl/1.1.1m", "fmt/8.1.1"
build_requires = "gtest/cci.20210126"
options = {"cxx_standard": [20], "build_testing": [True, False]}
default_options = {"cxx_standard": 20, "build_testing": True}
Expand Down
29 changes: 29 additions & 0 deletions include/redis_client_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ struct redis_client_config {
/// disconnect from the server will be attempted again
bool rety_failed_commands;

/// username Used for authentication with the redis server. If password is
/// defined and username is blank, it is set to "default".
std::string username;

/// password Used for authentication with the redis server
std::string password;

/// Creates a configuration with default parameters
redis_client_config()
: host("127.0.0.1")
Expand Down Expand Up @@ -55,6 +62,28 @@ struct redis_client_config {
return *this;
}

/**
* @brief Sets the username of the server.
* @param username The username to authenticate with the redis server.
* @returns The configuration object so subsequent commands to set methods
* can be chained.
*/
redis_client_config set_username(std::string username) {
this->username = username;
return *this;
}

/**
* @brief Sets the password of the server.
* @param password The password to authenticate with the redis server.
* @returns The configuration object so subsequent commands to set methods
* can be chained.
*/
redis_client_config set_password(std::string password) {
this->password = password;
return *this;
}

/**
* @brief Sets the maximum connections in the connection pool.
* @param num_connections The max number of connections.
Expand Down
35 changes: 33 additions & 2 deletions src/redis_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,39 @@ redis_client::redis_client(cpool::net::any_io_executor exec,
, state_(state::not_running) {

auto conn_creator = [&]() -> std::unique_ptr<cpool::tcp_connection> {
return std::make_unique<cpool::tcp_connection>(exec_, config_.host,
config_.port);
auto conn = std::make_unique<cpool::tcp_connection>(exec_, config_.host,
config_.port);
if (!config_.password.empty()) {
if (config_.username.empty()) {
config_.username = "default";
}

// login when a connection is created
conn->set_state_change_handler(
[&](cpool::tcp_connection* conn,
const cpool::client_connection_state state)
-> awaitable<cpool::error> {
if (state == cpool::client_connection_state::connected) {
auto username = this->config().username;
auto password = this->config().password;
auto loginCmd = redis_command(std::vector<std::string>{
"AUTH", username, password});

this->log_message(redis::log_level::trace,
"AUTH password");
auto reply = co_await this->send(conn, loginCmd);
if (reply.error()) {
this->log_message(redis::log_level::error,
reply.error().message());
}
co_return reply.error();
}

co_return cpool::error();
});
}

return conn;
};

con_pool_ = std::make_unique<cpool::connection_pool<cpool::tcp_connection>>(
Expand Down
72 changes: 66 additions & 6 deletions test/redis_client_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <string>
#include <vector>

#include <fmt/format.h>

#include "commands-json.hpp"
#include "commands.hpp"
#include "redis_client.hpp"
Expand All @@ -15,9 +17,12 @@ namespace {

using namespace redis;

std::string get_env_var(std::string const& key) {
const std::string DEFAULT_REDIS_HOST = "host.docker.internal";
const std::string DEFAULT_REDIS_PORT = "6379";

std::optional<std::string> get_env_var(std::string const& key) {
char* val = getenv(key.c_str());
return val == NULL ? std::string("redis") : std::string(val);
return (val == NULL) ? std::nullopt : std::optional(std::string(val));
}

void testForError(std::string cmd, const redis::redis_reply& reply) {
Expand Down Expand Up @@ -128,7 +133,7 @@ awaitable<void> test_basic(redis_client& client, int c,
awaitable<void> run_tests(asio::io_context& ctx) {
std::atomic<int> barrier;
auto exec = co_await cpool::net::this_coro::executor;
auto host = get_env_var("REDIS_HOST");
auto host = get_env_var("REDIS_HOST").value_or(DEFAULT_REDIS_HOST);

logMessage(redis::log_level::info, host);
redis_client client(exec, host, 6379);
Expand All @@ -147,7 +152,46 @@ awaitable<void> run_tests(asio::io_context& ctx) {

while (barrier != 0) {
cpool::timer timer(exec);
co_await timer.async_wait(std::chrono::milliseconds(100));
co_await timer.async_wait(100ms);
}

ctx.stop();
co_return;
}

awaitable<void> run_password_tests(asio::io_context& ctx) {
std::atomic<int> barrier;
auto exec = co_await cpool::net::this_coro::executor;
auto host = get_env_var("REDIS_PASSWORD_HOST").value_or(DEFAULT_REDIS_HOST);
auto portString =
get_env_var("REDIS_PASSWORD_PORT").value_or(DEFAULT_REDIS_PORT);
int port = std::stoi(portString);
auto password = get_env_var("REDIS_PASSWORD").value_or("");
auto config =
redis_client_config{}.set_host(host).set_port(port).set_password(
password);

logMessage(redis::log_level::info,
fmt::format("Logging into {}:{} with password {}", config.host,
config.port, config.password));

redis_client client(exec, config);
client.set_logging_handler(
std::bind(logMessage, std::placeholders::_1, std::placeholders::_2));

auto reply = co_await client.ping();
testForString("PING", reply, "PONG");
EXPECT_TRUE(client.running());

barrier = 2;
int num_runners = barrier;
for (int i = 0; i < num_runners; i++) {
cpool::co_spawn(ctx, test_basic(client, i, barrier), cpool::detached);
}

while (barrier != 0) {
cpool::timer timer(exec);
co_await timer.async_wait(100ms);
}

ctx.stop();
Expand Down Expand Up @@ -276,7 +320,7 @@ awaitable<void> test_json(redis_client& client, int c,
awaitable<void> run_json_tests(asio::io_context& ctx) {
std::atomic<int> barrier;
auto exec = co_await cpool::net::this_coro::executor;
auto host = get_env_var("REDIS_HOST");
auto host = get_env_var("REDIS_HOST").value_or(DEFAULT_REDIS_HOST);
redis_client client(exec, host, 6379);
client.set_logging_handler(
std::bind(logMessage, std::placeholders::_1, std::placeholders::_2));
Expand All @@ -289,7 +333,7 @@ awaitable<void> run_json_tests(asio::io_context& ctx) {

while (barrier != 0) {
cpool::timer timer(exec);
co_await timer.async_wait(std::chrono::milliseconds(100));
co_await timer.async_wait(100ms);
}

auto reply = co_await client.send(flush_all());
Expand All @@ -307,6 +351,22 @@ TEST(Redis, ClientTest) {
ctx.run();
}

TEST(Redis, MultiClientTest) {
asio::io_context ctx(8);

cpool::co_spawn(ctx, run_tests(std::ref(ctx)), cpool::detached);

ctx.run();
}

TEST(Redis, PasswordClientTest) {
asio::io_context ctx(1);

cpool::co_spawn(ctx, run_password_tests(std::ref(ctx)), cpool::detached);

ctx.run();
}

TEST(Redis, JsonTest) {
asio::io_context ctx(1);

Expand Down
8 changes: 5 additions & 3 deletions test/redis_sub_connection_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ namespace {
using string = std::string;
using namespace redis;

std::string get_env_var(std::string const& key) {
const std::string DEFAULT_REDIS_HOST = "host.docker.internal";

std::optional<std::string> get_env_var(std::string const& key) {
char* val = getenv(key.c_str());
return val == NULL ? std::string("redis") : std::string(val);
return (val == NULL) ? std::nullopt : std::optional(std::string(val));
}

awaitable<void> logMessage(log_level target, log_level level,
Expand Down Expand Up @@ -62,7 +64,7 @@ awaitable<void> connect_and_hold(redis_subscriber_connection& connection,

awaitable<void> run_tests(asio::io_context& ctx) {
auto exec = co_await cpool::net::this_coro::executor;
auto host = get_env_var("REDIS_HOST");
auto host = get_env_var("REDIS_HOST").value_or(DEFAULT_REDIS_HOST);
std::atomic_int barrier(1);

redis_subscriber_connection connection(exec, host, 6379);
Expand Down
8 changes: 5 additions & 3 deletions test/redis_sub_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ namespace {
using string = std::string;
using namespace redis;

std::string get_env_var(std::string const& key) {
const std::string DEFAULT_REDIS_HOST = "host.docker.internal";

std::optional<std::string> get_env_var(std::string const& key) {
char* val = getenv(key.c_str());
return val == NULL ? std::string("redis") : std::string(val);
return (val == NULL) ? std::nullopt : std::optional(std::string(val));
}

void testForError(std::string cmd, const redis::redis_reply& reply) {
Expand Down Expand Up @@ -144,7 +146,7 @@ awaitable<void> publish_messages(redis_client& client, std::string channel,
awaitable<void> run_tests(asio::io_context& ctx) {
std::atomic<int> barrier;
auto exec = co_await cpool::net::this_coro::executor;
auto host = get_env_var("REDIS_HOST");
auto host = get_env_var("REDIS_HOST").value_or(DEFAULT_REDIS_HOST);

redis_client client(exec, host, 6379);
redis_subscriber subscriber(exec, host, 6379);
Expand Down

0 comments on commit 05bcb0f

Please sign in to comment.