Commit 53cd7adf47ca3e001d841bb70d3e9dd979d4cecb
1 parent
79560cbc
Added lastError() to Command.
Showing
3 changed files
with
61 additions
and
10 deletions
include/redox/command.hpp
| @@ -61,6 +61,8 @@ public: | @@ -61,6 +61,8 @@ public: | ||
| 61 | */ | 61 | */ |
| 62 | int status() const { return reply_status_; } | 62 | int status() const { return reply_status_; } |
| 63 | 63 | ||
| 64 | + std::string lastError() const { return last_error_; } | ||
| 65 | + | ||
| 64 | /** | 66 | /** |
| 65 | * Returns true if this command got a successful reply. | 67 | * Returns true if this command got a successful reply. |
| 66 | */ | 68 | */ |
| @@ -138,6 +140,7 @@ private: | @@ -138,6 +140,7 @@ private: | ||
| 138 | // Place to store the reply value and status. | 140 | // Place to store the reply value and status. |
| 139 | ReplyT reply_val_; | 141 | ReplyT reply_val_; |
| 140 | std::atomic_int reply_status_; | 142 | std::atomic_int reply_status_; |
| 143 | + std::string last_error_; | ||
| 141 | 144 | ||
| 142 | // How many messages sent to server but not received reply | 145 | // How many messages sent to server but not received reply |
| 143 | std::atomic_int pending_ = {0}; | 146 | std::atomic_int pending_ = {0}; |
src/command.cpp
| @@ -37,7 +37,7 @@ Command<ReplyT>::Command( | @@ -37,7 +37,7 @@ Command<ReplyT>::Command( | ||
| 37 | const std::function<void(Command<ReplyT>&)>& callback, | 37 | const std::function<void(Command<ReplyT>&)>& callback, |
| 38 | double repeat, double after, bool free_memory, log::Logger& logger | 38 | double repeat, double after, bool free_memory, log::Logger& logger |
| 39 | ) : rdx_(rdx), id_(id), cmd_(cmd), repeat_(repeat), after_(after), free_memory_(free_memory), | 39 | ) : rdx_(rdx), id_(id), cmd_(cmd), repeat_(repeat), after_(after), free_memory_(free_memory), |
| 40 | - callback_(callback), logger_(logger) { | 40 | + callback_(callback), last_error_(), logger_(logger) { |
| 41 | timer_guard_.lock(); | 41 | timer_guard_.lock(); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| @@ -51,11 +51,13 @@ void Command<ReplyT>::wait() { | @@ -51,11 +51,13 @@ void Command<ReplyT>::wait() { | ||
| 51 | template<class ReplyT> | 51 | template<class ReplyT> |
| 52 | void Command<ReplyT>::processReply(redisReply* r) { | 52 | void Command<ReplyT>::processReply(redisReply* r) { |
| 53 | 53 | ||
| 54 | + last_error_.clear(); | ||
| 54 | reply_obj_ = r; | 55 | reply_obj_ = r; |
| 55 | 56 | ||
| 56 | if(reply_obj_ == nullptr) { | 57 | if(reply_obj_ == nullptr) { |
| 57 | reply_status_ = ERROR_REPLY; | 58 | reply_status_ = ERROR_REPLY; |
| 58 | - logger_.error() << "Received null redisReply* from hiredis."; | 59 | + last_error_ = "Received null redisReply* from hiredis."; |
| 60 | + logger_.error() << last_error_; | ||
| 59 | Redox::disconnectedCallback(rdx_->ctx_, REDIS_ERR); | 61 | Redox::disconnectedCallback(rdx_->ctx_, REDIS_ERR); |
| 60 | 62 | ||
| 61 | } else { | 63 | } else { |
| @@ -121,7 +123,7 @@ ReplyT Command<ReplyT>::reply() { | @@ -121,7 +123,7 @@ ReplyT Command<ReplyT>::reply() { | ||
| 121 | template<class ReplyT> | 123 | template<class ReplyT> |
| 122 | std::string Command<ReplyT>::cmd() const { | 124 | std::string Command<ReplyT>::cmd() const { |
| 123 | return rdx_->vecToStr(cmd_); | 125 | return rdx_->vecToStr(cmd_); |
| 124 | -}; | 126 | +} |
| 125 | 127 | ||
| 126 | template<class ReplyT> | 128 | template<class ReplyT> |
| 127 | bool Command<ReplyT>::isExpectedReply(int type) { | 129 | bool Command<ReplyT>::isExpectedReply(int type) { |
| @@ -133,8 +135,11 @@ bool Command<ReplyT>::isExpectedReply(int type) { | @@ -133,8 +135,11 @@ bool Command<ReplyT>::isExpectedReply(int type) { | ||
| 133 | 135 | ||
| 134 | if(checkErrorReply() || checkNilReply()) return false; | 136 | if(checkErrorReply() || checkNilReply()) return false; |
| 135 | 137 | ||
| 136 | - logger_.error() << cmd() << ": Received reply of type " << reply_obj_->type | ||
| 137 | - << ", expected type " << type << "."; | 138 | + std::stringstream errorMessage; |
| 139 | + errorMessage << "Received reply of type " << reply_obj_->type | ||
| 140 | + << ", expected type " << type << "."; | ||
| 141 | + last_error_ = errorMessage.str(); | ||
| 142 | + logger_.error() << cmd() << ": " << last_error_; | ||
| 138 | reply_status_ = WRONG_TYPE; | 143 | reply_status_ = WRONG_TYPE; |
| 139 | return false; | 144 | return false; |
| 140 | } | 145 | } |
| @@ -149,8 +154,11 @@ bool Command<ReplyT>::isExpectedReply(int typeA, int typeB) { | @@ -149,8 +154,11 @@ bool Command<ReplyT>::isExpectedReply(int typeA, int typeB) { | ||
| 149 | 154 | ||
| 150 | if(checkErrorReply() || checkNilReply()) return false; | 155 | if(checkErrorReply() || checkNilReply()) return false; |
| 151 | 156 | ||
| 152 | - logger_.error() << cmd() << ": Received reply of type " << reply_obj_->type | ||
| 153 | - << ", expected type " << typeA << " or " << typeB << "."; | 157 | + std::stringstream errorMessage; |
| 158 | + errorMessage << "Received reply of type " << reply_obj_->type | ||
| 159 | + << ", expected type " << typeA << " or " << typeB << "."; | ||
| 160 | + last_error_ = errorMessage.str(); | ||
| 161 | + logger_.error() << cmd() << ": " << last_error_; | ||
| 154 | reply_status_ = WRONG_TYPE; | 162 | reply_status_ = WRONG_TYPE; |
| 155 | return false; | 163 | return false; |
| 156 | } | 164 | } |
| @@ -159,7 +167,8 @@ template<class ReplyT> | @@ -159,7 +167,8 @@ template<class ReplyT> | ||
| 159 | bool Command<ReplyT>::checkErrorReply() { | 167 | bool Command<ReplyT>::checkErrorReply() { |
| 160 | 168 | ||
| 161 | if (reply_obj_->type == REDIS_REPLY_ERROR) { | 169 | if (reply_obj_->type == REDIS_REPLY_ERROR) { |
| 162 | - logger_.error() << cmd() << ": " << reply_obj_->str; | 170 | + last_error_ = reply_obj_->str; |
| 171 | + logger_.error() << cmd() << ": " << last_error_; | ||
| 163 | reply_status_ = ERROR_REPLY; | 172 | reply_status_ = ERROR_REPLY; |
| 164 | return true; | 173 | return true; |
| 165 | } | 174 | } |
test/test.cpp
| @@ -67,7 +67,7 @@ protected: | @@ -67,7 +67,7 @@ protected: | ||
| 67 | cmd_count++; | 67 | cmd_count++; |
| 68 | return [this, value](Command<ReplyT>& c) { | 68 | return [this, value](Command<ReplyT>& c) { |
| 69 | EXPECT_TRUE(c.ok()); | 69 | EXPECT_TRUE(c.ok()); |
| 70 | - if(c.ok()) EXPECT_EQ(c.reply(), value); | 70 | + if(c.ok()) EXPECT_EQ(value, c.reply()); |
| 71 | cmd_count--; | 71 | cmd_count--; |
| 72 | cmd_waiter.notify_all(); | 72 | cmd_waiter.notify_all(); |
| 73 | }; | 73 | }; |
| @@ -93,6 +93,22 @@ protected: | @@ -93,6 +93,22 @@ protected: | ||
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | /** | 95 | /** |
| 96 | + * Check the error | ||
| 97 | + */ | ||
| 98 | + template<class ReplyT> | ||
| 99 | + Callback<ReplyT> print_and_check_error(const ReplyT& value) { | ||
| 100 | + cmd_count++; | ||
| 101 | + return [this, value](Command<ReplyT>& c) { | ||
| 102 | + EXPECT_FALSE(c.ok()); | ||
| 103 | + EXPECT_FALSE(c.lastError().empty()); | ||
| 104 | +// EXPECT_EQ(value, c.reply()); | ||
| 105 | + cout << c.cmd() << ": " << c.lastError() << endl; | ||
| 106 | + cmd_count--; | ||
| 107 | + cmd_waiter.notify_all(); | ||
| 108 | + }; | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + /** | ||
| 96 | * Wait until all async commands that used check() as a callback | 112 | * Wait until all async commands that used check() as a callback |
| 97 | * complete. | 113 | * complete. |
| 98 | */ | 114 | */ |
| @@ -100,7 +116,7 @@ protected: | @@ -100,7 +116,7 @@ protected: | ||
| 100 | unique_lock<mutex> ul(cmd_waiter_lock); | 116 | unique_lock<mutex> ul(cmd_waiter_lock); |
| 101 | cmd_waiter.wait(ul, [this] { return (cmd_count == 0); }); | 117 | cmd_waiter.wait(ul, [this] { return (cmd_count == 0); }); |
| 102 | rdx.disconnect(); | 118 | rdx.disconnect(); |
| 103 | - }; | 119 | + } |
| 104 | 120 | ||
| 105 | template<class ReplyT> | 121 | template<class ReplyT> |
| 106 | void check_sync(Command<ReplyT>& c, const ReplyT& value) { | 122 | void check_sync(Command<ReplyT>& c, const ReplyT& value) { |
| @@ -116,6 +132,17 @@ protected: | @@ -116,6 +132,17 @@ protected: | ||
| 116 | cout << "[SYNC] " << c.cmd() << ": " << c.reply() << endl; | 132 | cout << "[SYNC] " << c.cmd() << ": " << c.reply() << endl; |
| 117 | c.free(); | 133 | c.free(); |
| 118 | } | 134 | } |
| 135 | + | ||
| 136 | + /** | ||
| 137 | + * Check the error | ||
| 138 | + */ | ||
| 139 | + template<class ReplyT> | ||
| 140 | + void print_and_check_error_sync(Command<ReplyT>& c, const ReplyT& value) { | ||
| 141 | + EXPECT_FALSE(c.ok()); | ||
| 142 | + EXPECT_FALSE(c.lastError().empty()); | ||
| 143 | +// EXPECT_EQ(value, c.reply()); | ||
| 144 | + cout << c.cmd() << ": " << c.lastError() << endl; | ||
| 145 | + } | ||
| 119 | }; | 146 | }; |
| 120 | 147 | ||
| 121 | // ------------------------------------------- | 148 | // ------------------------------------------- |
| @@ -170,6 +197,12 @@ TEST_F(RedoxTest, Loop) { | @@ -170,6 +197,12 @@ TEST_F(RedoxTest, Loop) { | ||
| 170 | wait_for_replies(); | 197 | wait_for_replies(); |
| 171 | } | 198 | } |
| 172 | 199 | ||
| 200 | +TEST_F(RedoxTest, GetSetError) { | ||
| 201 | + rdx.command<string>({"SET", "redox_test:a", "apple"}, print_and_check<string>("OK")); | ||
| 202 | + rdx.command<int>({"GET", "redox_test:a"}, print_and_check_error<int>(3)); | ||
| 203 | + wait_for_replies(); | ||
| 204 | +} | ||
| 205 | + | ||
| 173 | // ------------------------------------------- | 206 | // ------------------------------------------- |
| 174 | // Core unit tests - synchronous | 207 | // Core unit tests - synchronous |
| 175 | // ------------------------------------------- | 208 | // ------------------------------------------- |
| @@ -196,6 +229,12 @@ TEST_F(RedoxTest, IncrSync) { | @@ -196,6 +229,12 @@ TEST_F(RedoxTest, IncrSync) { | ||
| 196 | rdx.disconnect(); | 229 | rdx.disconnect(); |
| 197 | } | 230 | } |
| 198 | 231 | ||
| 232 | +TEST_F(RedoxTest, GetSetSyncError) { | ||
| 233 | + print_and_check_sync<string>(rdx.commandSync<string>({"SET", "redox_test:a", "apple"}), "OK"); | ||
| 234 | + print_and_check_error_sync<int>(rdx.commandSync<int>({"GET", "redox_test:a"}), 3); | ||
| 235 | + rdx.disconnect(); | ||
| 236 | +} | ||
| 237 | + | ||
| 199 | // ------------------------------------------- | 238 | // ------------------------------------------- |
| 200 | // End tests | 239 | // End tests |
| 201 | // ------------------------------------------- | 240 | // ------------------------------------------- |