Commit 53cd7adf47ca3e001d841bb70d3e9dd979d4cecb

Authored by Bram Veldhoen
1 parent 79560cbc

Added lastError() to Command.

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&lt;ReplyT&gt;::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&lt;ReplyT&gt;::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&lt;ReplyT&gt;::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&lt;ReplyT&gt;::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&lt;class ReplyT&gt;
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 // -------------------------------------------
... ...