Commit 53cd7adf47ca3e001d841bb70d3e9dd979d4cecb

Authored by Bram Veldhoen
1 parent 79560cbc

Added lastError() to Command.

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&lt;ReplyT&gt;::wait() { @@ -51,11 +51,13 @@ void Command&lt;ReplyT&gt;::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&lt;ReplyT&gt;::reply() { @@ -121,7 +123,7 @@ ReplyT Command&lt;ReplyT&gt;::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&lt;ReplyT&gt;::isExpectedReply(int type) { @@ -133,8 +135,11 @@ bool Command&lt;ReplyT&gt;::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&lt;ReplyT&gt;::isExpectedReply(int typeA, int typeB) { @@ -149,8 +154,11 @@ bool Command&lt;ReplyT&gt;::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&lt;class ReplyT&gt; @@ -159,7 +167,8 @@ template&lt;class ReplyT&gt;
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 // -------------------------------------------