2 Copyright (c) 2018-2019 Nokia.
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 #include <type_traits>
20 #include <sys/epoll.h>
21 #include <sys/timerfd.h>
22 #include <sys/eventfd.h>
23 #include <arpa/inet.h>
24 #include <gtest/gtest.h>
26 #include "private/createlogger.hpp"
27 #include "private/error.hpp"
28 #include "private/logger.hpp"
29 #include "private/redis/asynchirediscommanddispatcher.hpp"
30 #include "private/redis/reply.hpp"
31 #include "private/redis/contents.hpp"
32 #include "private/timer.hpp"
33 #include "private/tst/contentsbuildermock.hpp"
34 #include "private/tst/enginemock.hpp"
35 #include "private/tst/hiredissystemmock.hpp"
36 #include "private/tst/hiredisepolladaptermock.hpp"
37 #include "private/tst/redisreplybuilder.hpp"
39 using namespace shareddatalayer;
40 using namespace shareddatalayer::redis;
41 using namespace shareddatalayer::tst;
42 using namespace testing;
46 class AsyncHiredisCommandDispatcherBaseTest: public testing::Test
49 std::shared_ptr<ContentsBuilderMock> contentsBuilderMock;
50 StrictMock<EngineMock> engineMock;
51 HiredisSystemMock hiredisSystemMock;
52 std::shared_ptr<HiredisEpollAdapterMock> adapterMock;
55 std::unique_ptr<AsyncHiredisCommandDispatcher> dispatcher;
56 void (*connected)(const redisAsyncContext*, int);
57 void (*disconnected)(const redisAsyncContext*, int);
58 Timer::Callback savedConnectionRetryTimerCallback;
59 Timer::Duration expectedConnectionRetryTimerDuration;
60 Timer::Duration expectedConnectionVerificationRetryTimerDuration;
61 RedisReplyBuilder redisReplyBuilder;
62 const AsyncConnection::Namespace defaultNamespace;
63 std::shared_ptr<Logger> logger;
65 AsyncHiredisCommandDispatcherBaseTest():
66 contentsBuilderMock(std::make_shared<ContentsBuilderMock>(AsyncConnection::SEPARATOR)),
67 adapterMock(std::make_shared<HiredisEpollAdapterMock>(engineMock, hiredisSystemMock)),
71 disconnected(nullptr),
72 expectedConnectionRetryTimerDuration(std::chrono::seconds(1)),
73 expectedConnectionVerificationRetryTimerDuration(std::chrono::seconds(10)),
74 redisReplyBuilder { },
75 defaultNamespace("namespace"),
76 logger(createLogger(SDL_LOG_PREFIX))
80 virtual ~AsyncHiredisCommandDispatcherBaseTest()
84 MOCK_METHOD0(connectAck, void());
86 MOCK_METHOD0(disconnectCallback, void());
88 MOCK_METHOD2(ack, void(const std::error_code&, const Reply&));
90 void expectationsUntilConnect()
92 expectationsUntilConnect(ac);
95 void expectationsUntilConnect(redisAsyncContext& ac)
97 expectRedisAsyncConnect(ac);
100 void expectRedisAsyncConnect()
102 expectRedisAsyncConnect(ac);
105 void expectRedisAsyncConnect(redisAsyncContext& ac)
107 EXPECT_CALL(hiredisSystemMock, redisAsyncConnect(StrEq("host"), 6379U))
109 .WillOnce(InvokeWithoutArgs([this, &ac]()
116 void expectRedisAsyncConnectReturnNullptr()
118 EXPECT_CALL(hiredisSystemMock, redisAsyncConnect(StrEq("host"), 6379U))
120 .WillOnce(InvokeWithoutArgs([this]()
127 void expectRedisAsyncSetConnectCallback()
129 expectRedisAsyncSetConnectCallback(ac);
132 void expectRedisAsyncSetConnectCallback(redisAsyncContext& ac)
134 EXPECT_CALL(hiredisSystemMock, redisAsyncSetConnectCallback(&ac, _))
136 .WillOnce(Invoke([this](const redisAsyncContext*, redisConnectCallback* cb)
143 void expectRedisAsyncSetDisconnectCallback()
145 expectRedisAsyncSetDisconnectCallback(ac);
148 void expectRedisAsyncSetDisconnectCallback(redisAsyncContext& ac)
150 EXPECT_CALL(hiredisSystemMock, redisAsyncSetDisconnectCallback(&ac, _))
152 .WillOnce(Invoke([this](const redisAsyncContext*, redisDisconnectCallback* cb)
159 void expectAdapterAttach()
161 expectAdapterAttach(ac);
164 void expectAdapterAttach(redisAsyncContext& ac)
166 EXPECT_CALL(*adapterMock, attach(&ac))
170 void expectConnectAck()
172 EXPECT_CALL(*this, connectAck())
176 void expectDisconnectCallback()
178 EXPECT_CALL(*this, disconnectCallback())
182 void expectRedisAsyncFree()
184 EXPECT_CALL(hiredisSystemMock, redisAsyncFree(&ac))
188 void expectRedisAsyncDisconnect()
190 EXPECT_CALL(hiredisSystemMock, redisAsyncDisconnect(&ac))
194 void expectRedisAsyncCommandArgv(redisReply& rr)
196 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
198 .WillOnce(Invoke([&rr](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
199 int, const char**, const size_t*)
206 void expectCommandListQuery()
208 expectRedisAsyncCommandArgv(redisReplyBuilder.buildCommandListQueryReply());
211 void expectCommandListQueryReturnError()
213 expectRedisAsyncCommandArgv(redisReplyBuilder.buildErrorReply("SomeErrorForCommandListQuery"));
216 void verifyAckErrorReply(const Reply& reply)
218 EXPECT_EQ(Reply::Type::NIL, reply.getType());
219 EXPECT_EQ(0, reply.getInteger());
220 EXPECT_TRUE(reply.getString()->str.empty());
221 EXPECT_EQ(static_cast<ReplyStringLength>(0), reply.getString()->len);
222 EXPECT_TRUE(reply.getArray()->empty());
225 void expectAckError()
227 EXPECT_CALL(*this, ack(Ne(std::error_code()), _))
229 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
231 verifyAckErrorReply(reply);
235 void expectAckError(const std::error_code& ec)
237 EXPECT_CALL(*this, ack(ec, _))
239 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
241 verifyAckErrorReply(reply);
245 void expectArmConnectionRetryTimer()
247 EXPECT_CALL(engineMock, armTimer(_, expectedConnectionRetryTimerDuration, _))
249 .WillOnce(SaveArg<2>(&savedConnectionRetryTimerCallback));
252 void expectArmConnectionVerificationRetryTimer()
254 EXPECT_CALL(engineMock, armTimer(_, expectedConnectionVerificationRetryTimerDuration, _))
256 .WillOnce(SaveArg<2>(&savedConnectionRetryTimerCallback));
259 void expectDisarmConnectionRetryTimer()
261 EXPECT_CALL(engineMock, disarmTimer(_))
266 class AsyncHiredisCommandDispatcherDisconnectedTest: public AsyncHiredisCommandDispatcherBaseTest
269 AsyncHiredisCommandDispatcherDisconnectedTest()
272 expectationsUntilConnect();
273 expectAdapterAttach();
274 expectRedisAsyncSetConnectCallback();
275 expectRedisAsyncSetDisconnectCallback();
276 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
286 ~AsyncHiredisCommandDispatcherDisconnectedTest()
291 class AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest: public AsyncHiredisCommandDispatcherBaseTest
294 AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest()
297 expectationsUntilConnect();
298 expectAdapterAttach();
299 expectRedisAsyncSetConnectCallback();
300 expectRedisAsyncSetDisconnectCallback();
301 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
311 ~AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest()
313 expectRedisAsyncFree();
317 class AsyncHiredisCommandDispatcherConnectedTest: public AsyncHiredisCommandDispatcherDisconnectedTest
321 redisCallbackFn* savedCb;
324 AsyncHiredisCommandDispatcherConnectedTest():
325 contents { { "CMD", "key1", "value1", "key2", "value2" },
330 expectCommandListQuery();
334 ~AsyncHiredisCommandDispatcherConnectedTest()
336 expectRedisAsyncFree();
341 EXPECT_CALL(*this, ack(std::error_code(), _))
345 void expectReplyError(const std::string& msg)
347 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
349 .WillOnce(Invoke([this, msg](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
350 int, const char**, const size_t*)
352 cb(ac, &redisReplyBuilder.buildErrorReply(msg), pd);
357 void expectContextError(int code)
359 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
361 .WillOnce(Invoke([code](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
369 void expectRedisAsyncFreeCallPendingCallback(redisCallbackFn* cb, void* pd)
371 EXPECT_CALL(hiredisSystemMock, redisAsyncFree(&ac))
373 .WillOnce(Invoke([cb, pd](redisAsyncContext* ac)
379 void expectAckNotCalled()
381 EXPECT_CALL(*this, ack(_,_))
385 void expectRedisAsyncCommandArgv_SaveCb()
387 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
389 .WillRepeatedly(Invoke([this](redisAsyncContext*, redisCallbackFn* cb, void* pd,
390 int, const char**, const size_t*)
399 using AsyncHiredisCommandDispatcherDeathTest = AsyncHiredisCommandDispatcherConnectedTest;
402 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, IsNotCopyable)
404 EXPECT_FALSE(std::is_copy_constructible<AsyncHiredisCommandDispatcher>::value);
405 EXPECT_FALSE(std::is_copy_assignable<AsyncHiredisCommandDispatcher>::value);
408 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ImplementsAsyncRedisCommandDispatcher)
410 EXPECT_TRUE((std::is_base_of<AsyncCommandDispatcher, AsyncHiredisCommandDispatcher>::value));
413 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, CannotDispatchCommandsIfDisconnected)
415 Engine::Callback storedCallback;
416 EXPECT_CALL(engineMock, postCallback(_))
418 .WillOnce(SaveArg<0>(&storedCallback));
419 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::ack,
421 std::placeholders::_1,
422 std::placeholders::_2),
425 expectAckError(std::error_code(AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED));
429 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ContextErrorInConnectArmsRetryTimer)
432 expectationsUntilConnect();
433 expectArmConnectionRetryTimer();
435 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
443 expectDisarmConnectionRetryTimer();
446 TEST_F(AsyncHiredisCommandDispatcherBaseTest, NullRedisContextInConnectArmsRetryTimer)
449 expectRedisAsyncConnectReturnNullptr();
450 expectArmConnectionRetryTimer();
451 expectDisarmConnectionRetryTimer();
453 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
463 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, FailedCommandListQueryArmsRetryTimer)
466 expectCommandListQueryReturnError();
467 expectArmConnectionVerificationRetryTimer();
468 expectRedisAsyncFree();
470 expectDisarmConnectionRetryTimer();
473 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ErrorInConnectedCallbackArmsRetryTimer)
476 expectArmConnectionRetryTimer();
478 expectDisarmConnectionRetryTimer();
481 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ConnectionSucceedsWithRetryTimer)
484 expectArmConnectionRetryTimer();
488 expectationsUntilConnect();
489 expectAdapterAttach();
490 expectRedisAsyncSetConnectCallback();
491 expectRedisAsyncSetDisconnectCallback();
493 savedConnectionRetryTimerCallback();
495 expectCommandListQuery();
498 dispatcher->waitConnectedAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::connectAck, this));
501 expectRedisAsyncFree();
504 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ConnectAckCalledOnceConnected)
507 expectCommandListQuery();
509 dispatcher->waitConnectedAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::connectAck, this));
511 expectRedisAsyncFree();
514 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ConnectAckCalledIfConnected)
516 Engine::Callback storedCallback;
517 EXPECT_CALL(engineMock, postCallback(_))
519 .WillOnce(SaveArg<0>(&storedCallback));
520 expectCommandListQuery();
522 dispatcher->waitConnectedAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::connectAck, this));
525 expectRedisAsyncFree();
528 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanDispatchCommands)
530 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
532 .WillOnce(Invoke([this](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
533 int argc, const char** argv, const size_t* argvlen)
535 EXPECT_EQ((int)contents.stack.size(), argc);
536 EXPECT_EQ(contents.sizes[0], argvlen[0]);
537 EXPECT_EQ(contents.sizes[1], argvlen[1]);
538 EXPECT_EQ(contents.sizes[2], argvlen[2]);
539 EXPECT_EQ(contents.sizes[3], argvlen[3]);
540 EXPECT_EQ(contents.sizes[4], argvlen[4]);
541 EXPECT_FALSE(std::memcmp(argv[0], contents.stack[0].c_str(), contents.sizes[0]));
542 EXPECT_FALSE(std::memcmp(argv[1], contents.stack[1].c_str(), contents.sizes[1]));
543 EXPECT_FALSE(std::memcmp(argv[2], contents.stack[2].c_str(), contents.sizes[2]));
544 EXPECT_FALSE(std::memcmp(argv[3], contents.stack[3].c_str(), contents.sizes[3]));
545 EXPECT_FALSE(std::memcmp(argv[4], contents.stack[4].c_str(), contents.sizes[4]));
546 cb(ac, &redisReplyBuilder.buildNilReply(), pd);
550 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
552 std::placeholders::_1,
553 std::placeholders::_2),
558 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseNilReply)
560 expectRedisAsyncCommandArgv(redisReplyBuilder.buildNilReply());
561 EXPECT_CALL(*this, ack(std::error_code(), _))
563 .WillOnce(Invoke([](const std::error_code&, const Reply& reply)
565 EXPECT_EQ(Reply::Type::NIL, reply.getType());
566 EXPECT_EQ(0, reply.getInteger());
567 EXPECT_TRUE(reply.getString()->str.empty());
568 EXPECT_EQ(static_cast<ReplyStringLength>(0), reply.getString()->len);
569 EXPECT_TRUE(reply.getArray()->empty());
571 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
573 std::placeholders::_1,
574 std::placeholders::_2),
579 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseIntegerReply)
581 expectRedisAsyncCommandArgv(redisReplyBuilder.buildIntegerReply());
582 EXPECT_CALL(*this, ack(std::error_code(), _))
584 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
586 auto expected(redisReplyBuilder.buildIntegerReply());
587 EXPECT_EQ(Reply::Type::INTEGER, reply.getType());
588 EXPECT_EQ(expected.integer, reply.getInteger());
590 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
592 std::placeholders::_1,
593 std::placeholders::_2),
598 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseStatusReply)
600 expectRedisAsyncCommandArgv(redisReplyBuilder.buildStatusReply());
601 EXPECT_CALL(*this, ack(std::error_code(), _))
603 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
605 auto expected(redisReplyBuilder.buildStatusReply());
606 EXPECT_EQ(Reply::Type::STATUS, reply.getType());
607 EXPECT_EQ(expected.len, reply.getString()->len);
608 EXPECT_FALSE(std::memcmp(reply.getString()->str.c_str(), expected.str, expected.len));
610 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
612 std::placeholders::_1,
613 std::placeholders::_2),
618 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseStringReply)
620 expectRedisAsyncCommandArgv(redisReplyBuilder.buildStringReply());
621 EXPECT_CALL(*this, ack(std::error_code(), _))
623 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
625 auto expected(redisReplyBuilder.buildStringReply());
626 EXPECT_EQ(Reply::Type::STRING, reply.getType());
627 EXPECT_EQ(expected.len, reply.getString()->len);
628 EXPECT_FALSE(std::memcmp(reply.getString()->str.c_str(), expected.str, expected.len));
630 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
632 std::placeholders::_1,
633 std::placeholders::_2),
638 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseArrayReply)
640 expectRedisAsyncCommandArgv(redisReplyBuilder.buildArrayReply());
641 EXPECT_CALL(*this, ack(std::error_code(), _))
643 .WillOnce(Invoke([](const std::error_code&, const Reply& reply)
645 auto array(reply.getArray());
646 EXPECT_EQ(Reply::Type::ARRAY, reply.getType());
647 EXPECT_EQ(Reply::Type::STRING, (*array)[0]->getType());
648 EXPECT_EQ(Reply::Type::NIL, (*array)[1]->getType());
650 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
652 std::placeholders::_1,
653 std::placeholders::_2),
658 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanHandleDispatchHiredisBufferErrors)
660 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
662 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn*, void*, int, const char**, const size_t*)
667 Engine::Callback storedCallback;
668 EXPECT_CALL(engineMock, postCallback(_))
670 .WillOnce(SaveArg<0>(&storedCallback));
671 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
673 std::placeholders::_1,
674 std::placeholders::_2),
681 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanHandleDispatchHiredisCbErrors)
683 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
685 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
691 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
693 std::placeholders::_1,
694 std::placeholders::_2),
699 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, DatasetStillBeingLoadedInMemoryIsRecognizedFromReply)
701 expectReplyError("LOADING Redis is loading the dataset in memory");
702 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING), _))
704 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
706 std::placeholders::_1,
707 std::placeholders::_2),
712 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, ProtocolErrorIsRecognizedFromReply)
714 expectReplyError("ERR Protocol error: invalid bulk length");
715 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR), _))
717 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
719 std::placeholders::_1,
720 std::placeholders::_2),
725 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, UnrecognizedReplyErrorIsConvertedToUnknownError)
727 expectReplyError("something sinister");
728 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR), _))
730 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
732 std::placeholders::_1,
733 std::placeholders::_2),
738 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, IOErrorInContext)
740 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
742 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
744 ac->err = REDIS_ERR_IO;
749 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::IO_ERROR), _))
751 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
753 std::placeholders::_1,
754 std::placeholders::_2),
759 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, IOErrorInContextWithECONNRESETerrnoValue)
761 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
763 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
765 ac->err = REDIS_ERR_IO;
770 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST), _))
772 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
774 std::placeholders::_1,
775 std::placeholders::_2),
780 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, EofErrorInContext)
782 expectContextError(REDIS_ERR_EOF);
783 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST), _))
785 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
787 std::placeholders::_1,
788 std::placeholders::_2),
793 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, ProtocolErrorInContext)
795 expectContextError(REDIS_ERR_PROTOCOL);
796 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR), _))
798 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
800 std::placeholders::_1,
801 std::placeholders::_2),
806 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, OomErrorInContext)
808 expectContextError(REDIS_ERR_OOM);
809 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY), _))
811 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
813 std::placeholders::_1,
814 std::placeholders::_2),
819 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, UnrecognizedContextErrorIsConvertedToUnknownError)
821 expectContextError(REDIS_ERR_OTHER);
822 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR), _))
824 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
826 std::placeholders::_1,
827 std::placeholders::_2),
832 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, PendingClientCallbacksAreNotCalledAfterDisabled)
835 expectRedisAsyncCommandArgv_SaveCb();
836 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
838 std::placeholders::_1,
839 std::placeholders::_2),
843 savedCb(&ac, &redisReplyBuilder.buildStringReply(), savedPd);
844 dispatcher->disableCommandCallbacks();
845 expectRedisAsyncCommandArgv_SaveCb();
846 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
848 std::placeholders::_1,
849 std::placeholders::_2),
852 expectAckNotCalled();
853 savedCb(&ac, &redisReplyBuilder.buildStringReply(), savedPd);
856 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, RegisteredClientDisconnectCallbackIsCalled)
859 dispatcher->registerDisconnectCb(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::disconnectCallback,
861 expectDisconnectCallback();
862 expectArmConnectionRetryTimer();
863 disconnected(&ac, 0);
864 expectDisarmConnectionRetryTimer();
865 expectCommandListQuery();
866 connected(&ac, 0); // restore connection to meet destructor expectations
869 TEST_F(AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest, CanHandleMultipleRepliesForSameRedisCommand)
872 redisCallbackFn* savedCb;
874 Contents contents({ { "cmd", "key", "value" }, { 3, 3, 5 } });
875 expectCommandListQuery();
877 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
879 .WillOnce(Invoke([&savedCb, &savedPd](redisAsyncContext*, redisCallbackFn* cb, void* pd,
880 int, const char**, const size_t*)
886 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
888 std::placeholders::_1,
889 std::placeholders::_2),
892 EXPECT_CALL(*this, ack(std::error_code(), _))
895 rr.type = REDIS_REPLY_NIL;
896 savedCb(&ac, &rr, savedPd);
897 savedCb(&ac, &rr, savedPd);
898 savedCb(&ac, &rr, savedPd);
901 TEST_F(AsyncHiredisCommandDispatcherDeathTest, CbRemovedAfterHiredisCb)
903 redisCallbackFn* savedCb;
905 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
907 .WillOnce(Invoke([this, &savedCb, &savedPd](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
908 int, const char**, const size_t*)
912 cb(ac, &redisReplyBuilder.buildNilReply(), pd);
916 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherDeathTest::ack,
918 std::placeholders::_1,
919 std::placeholders::_2),
922 EXPECT_EXIT(savedCb(&ac, &redisReplyBuilder.buildNilReply(), savedPd), KilledBySignal(SIGABRT), "");
925 TEST_F(AsyncHiredisCommandDispatcherDeathTest, TooManyRepliesAborts)
928 redisCallbackFn* savedCb;
930 Contents contents({ { "cmd", "key", "value" }, { 3, 3, 5 } });
931 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
933 .WillOnce(Invoke([&savedCb, &savedPd](redisAsyncContext*, redisCallbackFn* cb, void* pd,
934 int, const char**, const size_t*)
941 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
943 std::placeholders::_1,
944 std::placeholders::_2),
947 savedCb(&ac, &redisReplyBuilder.buildNilReply(), savedPd);
948 EXPECT_EXIT(savedCb(&ac, &redisReplyBuilder.buildNilReply(), savedPd), KilledBySignal(SIGABRT), "");