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.
18 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 * platform project (RICP).
22 #include <type_traits>
25 #include <sys/epoll.h>
26 #include <sys/timerfd.h>
27 #include <sys/eventfd.h>
28 #include <arpa/inet.h>
29 #include <gtest/gtest.h>
31 #include "private/createlogger.hpp"
32 #include "private/error.hpp"
33 #include "private/logger.hpp"
34 #include "private/redis/asynchirediscommanddispatcher.hpp"
35 #include "private/redis/reply.hpp"
36 #include "private/redis/contents.hpp"
37 #include "private/timer.hpp"
38 #include "private/tst/contentsbuildermock.hpp"
39 #include "private/tst/enginemock.hpp"
40 #include "private/tst/hiredissystemmock.hpp"
41 #include "private/tst/hiredisepolladaptermock.hpp"
42 #include "private/tst/redisreplybuilder.hpp"
44 using namespace shareddatalayer;
45 using namespace shareddatalayer::redis;
46 using namespace shareddatalayer::tst;
47 using namespace testing;
51 class AsyncHiredisCommandDispatcherBaseTest: public testing::Test
54 std::shared_ptr<ContentsBuilderMock> contentsBuilderMock;
55 StrictMock<EngineMock> engineMock;
56 HiredisSystemMock hiredisSystemMock;
57 std::shared_ptr<HiredisEpollAdapterMock> adapterMock;
60 std::unique_ptr<AsyncHiredisCommandDispatcher> dispatcher;
61 void (*connected)(const redisAsyncContext*, int);
62 void (*disconnected)(const redisAsyncContext*, int);
63 Timer::Callback savedConnectionRetryTimerCallback;
64 Timer::Duration expectedConnectionRetryTimerDuration;
65 Timer::Duration expectedConnectionVerificationRetryTimerDuration;
66 RedisReplyBuilder redisReplyBuilder;
67 const AsyncConnection::Namespace defaultNamespace;
68 std::shared_ptr<Logger> logger;
70 AsyncHiredisCommandDispatcherBaseTest():
71 contentsBuilderMock(std::make_shared<ContentsBuilderMock>(AsyncConnection::SEPARATOR)),
72 adapterMock(std::make_shared<HiredisEpollAdapterMock>(engineMock, hiredisSystemMock)),
76 disconnected(nullptr),
77 expectedConnectionRetryTimerDuration(std::chrono::seconds(1)),
78 expectedConnectionVerificationRetryTimerDuration(std::chrono::seconds(10)),
79 redisReplyBuilder { },
80 defaultNamespace("namespace"),
81 logger(createLogger(SDL_LOG_PREFIX))
85 virtual ~AsyncHiredisCommandDispatcherBaseTest()
89 MOCK_METHOD0(connectAck, void());
91 MOCK_METHOD0(disconnectCallback, void());
93 MOCK_METHOD2(ack, void(const std::error_code&, const Reply&));
95 void expectationsUntilConnect()
97 expectationsUntilConnect(ac);
100 void expectationsUntilConnect(redisAsyncContext& ac)
102 expectRedisAsyncConnect(ac);
105 void expectRedisAsyncConnect()
107 expectRedisAsyncConnect(ac);
110 void expectRedisAsyncConnect(redisAsyncContext& ac)
112 EXPECT_CALL(hiredisSystemMock, redisAsyncConnect(StrEq("host"), 6379U))
114 .WillOnce(InvokeWithoutArgs([this, &ac]()
121 void expectRedisAsyncConnectReturnNullptr()
123 EXPECT_CALL(hiredisSystemMock, redisAsyncConnect(StrEq("host"), 6379U))
125 .WillOnce(InvokeWithoutArgs([this]()
132 void expectRedisAsyncSetConnectCallback()
134 expectRedisAsyncSetConnectCallback(ac);
137 void expectRedisAsyncSetConnectCallback(redisAsyncContext& ac)
139 EXPECT_CALL(hiredisSystemMock, redisAsyncSetConnectCallback(&ac, _))
141 .WillOnce(Invoke([this](const redisAsyncContext*, redisConnectCallback* cb)
148 void expectRedisAsyncSetDisconnectCallback()
150 expectRedisAsyncSetDisconnectCallback(ac);
153 void expectRedisAsyncSetDisconnectCallback(redisAsyncContext& ac)
155 EXPECT_CALL(hiredisSystemMock, redisAsyncSetDisconnectCallback(&ac, _))
157 .WillOnce(Invoke([this](const redisAsyncContext*, redisDisconnectCallback* cb)
164 void expectAdapterAttach()
166 expectAdapterAttach(ac);
169 void expectAdapterAttach(redisAsyncContext& ac)
171 EXPECT_CALL(*adapterMock, attach(&ac))
175 void expectConnectAck()
177 EXPECT_CALL(*this, connectAck())
181 void expectDisconnectCallback()
183 EXPECT_CALL(*this, disconnectCallback())
187 void expectRedisAsyncFree()
189 EXPECT_CALL(hiredisSystemMock, redisAsyncFree(&ac))
193 void expectRedisAsyncDisconnect()
195 EXPECT_CALL(hiredisSystemMock, redisAsyncDisconnect(&ac))
199 void expectRedisAsyncCommandArgv(redisReply& rr)
201 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
203 .WillOnce(Invoke([&rr](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
204 int, const char**, const size_t*)
211 void expectCommandListQuery()
213 expectRedisAsyncCommandArgv(redisReplyBuilder.buildCommandListQueryReply());
216 void expectCommandListQueryReturnError()
218 expectRedisAsyncCommandArgv(redisReplyBuilder.buildErrorReply("SomeErrorForCommandListQuery"));
221 void verifyAckErrorReply(const Reply& reply)
223 EXPECT_EQ(Reply::Type::NIL, reply.getType());
224 EXPECT_EQ(0, reply.getInteger());
225 EXPECT_TRUE(reply.getString()->str.empty());
226 EXPECT_EQ(static_cast<ReplyStringLength>(0), reply.getString()->len);
227 EXPECT_TRUE(reply.getArray()->empty());
230 void expectAckError()
232 EXPECT_CALL(*this, ack(Ne(std::error_code()), _))
234 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
236 verifyAckErrorReply(reply);
240 void expectAckError(const std::error_code& ec)
242 EXPECT_CALL(*this, ack(ec, _))
244 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
246 verifyAckErrorReply(reply);
250 void expectArmConnectionRetryTimer()
252 EXPECT_CALL(engineMock, armTimer(_, expectedConnectionRetryTimerDuration, _))
254 .WillOnce(SaveArg<2>(&savedConnectionRetryTimerCallback));
257 void expectArmConnectionVerificationRetryTimer()
259 EXPECT_CALL(engineMock, armTimer(_, expectedConnectionVerificationRetryTimerDuration, _))
261 .WillOnce(SaveArg<2>(&savedConnectionRetryTimerCallback));
264 void expectDisarmConnectionRetryTimer()
266 EXPECT_CALL(engineMock, disarmTimer(_))
271 class AsyncHiredisCommandDispatcherDisconnectedTest: public AsyncHiredisCommandDispatcherBaseTest
274 AsyncHiredisCommandDispatcherDisconnectedTest()
277 expectationsUntilConnect();
278 expectAdapterAttach();
279 expectRedisAsyncSetConnectCallback();
280 expectRedisAsyncSetDisconnectCallback();
281 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
292 ~AsyncHiredisCommandDispatcherDisconnectedTest()
297 class AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest: public AsyncHiredisCommandDispatcherBaseTest
300 AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest()
303 expectationsUntilConnect();
304 expectAdapterAttach();
305 expectRedisAsyncSetConnectCallback();
306 expectRedisAsyncSetDisconnectCallback();
307 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
318 ~AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest()
320 expectRedisAsyncFree();
324 class AsyncHiredisCommandDispatcherConnectedTest: public AsyncHiredisCommandDispatcherDisconnectedTest
328 redisCallbackFn* savedCb;
331 AsyncHiredisCommandDispatcherConnectedTest():
332 contents { { "CMD", "key1", "value1", "key2", "value2" },
337 expectCommandListQuery();
341 ~AsyncHiredisCommandDispatcherConnectedTest()
343 expectRedisAsyncFree();
348 EXPECT_CALL(*this, ack(std::error_code(), _))
352 void expectReplyError(const std::string& msg)
354 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
356 .WillOnce(Invoke([this, msg](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
357 int, const char**, const size_t*)
359 cb(ac, &redisReplyBuilder.buildErrorReply(msg), pd);
364 void expectContextError(int code)
366 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
368 .WillOnce(Invoke([code](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
376 void expectRedisAsyncFreeCallPendingCallback(redisCallbackFn* cb, void* pd)
378 EXPECT_CALL(hiredisSystemMock, redisAsyncFree(&ac))
380 .WillOnce(Invoke([cb, pd](redisAsyncContext* ac)
386 void expectAckNotCalled()
388 EXPECT_CALL(*this, ack(_,_))
392 void expectRedisAsyncCommandArgv_SaveCb()
394 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
396 .WillRepeatedly(Invoke([this](redisAsyncContext*, redisCallbackFn* cb, void* pd,
397 int, const char**, const size_t*)
406 using AsyncHiredisCommandDispatcherDeathTest = AsyncHiredisCommandDispatcherConnectedTest;
408 class AsyncHiredisCommandDispatcherForSentinelTest: public AsyncHiredisCommandDispatcherBaseTest
411 AsyncHiredisCommandDispatcherForSentinelTest()
414 expectationsUntilConnect();
415 expectAdapterAttach();
416 expectRedisAsyncSetConnectCallback();
417 expectRedisAsyncSetDisconnectCallback();
418 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
429 ~AsyncHiredisCommandDispatcherForSentinelTest()
431 expectRedisAsyncFree();
436 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, IsNotCopyable)
438 EXPECT_FALSE(std::is_copy_constructible<AsyncHiredisCommandDispatcher>::value);
439 EXPECT_FALSE(std::is_copy_assignable<AsyncHiredisCommandDispatcher>::value);
442 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ImplementsAsyncRedisCommandDispatcher)
444 EXPECT_TRUE((std::is_base_of<AsyncCommandDispatcher, AsyncHiredisCommandDispatcher>::value));
447 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, CannotDispatchCommandsIfDisconnected)
449 Engine::Callback storedCallback;
450 EXPECT_CALL(engineMock, postCallback(_))
452 .WillOnce(SaveArg<0>(&storedCallback));
453 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::ack,
455 std::placeholders::_1,
456 std::placeholders::_2),
459 expectAckError(std::error_code(AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED));
463 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ContextErrorInConnectArmsRetryTimer)
466 expectationsUntilConnect();
467 expectArmConnectionRetryTimer();
469 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
478 expectDisarmConnectionRetryTimer();
481 TEST_F(AsyncHiredisCommandDispatcherBaseTest, NullRedisContextInConnectArmsRetryTimer)
484 expectRedisAsyncConnectReturnNullptr();
485 expectArmConnectionRetryTimer();
486 expectDisarmConnectionRetryTimer();
488 dispatcher.reset(new AsyncHiredisCommandDispatcher(engineMock,
499 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, FailedCommandListQueryArmsRetryTimer)
502 expectCommandListQueryReturnError();
503 expectArmConnectionVerificationRetryTimer();
504 expectRedisAsyncFree();
506 expectDisarmConnectionRetryTimer();
509 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ErrorInConnectedCallbackArmsRetryTimer)
512 expectArmConnectionRetryTimer();
514 expectDisarmConnectionRetryTimer();
517 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ConnectionSucceedsWithRetryTimer)
520 expectArmConnectionRetryTimer();
524 expectationsUntilConnect();
525 expectAdapterAttach();
526 expectRedisAsyncSetConnectCallback();
527 expectRedisAsyncSetDisconnectCallback();
529 savedConnectionRetryTimerCallback();
531 expectCommandListQuery();
534 dispatcher->waitConnectedAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::connectAck, this));
537 expectRedisAsyncFree();
540 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ConnectAckCalledOnceConnected)
543 expectCommandListQuery();
545 dispatcher->waitConnectedAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::connectAck, this));
547 expectRedisAsyncFree();
550 TEST_F(AsyncHiredisCommandDispatcherDisconnectedTest, ConnectAckCalledIfConnected)
552 Engine::Callback storedCallback;
553 EXPECT_CALL(engineMock, postCallback(_))
555 .WillOnce(SaveArg<0>(&storedCallback));
556 expectCommandListQuery();
558 dispatcher->waitConnectedAsync(std::bind(&AsyncHiredisCommandDispatcherDisconnectedTest::connectAck, this));
561 expectRedisAsyncFree();
564 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanDispatchCommands)
566 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
568 .WillOnce(Invoke([this](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
569 int argc, const char** argv, const size_t* argvlen)
571 EXPECT_EQ((int)contents.stack.size(), argc);
572 EXPECT_EQ(contents.sizes[0], argvlen[0]);
573 EXPECT_EQ(contents.sizes[1], argvlen[1]);
574 EXPECT_EQ(contents.sizes[2], argvlen[2]);
575 EXPECT_EQ(contents.sizes[3], argvlen[3]);
576 EXPECT_EQ(contents.sizes[4], argvlen[4]);
577 EXPECT_FALSE(std::memcmp(argv[0], contents.stack[0].c_str(), contents.sizes[0]));
578 EXPECT_FALSE(std::memcmp(argv[1], contents.stack[1].c_str(), contents.sizes[1]));
579 EXPECT_FALSE(std::memcmp(argv[2], contents.stack[2].c_str(), contents.sizes[2]));
580 EXPECT_FALSE(std::memcmp(argv[3], contents.stack[3].c_str(), contents.sizes[3]));
581 EXPECT_FALSE(std::memcmp(argv[4], contents.stack[4].c_str(), contents.sizes[4]));
582 cb(ac, &redisReplyBuilder.buildNilReply(), pd);
586 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
588 std::placeholders::_1,
589 std::placeholders::_2),
594 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseNilReply)
596 expectRedisAsyncCommandArgv(redisReplyBuilder.buildNilReply());
597 EXPECT_CALL(*this, ack(std::error_code(), _))
599 .WillOnce(Invoke([](const std::error_code&, const Reply& reply)
601 EXPECT_EQ(Reply::Type::NIL, reply.getType());
602 EXPECT_EQ(0, reply.getInteger());
603 EXPECT_TRUE(reply.getString()->str.empty());
604 EXPECT_EQ(static_cast<ReplyStringLength>(0), reply.getString()->len);
605 EXPECT_TRUE(reply.getArray()->empty());
607 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
609 std::placeholders::_1,
610 std::placeholders::_2),
615 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseIntegerReply)
617 expectRedisAsyncCommandArgv(redisReplyBuilder.buildIntegerReply());
618 EXPECT_CALL(*this, ack(std::error_code(), _))
620 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
622 auto expected(redisReplyBuilder.buildIntegerReply());
623 EXPECT_EQ(Reply::Type::INTEGER, reply.getType());
624 EXPECT_EQ(expected.integer, reply.getInteger());
626 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
628 std::placeholders::_1,
629 std::placeholders::_2),
634 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseStatusReply)
636 expectRedisAsyncCommandArgv(redisReplyBuilder.buildStatusReply());
637 EXPECT_CALL(*this, ack(std::error_code(), _))
639 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
641 auto expected(redisReplyBuilder.buildStatusReply());
642 EXPECT_EQ(Reply::Type::STATUS, reply.getType());
643 EXPECT_EQ(expected.len, reply.getString()->len);
644 EXPECT_FALSE(std::memcmp(reply.getString()->str.c_str(), expected.str, expected.len));
646 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
648 std::placeholders::_1,
649 std::placeholders::_2),
654 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseStringReply)
656 expectRedisAsyncCommandArgv(redisReplyBuilder.buildStringReply());
657 EXPECT_CALL(*this, ack(std::error_code(), _))
659 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
661 auto expected(redisReplyBuilder.buildStringReply());
662 EXPECT_EQ(Reply::Type::STRING, reply.getType());
663 EXPECT_EQ(expected.len, reply.getString()->len);
664 EXPECT_FALSE(std::memcmp(reply.getString()->str.c_str(), expected.str, expected.len));
666 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
668 std::placeholders::_1,
669 std::placeholders::_2),
674 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanParseArrayReply)
676 expectRedisAsyncCommandArgv(redisReplyBuilder.buildArrayReply());
677 EXPECT_CALL(*this, ack(std::error_code(), _))
679 .WillOnce(Invoke([](const std::error_code&, const Reply& reply)
681 auto array(reply.getArray());
682 EXPECT_EQ(Reply::Type::ARRAY, reply.getType());
683 EXPECT_EQ(Reply::Type::STRING, (*array)[0]->getType());
684 EXPECT_EQ(Reply::Type::NIL, (*array)[1]->getType());
686 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
688 std::placeholders::_1,
689 std::placeholders::_2),
694 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanHandleDispatchHiredisBufferErrors)
696 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
698 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn*, void*, int, const char**, const size_t*)
703 Engine::Callback storedCallback;
704 EXPECT_CALL(engineMock, postCallback(_))
706 .WillOnce(SaveArg<0>(&storedCallback));
707 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
709 std::placeholders::_1,
710 std::placeholders::_2),
717 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, CanHandleDispatchHiredisCbErrors)
719 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
721 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
727 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
729 std::placeholders::_1,
730 std::placeholders::_2),
735 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, DatasetStillBeingLoadedInMemoryIsRecognizedFromReply)
737 expectReplyError("LOADING Redis is loading the dataset in memory");
738 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING), _))
740 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
742 std::placeholders::_1,
743 std::placeholders::_2),
748 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, ProtocolErrorIsRecognizedFromReply)
750 expectReplyError("ERR Protocol error: invalid bulk length");
751 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR), _))
753 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
755 std::placeholders::_1,
756 std::placeholders::_2),
761 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, UnrecognizedReplyErrorIsConvertedToUnknownError)
763 expectReplyError("something sinister");
764 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR), _))
766 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
768 std::placeholders::_1,
769 std::placeholders::_2),
774 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, IOErrorInContext)
776 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
778 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
780 ac->err = REDIS_ERR_IO;
785 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::IO_ERROR), _))
787 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
789 std::placeholders::_1,
790 std::placeholders::_2),
795 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, IOErrorInContextWithECONNRESETerrnoValue)
797 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
799 .WillOnce(Invoke([](redisAsyncContext* ac, redisCallbackFn* cb, void* pd, int, const char**, const size_t*)
801 ac->err = REDIS_ERR_IO;
806 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST), _))
808 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
810 std::placeholders::_1,
811 std::placeholders::_2),
816 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, EofErrorInContext)
818 expectContextError(REDIS_ERR_EOF);
819 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST), _))
821 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
823 std::placeholders::_1,
824 std::placeholders::_2),
829 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, ProtocolErrorInContext)
831 expectContextError(REDIS_ERR_PROTOCOL);
832 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR), _))
834 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
836 std::placeholders::_1,
837 std::placeholders::_2),
842 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, OomErrorInContext)
844 expectContextError(REDIS_ERR_OOM);
845 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY), _))
847 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
849 std::placeholders::_1,
850 std::placeholders::_2),
855 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, UnrecognizedContextErrorIsConvertedToUnknownError)
857 expectContextError(REDIS_ERR_OTHER);
858 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR), _))
860 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
862 std::placeholders::_1,
863 std::placeholders::_2),
868 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, PendingClientCallbacksAreNotCalledAfterDisabled)
871 expectRedisAsyncCommandArgv_SaveCb();
872 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
874 std::placeholders::_1,
875 std::placeholders::_2),
879 savedCb(&ac, &redisReplyBuilder.buildStringReply(), savedPd);
880 dispatcher->disableCommandCallbacks();
881 expectRedisAsyncCommandArgv_SaveCb();
882 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
884 std::placeholders::_1,
885 std::placeholders::_2),
888 expectAckNotCalled();
889 savedCb(&ac, &redisReplyBuilder.buildStringReply(), savedPd);
892 TEST_F(AsyncHiredisCommandDispatcherConnectedTest, RegisteredClientDisconnectCallbackIsCalled)
895 dispatcher->registerDisconnectCb(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::disconnectCallback,
897 expectDisconnectCallback();
898 expectArmConnectionRetryTimer();
899 disconnected(&ac, 0);
900 expectDisarmConnectionRetryTimer();
901 expectCommandListQuery();
902 connected(&ac, 0); // restore connection to meet destructor expectations
905 TEST_F(AsyncHiredisCommandDispatcherWithPermanentCommandCallbacksTest, CanHandleMultipleRepliesForSameRedisCommand)
908 redisCallbackFn* savedCb;
910 Contents contents({ { "cmd", "key", "value" }, { 3, 3, 5 } });
911 expectCommandListQuery();
913 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
915 .WillOnce(Invoke([&savedCb, &savedPd](redisAsyncContext*, redisCallbackFn* cb, void* pd,
916 int, const char**, const size_t*)
922 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
924 std::placeholders::_1,
925 std::placeholders::_2),
928 EXPECT_CALL(*this, ack(std::error_code(), _))
931 rr.type = REDIS_REPLY_NIL;
932 savedCb(&ac, &rr, savedPd);
933 savedCb(&ac, &rr, savedPd);
934 savedCb(&ac, &rr, savedPd);
937 TEST_F(AsyncHiredisCommandDispatcherDeathTest, CbRemovedAfterHiredisCb)
939 redisCallbackFn* savedCb;
941 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
943 .WillOnce(Invoke([this, &savedCb, &savedPd](redisAsyncContext* ac, redisCallbackFn* cb, void* pd,
944 int, const char**, const size_t*)
948 cb(ac, &redisReplyBuilder.buildNilReply(), pd);
952 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherDeathTest::ack,
954 std::placeholders::_1,
955 std::placeholders::_2),
958 EXPECT_EXIT(savedCb(&ac, &redisReplyBuilder.buildNilReply(), savedPd), KilledBySignal(SIGABRT), "");
961 TEST_F(AsyncHiredisCommandDispatcherDeathTest, TooManyRepliesAborts)
964 redisCallbackFn* savedCb;
966 Contents contents({ { "cmd", "key", "value" }, { 3, 3, 5 } });
967 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(&ac, _, _, _, _, _))
969 .WillOnce(Invoke([&savedCb, &savedPd](redisAsyncContext*, redisCallbackFn* cb, void* pd,
970 int, const char**, const size_t*)
977 dispatcher->dispatchAsync(std::bind(&AsyncHiredisCommandDispatcherConnectedTest::ack,
979 std::placeholders::_1,
980 std::placeholders::_2),
983 savedCb(&ac, &redisReplyBuilder.buildNilReply(), savedPd);
984 EXPECT_EXIT(savedCb(&ac, &redisReplyBuilder.buildNilReply(), savedPd), KilledBySignal(SIGABRT), "");
987 TEST_F(AsyncHiredisCommandDispatcherForSentinelTest, CommandListInquiryIsNotSent)
989 EXPECT_CALL(hiredisSystemMock, redisAsyncCommandArgv(_, _, _, _, _, _))