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,
287 ~AsyncHiredisCommandDispatcherDisconnectedTest()
292 class AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest: public AsyncHiredisCommandDispatcherBaseTest
295 AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest()
298 expectationsUntilConnect();
299 expectAdapterAttach();
300 expectRedisAsyncSetConnectCallback();
301 expectRedisAsyncSetDisconnectCallback();
302 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
313 ~AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest()
315 expectRedisAsyncFree();
319 class AsyncHiredisCommandDispatcherConnectedTest: public AsyncHiredisCommandDispatcherDisconnectedTest
323 redisCallbackFn* savedCb;
326 AsyncHiredisCommandDispatcherConnectedTest():
327 contents { { "CMD", "key1", "value1", "key2", "value2" },
332 expectCommandListQuery();
336 ~AsyncHiredisCommandDispatcherConnectedTest()
338 expectRedisAsyncFree();
343 EXPECT_CALL(*this, ack(std::error_code(), _))
347 void expectReplyError(const std::string& msg)
349 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
351 .WillOnce(Invoke([this, msg](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
352 int, const char**, const size_t*)
354 cb(ac, &redisReplyBuilder.buildErrorReply(msg), pd);
359 void expectContextError(int code)
361 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
363 .WillOnce(Invoke([code](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
371 void expectRedisAsyncFreeCallPendingCallback(redisCallbackFn* cb, void* pd)
373 EXPECT_CALL(hiredisSystemMock, redisAsyncFree(&ac))
375 .WillOnce(Invoke([cb, pd](redisAsyncContext* ac)
381 void expectAckNotCalled()
383 EXPECT_CALL(*this, ack(_,_))
387 void expectRedisAsyncCommandArgv_SaveCb()
389 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
391 .WillRepeatedly(Invoke([this](redisAsyncContext*, redisCallbackFn* cb, void* pd,
392 int, const char**, const size_t*)
401 using AsyncHiredisCommandDispatcherDeathTest = AsyncHiredisCommandDispatcherConnectedTest;
403 class AsyncHiredisCommandDispatcherForSentinelTest: public AsyncHiredisCommandDispatcherBaseTest
406 AsyncHiredisCommandDispatcherForSentinelTest()
409 expectationsUntilConnect();
410 expectAdapterAttach();
411 expectRedisAsyncSetConnectCallback();
412 expectRedisAsyncSetDisconnectCallback();
413 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
424 ~AsyncHiredisCommandDispatcherForSentinelTest()
426 expectRedisAsyncFree();
431 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, IsNotCopyable)
433 EXPECT_FALSE(std::is_copy_constructible<AsyncHiredisCommandDispatcher>::value);
434 EXPECT_FALSE(std::is_copy_assignable<AsyncHiredisCommandDispatcher>::value);
437 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ImplementsAsyncRedisCommandDispatcher)
439 EXPECT_TRUE((std::is_base_of<AsyncCommandDispatcher, AsyncHiredisCommandDispatcher>::value));
442 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, CannotDispatchCommandsIfDisconnected)
444 Engine::Callback storedCallback;
445 EXPECT_CALL(engineMock, postCallback(_))
447 .WillOnce(SaveArg<0>(&storedCallback));
448 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::ack,
450 std::placeholders::_1,
451 std::placeholders::_2),
454 expectAckError(std::error_code(AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED));
458 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ContextErrorInConnectArmsRetryTimer)
461 expectationsUntilConnect();
462 expectArmConnectionRetryTimer();
464 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
473 expectDisarmConnectionRetryTimer();
476 TEST_F(AsyncHiredisCommandDispatcherBaseTest, NullRedisContextInConnectArmsRetryTimer)
479 expectRedisAsyncConnectReturnNullptr();
480 expectArmConnectionRetryTimer();
481 expectDisarmConnectionRetryTimer();
483 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
494 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, FailedCommandListQueryArmsRetryTimer)
497 expectCommandListQueryReturnError();
498 expectArmConnectionVerificationRetryTimer();
499 expectRedisAsyncFree();
501 expectDisarmConnectionRetryTimer();
504 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ErrorInConnectedCallbackArmsRetryTimer)
507 expectArmConnectionRetryTimer();
509 expectDisarmConnectionRetryTimer();
512 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ConnectionSucceedsWithRetryTimer)
515 expectArmConnectionRetryTimer();
519 expectationsUntilConnect();
520 expectAdapterAttach();
521 expectRedisAsyncSetConnectCallback();
522 expectRedisAsyncSetDisconnectCallback();
524 savedConnectionRetryTimerCallback();
526 expectCommandListQuery();
529 dispatcher->waitConnectedAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::connectAck, this));
532 expectRedisAsyncFree();
535 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ConnectAckCalledOnceConnected)
538 expectCommandListQuery();
540 dispatcher->waitConnectedAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::connectAck, this));
542 expectRedisAsyncFree();
545 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ConnectAckCalledIfConnected)
547 Engine::Callback storedCallback;
548 EXPECT_CALL(engineMock, postCallback(_))
550 .WillOnce(SaveArg<0>(&storedCallback));
551 expectCommandListQuery();
553 dispatcher->waitConnectedAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::connectAck, this));
556 expectRedisAsyncFree();
559 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanDispatchCommands)
561 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
563 .WillOnce(Invoke([this](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
564 int argc, const char** argv, const size_t* argvlen)
566 EXPECT_EQ((int)contents.stack.size(), argc);
567 EXPECT_EQ(contents.sizes[0], argvlen[0]);
568 EXPECT_EQ(contents.sizes[1], argvlen[1]);
569 EXPECT_EQ(contents.sizes[2], argvlen[2]);
570 EXPECT_EQ(contents.sizes[3], argvlen[3]);
571 EXPECT_EQ(contents.sizes[4], argvlen[4]);
572 EXPECT_FALSE(std::memcmp(argv[0], contents.stack[0].c_str(), contents.sizes[0]));
573 EXPECT_FALSE(std::memcmp(argv[1], contents.stack[1].c_str(), contents.sizes[1]));
574 EXPECT_FALSE(std::memcmp(argv[2], contents.stack[2].c_str(), contents.sizes[2]));
575 EXPECT_FALSE(std::memcmp(argv[3], contents.stack[3].c_str(), contents.sizes[3]));
576 EXPECT_FALSE(std::memcmp(argv[4], contents.stack[4].c_str(), contents.sizes[4]));
577 cb(ac, &redisReplyBuilder.buildNilReply(), pd);
581 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
583 std::placeholders::_1,
584 std::placeholders::_2),
589 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseNilReply)
591 expectRedisAsyncCommandArgv(redisReplyBuilder.buildNilReply());
592 EXPECT_CALL(*this, ack(std::error_code(), _))
594 .WillOnce(Invoke([](const std::error_code&, const Reply& reply)
596 EXPECT_EQ(Reply::Type::NIL, reply.getType());
597 EXPECT_EQ(0, reply.getInteger());
598 EXPECT_TRUE(reply.getString()->str.empty());
599 EXPECT_EQ(static_cast<ReplyStringLength>(0), reply.getString()->len);
600 EXPECT_TRUE(reply.getArray()->empty());
602 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
604 std::placeholders::_1,
605 std::placeholders::_2),
610 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseIntegerReply)
612 expectRedisAsyncCommandArgv(redisReplyBuilder.buildIntegerReply());
613 EXPECT_CALL(*this, ack(std::error_code(), _))
615 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
617 auto expected(redisReplyBuilder.buildIntegerReply());
618 EXPECT_EQ(Reply::Type::INTEGER, reply.getType());
619 EXPECT_EQ(expected.integer, reply.getInteger());
621 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
623 std::placeholders::_1,
624 std::placeholders::_2),
629 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseStatusReply)
631 expectRedisAsyncCommandArgv(redisReplyBuilder.buildStatusReply());
632 EXPECT_CALL(*this, ack(std::error_code(), _))
634 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
636 auto expected(redisReplyBuilder.buildStatusReply());
637 EXPECT_EQ(Reply::Type::STATUS, reply.getType());
638 EXPECT_EQ(expected.len, reply.getString()->len);
639 EXPECT_FALSE(std::memcmp(reply.getString()->str.c_str(), expected.str, expected.len));
641 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
643 std::placeholders::_1,
644 std::placeholders::_2),
649 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseStringReply)
651 expectRedisAsyncCommandArgv(redisReplyBuilder.buildStringReply());
652 EXPECT_CALL(*this, ack(std::error_code(), _))
654 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
656 auto expected(redisReplyBuilder.buildStringReply());
657 EXPECT_EQ(Reply::Type::STRING, reply.getType());
658 EXPECT_EQ(expected.len, reply.getString()->len);
659 EXPECT_FALSE(std::memcmp(reply.getString()->str.c_str(), expected.str, expected.len));
661 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
663 std::placeholders::_1,
664 std::placeholders::_2),
669 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseArrayReply)
671 expectRedisAsyncCommandArgv(redisReplyBuilder.buildArrayReply());
672 EXPECT_CALL(*this, ack(std::error_code(), _))
674 .WillOnce(Invoke([](const std::error_code&, const Reply& reply)
676 auto array(reply.getArray());
677 EXPECT_EQ(Reply::Type::ARRAY, reply.getType());
678 EXPECT_EQ(Reply::Type::STRING, (*array)[0]->getType());
679 EXPECT_EQ(Reply::Type::NIL, (*array)[1]->getType());
681 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
683 std::placeholders::_1,
684 std::placeholders::_2),
689 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanHandleDispatchHiredisBufferErrors)
691 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
693 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn*, void*, int, const char**, const size_t*)
698 Engine::Callback storedCallback;
699 EXPECT_CALL(engineMock, postCallback(_))
701 .WillOnce(SaveArg<0>(&storedCallback));
702 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
704 std::placeholders::_1,
705 std::placeholders::_2),
712 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanHandleDispatchHiredisCbErrors)
714 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
716 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
722 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
724 std::placeholders::_1,
725 std::placeholders::_2),
730 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, DatasetStillBeingLoadedInMemoryIsRecognizedFromReply)
732 expectReplyError("LOADING Redis is loading the dataset in memory");
733 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING), _))
735 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
737 std::placeholders::_1,
738 std::placeholders::_2),
743 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, ProtocolErrorIsRecognizedFromReply)
745 expectReplyError("ERR Protocol error: invalid bulk length");
746 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR), _))
748 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
750 std::placeholders::_1,
751 std::placeholders::_2),
756 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, UnrecognizedReplyErrorIsConvertedToUnknownError)
758 expectReplyError("something sinister");
759 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR), _))
761 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
763 std::placeholders::_1,
764 std::placeholders::_2),
769 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, IOErrorInContext)
771 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
773 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
775 ac->err = REDIS_ERR_IO;
780 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::IO_ERROR), _))
782 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
784 std::placeholders::_1,
785 std::placeholders::_2),
790 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, IOErrorInContextWithECONNRESETerrnoValue)
792 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
794 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
796 ac->err = REDIS_ERR_IO;
801 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST), _))
803 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
805 std::placeholders::_1,
806 std::placeholders::_2),
811 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, EofErrorInContext)
813 expectContextError(REDIS_ERR_EOF);
814 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST), _))
816 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
818 std::placeholders::_1,
819 std::placeholders::_2),
824 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, ProtocolErrorInContext)
826 expectContextError(REDIS_ERR_PROTOCOL);
827 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR), _))
829 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
831 std::placeholders::_1,
832 std::placeholders::_2),
837 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, OomErrorInContext)
839 expectContextError(REDIS_ERR_OOM);
840 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY), _))
842 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
844 std::placeholders::_1,
845 std::placeholders::_2),
850 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, UnrecognizedContextErrorIsConvertedToUnknownError)
852 expectContextError(REDIS_ERR_OTHER);
853 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR), _))
855 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
857 std::placeholders::_1,
858 std::placeholders::_2),
863 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, PendingClientCallbacksAreNotCalledAfterDisabled)
866 expectRedisAsyncCommandArgv_SaveCb();
867 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
869 std::placeholders::_1,
870 std::placeholders::_2),
874 savedCb(&ac, &redisReplyBuilder.buildStringReply(), savedPd);
875 dispatcher->disableCommandCallbacks();
876 expectRedisAsyncCommandArgv_SaveCb();
877 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
879 std::placeholders::_1,
880 std::placeholders::_2),
883 expectAckNotCalled();
884 savedCb(&ac, &redisReplyBuilder.buildStringReply(), savedPd);
887 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, RegisteredClientDisconnectCallbackIsCalled)
890 dispatcher->registerDisconnectCb(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::disconnectCallback,
892 expectDisconnectCallback();
893 expectArmConnectionRetryTimer();
894 disconnected(&ac, 0);
895 expectDisarmConnectionRetryTimer();
896 expectCommandListQuery();
897 connected(&ac, 0); // restore connection to meet destructor expectations
900 TEST_F(AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest, CanHandleMultipleRepliesForSameRedisCommand)
903 redisCallbackFn* savedCb;
905 Contents contents({ { "cmd", "key", "value" }, { 3, 3, 5 } });
906 expectCommandListQuery();
908 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
910 .WillOnce(Invoke([&savedCb, &savedPd](redisAsyncContext*, redisCallbackFn* cb, void* pd,
911 int, const char**, const size_t*)
917 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
919 std::placeholders::_1,
920 std::placeholders::_2),
923 EXPECT_CALL(*this, ack(std::error_code(), _))
926 rr.type = REDIS_REPLY_NIL;
927 savedCb(&ac, &rr, savedPd);
928 savedCb(&ac, &rr, savedPd);
929 savedCb(&ac, &rr, savedPd);
932 TEST_F(AsyncHiredisCommandDispatcherDeathTest, CbRemovedAfterHiredisCb)
934 redisCallbackFn* savedCb;
936 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
938 .WillOnce(Invoke([this, &savedCb, &savedPd](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
939 int, const char**, const size_t*)
943 cb(ac, &redisReplyBuilder.buildNilReply(), pd);
947 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherDeathTest::ack,
949 std::placeholders::_1,
950 std::placeholders::_2),
953 EXPECT_EXIT(savedCb(&ac, &redisReplyBuilder.buildNilReply(), savedPd), KilledBySignal(SIGABRT), "");
956 TEST_F(AsyncHiredisCommandDispatcherDeathTest, TooManyRepliesAborts)
959 redisCallbackFn* savedCb;
961 Contents contents({ { "cmd", "key", "value" }, { 3, 3, 5 } });
962 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
964 .WillOnce(Invoke([&savedCb, &savedPd](redisAsyncContext*, redisCallbackFn* cb, void* pd,
965 int, const char**, const size_t*)
972 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
974 std::placeholders::_1,
975 std::placeholders::_2),
978 savedCb(&ac, &redisReplyBuilder.buildNilReply(), savedPd);
979 EXPECT_EXIT(savedCb(&ac, &redisReplyBuilder.buildNilReply(), savedPd), KilledBySignal(SIGABRT), "");
982 TEST_F(AsyncHiredisCommandDispatcherForSentinelTest, CommandListInquiryIsNotSent)
984 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(_, _, _, _, _, _))