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 | 61 | */ |
| 62 | 62 | int status() const { return reply_status_; } |
| 63 | 63 | |
| 64 | + std::string lastError() const { return last_error_; } | |
| 65 | + | |
| 64 | 66 | /** |
| 65 | 67 | * Returns true if this command got a successful reply. |
| 66 | 68 | */ |
| ... | ... | @@ -138,6 +140,7 @@ private: |
| 138 | 140 | // Place to store the reply value and status. |
| 139 | 141 | ReplyT reply_val_; |
| 140 | 142 | std::atomic_int reply_status_; |
| 143 | + std::string last_error_; | |
| 141 | 144 | |
| 142 | 145 | // How many messages sent to server but not received reply |
| 143 | 146 | std::atomic_int pending_ = {0}; | ... | ... |
src/command.cpp
| ... | ... | @@ -37,7 +37,7 @@ Command<ReplyT>::Command( |
| 37 | 37 | const std::function<void(Command<ReplyT>&)>& callback, |
| 38 | 38 | double repeat, double after, bool free_memory, log::Logger& logger |
| 39 | 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 | 41 | timer_guard_.lock(); |
| 42 | 42 | } |
| 43 | 43 | |
| ... | ... | @@ -51,11 +51,13 @@ void Command<ReplyT>::wait() { |
| 51 | 51 | template<class ReplyT> |
| 52 | 52 | void Command<ReplyT>::processReply(redisReply* r) { |
| 53 | 53 | |
| 54 | + last_error_.clear(); | |
| 54 | 55 | reply_obj_ = r; |
| 55 | 56 | |
| 56 | 57 | if(reply_obj_ == nullptr) { |
| 57 | 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 | 61 | Redox::disconnectedCallback(rdx_->ctx_, REDIS_ERR); |
| 60 | 62 | |
| 61 | 63 | } else { |
| ... | ... | @@ -121,7 +123,7 @@ ReplyT Command<ReplyT>::reply() { |
| 121 | 123 | template<class ReplyT> |
| 122 | 124 | std::string Command<ReplyT>::cmd() const { |
| 123 | 125 | return rdx_->vecToStr(cmd_); |
| 124 | -}; | |
| 126 | +} | |
| 125 | 127 | |
| 126 | 128 | template<class ReplyT> |
| 127 | 129 | bool Command<ReplyT>::isExpectedReply(int type) { |
| ... | ... | @@ -133,8 +135,11 @@ bool Command<ReplyT>::isExpectedReply(int type) { |
| 133 | 135 | |
| 134 | 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 | 143 | reply_status_ = WRONG_TYPE; |
| 139 | 144 | return false; |
| 140 | 145 | } |
| ... | ... | @@ -149,8 +154,11 @@ bool Command<ReplyT>::isExpectedReply(int typeA, int typeB) { |
| 149 | 154 | |
| 150 | 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 | 162 | reply_status_ = WRONG_TYPE; |
| 155 | 163 | return false; |
| 156 | 164 | } |
| ... | ... | @@ -159,7 +167,8 @@ template<class ReplyT> |
| 159 | 167 | bool Command<ReplyT>::checkErrorReply() { |
| 160 | 168 | |
| 161 | 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 | 172 | reply_status_ = ERROR_REPLY; |
| 164 | 173 | return true; |
| 165 | 174 | } | ... | ... |
test/test.cpp
| ... | ... | @@ -67,7 +67,7 @@ protected: |
| 67 | 67 | cmd_count++; |
| 68 | 68 | return [this, value](Command<ReplyT>& c) { |
| 69 | 69 | EXPECT_TRUE(c.ok()); |
| 70 | - if(c.ok()) EXPECT_EQ(c.reply(), value); | |
| 70 | + if(c.ok()) EXPECT_EQ(value, c.reply()); | |
| 71 | 71 | cmd_count--; |
| 72 | 72 | cmd_waiter.notify_all(); |
| 73 | 73 | }; |
| ... | ... | @@ -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 | 112 | * Wait until all async commands that used check() as a callback |
| 97 | 113 | * complete. |
| 98 | 114 | */ |
| ... | ... | @@ -100,7 +116,7 @@ protected: |
| 100 | 116 | unique_lock<mutex> ul(cmd_waiter_lock); |
| 101 | 117 | cmd_waiter.wait(ul, [this] { return (cmd_count == 0); }); |
| 102 | 118 | rdx.disconnect(); |
| 103 | - }; | |
| 119 | + } | |
| 104 | 120 | |
| 105 | 121 | template<class ReplyT> |
| 106 | 122 | void check_sync(Command<ReplyT>& c, const ReplyT& value) { |
| ... | ... | @@ -116,6 +132,17 @@ protected: |
| 116 | 132 | cout << "[SYNC] " << c.cmd() << ": " << c.reply() << endl; |
| 117 | 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 | 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 | 207 | // Core unit tests - synchronous |
| 175 | 208 | // ------------------------------------------- |
| ... | ... | @@ -196,6 +229,12 @@ TEST_F(RedoxTest, IncrSync) { |
| 196 | 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 | 239 | // End tests |
| 201 | 240 | // ------------------------------------------- | ... | ... |