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/asynchiredisclustercommanddispatcher.hpp"
30 #include "private/redis/redisgeneral.hpp"
31 #include "private/redis/reply.hpp"
32 #include "private/redis/contents.hpp"
33 #include "private/tst/hiredisclustersystemmock.hpp"
34 #include "private/timer.hpp"
35 #include "private/tst/contentsbuildermock.hpp"
36 #include "private/tst/enginemock.hpp"
37 #include "private/tst/hiredisclusterepolladaptermock.hpp"
38 #include "private/tst/redisreplybuilder.hpp"
40 using namespace shareddatalayer;
41 using namespace shareddatalayer::redis;
42 using namespace shareddatalayer::tst;
43 using namespace testing;
47 class AsyncHiredisClusterCommandDispatcherBaseTest: public testing::Test
50 std::shared_ptr<ContentsBuilderMock> contentsBuilderMock;
51 StrictMock<EngineMock> engineMock;
52 HiredisClusterSystemMock hiredisClusterSystemMock;
53 std::shared_ptr<HiredisClusterEpollAdapterMock> adapterMock;
54 redisClusterAsyncContext acc;
57 std::unique_ptr<AsyncHiredisClusterCommandDispatcher> dispatcher;
58 void (*connected)(const redisClusterAsyncContext*, const redisAsyncContext*, int);
59 void (*disconnected)(const redisClusterAsyncContext*, const redisAsyncContext*, int);
60 Timer::Callback savedConnectionRetryTimerCallback;
61 Timer::Duration expectedRetryTimerDuration;
63 Contents clusterConnectionSetupContents;
64 RedisReplyBuilder redisReplyBuilder;
65 const AsyncConnection::Namespace defaultNamespace;
66 std::shared_ptr<Logger> logger;
68 AsyncHiredisClusterCommandDispatcherBaseTest():
69 contentsBuilderMock(std::make_shared<ContentsBuilderMock>(AsyncConnection::SEPARATOR)),
70 adapterMock(std::make_shared<HiredisClusterEpollAdapterMock>(engineMock, hiredisClusterSystemMock)),
75 disconnected(nullptr),
76 expectedRetryTimerDuration(std::chrono::seconds(1)),
77 contents { { "CMD", "key1", "value1", "key2", "value2" },
79 redisReplyBuilder { },
80 defaultNamespace("namespace"),
81 logger(createLogger(SDL_LOG_PREFIX))
85 virtual ~AsyncHiredisClusterCommandDispatcherBaseTest()
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(acc);
100 void expectationsUntilConnect(redisClusterAsyncContext& acc)
102 expectRedisClusterAsyncConnect(acc);
105 void expectRedisClusterAsyncConnect()
107 expectRedisClusterAsyncConnect(acc);
110 void expectRedisClusterAsyncConnect(redisClusterAsyncContext& acc)
112 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncConnect(StrEq("addr1:28416,addr2:56832"),
113 HIRCLUSTER_FLAG_ROUTE_USE_SLOTS))
115 .WillOnce(InvokeWithoutArgs([this, &acc]()
121 void expectRedisClusterAsyncConnectReturnNullptr()
123 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncConnect(StrEq("addr1:28416,addr2:56832"),
124 HIRCLUSTER_FLAG_ROUTE_USE_SLOTS))
126 .WillOnce(InvokeWithoutArgs([this]()
132 void expectRedisClusterAsyncSetConnectCallback()
134 expectRedisClusterAsyncSetConnectCallback(acc);
137 void expectRedisClusterAsyncSetConnectCallback(redisClusterAsyncContext& acc)
139 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncSetConnectCallback(&acc, _))
141 .WillOnce(Invoke([this](const redisClusterAsyncContext*, redisClusterInstanceConnectCallback* cb)
148 void expectRedisClusterAsyncSetDisconnectCallback()
150 expectRedisClusterAsyncSetDisconnectCallback(acc);
153 void expectRedisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext& acc)
155 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncSetDisconnectCallback(&acc, _))
157 .WillOnce(Invoke([this](const redisClusterAsyncContext*, redisClusterInstanceDisconnectCallback* cb)
164 void expectCommandListQuery()
166 expectRedisClusterAsyncCommandArgv(redisReplyBuilder.buildCommandListQueryReply());
169 void expectCommandListQueryReturnError()
171 expectRedisClusterAsyncCommandArgv(redisReplyBuilder.buildErrorReply("SomeErrorForCommandListQuery"));
174 void expectAdapterSetup()
176 expectAdapterSetup(acc);
179 void expectAdapterSetup(redisClusterAsyncContext& acc)
181 EXPECT_CALL(*adapterMock, setup(&acc))
185 void expectAdapterDetach()
187 EXPECT_CALL(*adapterMock, detach(&ac))
191 void expectConnectAck()
193 EXPECT_CALL(*this, connectAck())
197 void expectDisconnectCallback()
199 EXPECT_CALL(*this, disconnectCallback())
203 void expectRedisClusterAsyncFree()
205 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncFree(&acc))
209 void expectRedisClusterAsyncDisconnect()
211 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncDisconnect(&acc))
215 void verifyAckErrorReply(const Reply& reply)
217 EXPECT_EQ(Reply::Type::NIL, reply.getType());
218 EXPECT_EQ(0, reply.getInteger());
219 EXPECT_TRUE(reply.getString()->str.empty());
220 EXPECT_EQ(static_cast<ReplyStringLength>(0), reply.getString()->len);
221 EXPECT_TRUE(reply.getArray()->empty());
224 void expectAckError()
226 EXPECT_CALL(*this, ack(Ne(std::error_code()), _))
228 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
230 verifyAckErrorReply(reply);
234 void expectAckError(const std::error_code& ec)
236 EXPECT_CALL(*this, ack(ec, _))
238 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
240 verifyAckErrorReply(reply);
244 void expectArmConnectionRetryTimer()
246 EXPECT_CALL(engineMock, armTimer(_, expectedRetryTimerDuration, _))
248 .WillOnce(SaveArg<2>(&savedConnectionRetryTimerCallback));
251 void expectDisarmConnectionRetryTimer()
253 EXPECT_CALL(engineMock, disarmTimer(_))
257 void expectRedisClusterAsyncCommandArgv(redisReply& rr)
259 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
261 .WillOnce(Invoke([&rr](redisClusterAsyncContext* acc, redisClusterCallbackFn* cb, void* pd, const char*, int,
262 int, const char**, const size_t*)
271 EXPECT_CALL(*this, ack(std::error_code(), _))
275 void expectReplyError(const std::string& msg)
277 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
279 .WillOnce(Invoke([this, msg](redisClusterAsyncContext* acc, redisClusterCallbackFn* cb, void* pd, const char*,
280 int, int, const char**, const size_t*)
282 cb(acc, &redisReplyBuilder.buildErrorReply(msg), pd);
287 void expectContextError(int code)
289 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
291 .WillOnce(Invoke([code](redisClusterAsyncContext* acc, redisClusterCallbackFn* cb, void* pd, const char*, int,
292 int, const char**, const size_t*)
295 cb(acc, nullptr, pd);
300 void expectRedisClusterAsyncFreeCallPendingCallback(redisClusterCallbackFn* cb, void* pd)
302 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncFree(&acc))
304 .WillOnce(Invoke([this, cb, pd](redisClusterAsyncContext* acc)
306 cb(acc, &redisReplyBuilder.buildNilReply(), pd);
310 void expectAckNotCalled()
312 EXPECT_CALL(*this, ack(_,_))
316 void expectionsForSuccessfullConnectionSetup()
318 expectationsUntilConnect();
319 expectAdapterSetup();
320 expectRedisClusterAsyncSetConnectCallback();
321 expectRedisClusterAsyncSetDisconnectCallback();
322 expectCommandListQuery();
325 void callConnectionRetryTimerCallback()
327 ASSERT_NE(savedConnectionRetryTimerCallback, nullptr);
328 savedConnectionRetryTimerCallback();
332 class AsyncHiredisClusterCommandDispatcherDisconnectedTest: public AsyncHiredisClusterCommandDispatcherBaseTest
335 AsyncHiredisClusterCommandDispatcherDisconnectedTest()
338 expectationsUntilConnect();
339 expectAdapterSetup();
340 expectRedisClusterAsyncSetConnectCallback();
341 expectRedisClusterAsyncSetDisconnectCallback();
342 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
344 dispatcher.reset(new AsyncHiredisClusterCommandDispatcher(engineMock,
346 { { "addr1", 111 }, { "addr2", 222 } },
349 hiredisClusterSystemMock,
354 ~AsyncHiredisClusterCommandDispatcherDisconnectedTest()
359 class AsyncHiredisClusterCommandDispatcherWithPermanentCommandCallbacksTest: public AsyncHiredisClusterCommandDispatcherBaseTest
362 AsyncHiredisClusterCommandDispatcherWithPermanentCommandCallbacksTest()
365 expectionsForSuccessfullConnectionSetup();
366 dispatcher.reset(new AsyncHiredisClusterCommandDispatcher(engineMock,
368 { { "addr1", 111 }, { "addr2", 222 } },
371 hiredisClusterSystemMock,
376 ~AsyncHiredisClusterCommandDispatcherWithPermanentCommandCallbacksTest()
378 expectRedisClusterAsyncFree();
382 class AsyncHiredisClusterCommandDispatcherConnectedTest: public AsyncHiredisClusterCommandDispatcherBaseTest
385 redisClusterCallbackFn* savedCb;
388 AsyncHiredisClusterCommandDispatcherConnectedTest():
393 expectionsForSuccessfullConnectionSetup();
394 dispatcher.reset(new AsyncHiredisClusterCommandDispatcher(engineMock,
396 { { "addr1", 111 }, { "addr2", 222 } },
399 hiredisClusterSystemMock,
402 connected(&acc, &ac, 0);
405 ~AsyncHiredisClusterCommandDispatcherConnectedTest()
407 expectRedisClusterAsyncFree();
410 void expectRedisClusterAsyncCommandArgvWithKey_SaveCb()
412 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
414 .WillOnce(Invoke([this](redisClusterAsyncContext*, redisClusterCallbackFn* cb, void* pd,
415 const char*, int, int, const char**, const size_t*)
424 using AsyncHiredisClusterCommandDispatcherDeathTest = AsyncHiredisClusterCommandDispatcherConnectedTest;
427 TEST_F(AsyncHiredisClusterCommandDispatcherDisconnectedTest, IsNotCopyable)
429 EXPECT_FALSE(std::is_copy_constructible<AsyncHiredisClusterCommandDispatcher>::value);
430 EXPECT_FALSE(std::is_copy_assignable<AsyncHiredisClusterCommandDispatcher>::value);
433 TEST_F(AsyncHiredisClusterCommandDispatcherDisconnectedTest, ImplementsAsyncRedisCommandDispatcher)
435 EXPECT_TRUE((std::is_base_of<AsyncCommandDispatcher, AsyncHiredisClusterCommandDispatcher>::value));
438 TEST_F(AsyncHiredisClusterCommandDispatcherDisconnectedTest, CannotDispatchCommandsIfDisconnected)
440 Engine::Callback storedCallback;
441 EXPECT_CALL(engineMock, postCallback(_))
443 .WillOnce(SaveArg<0>(&storedCallback));
444 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherDisconnectedTest::ack,
446 std::placeholders::_1,
447 std::placeholders::_2),
450 expectAckError(AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED);
454 TEST_F(AsyncHiredisClusterCommandDispatcherBaseTest, ContextErrorInConnectArmsRetryTimer)
458 expectationsUntilConnect();
459 expectArmConnectionRetryTimer();
460 expectDisarmConnectionRetryTimer();
462 dispatcher.reset(new AsyncHiredisClusterCommandDispatcher(engineMock,
464 { { "addr1", 111 }, { "addr2", 222 } },
467 hiredisClusterSystemMock,
472 TEST_F(AsyncHiredisClusterCommandDispatcherBaseTest, NullRedisContextInConnectArmsRetryTimer)
475 expectRedisClusterAsyncConnectReturnNullptr();
476 expectArmConnectionRetryTimer();
477 expectDisarmConnectionRetryTimer();
479 dispatcher.reset(new AsyncHiredisClusterCommandDispatcher(engineMock,
481 { { "addr1", 111 }, { "addr2", 222 } },
484 hiredisClusterSystemMock,
489 TEST_F(AsyncHiredisClusterCommandDispatcherBaseTest, FailedCommandListQueryArmsRetryTimer)
492 Engine::Callback storedCallback;
493 expectationsUntilConnect();
494 expectAdapterSetup();
495 expectRedisClusterAsyncSetConnectCallback();
496 expectRedisClusterAsyncSetDisconnectCallback();
497 expectCommandListQueryReturnError();
498 expectArmConnectionRetryTimer();
500 dispatcher.reset(new AsyncHiredisClusterCommandDispatcher(engineMock,
502 { { "addr1", 111 }, { "addr2", 222 } },
505 hiredisClusterSystemMock,
509 expectDisarmConnectionRetryTimer();
512 TEST_F(AsyncHiredisClusterCommandDispatcherBaseTest, ConnectionSucceedsWithRetryTimer)
515 expectRedisClusterAsyncConnectReturnNullptr();
516 expectArmConnectionRetryTimer();
518 dispatcher.reset(new AsyncHiredisClusterCommandDispatcher(engineMock,
520 { { "addr1", 111 }, { "addr2", 222 } },
523 hiredisClusterSystemMock,
527 expectionsForSuccessfullConnectionSetup();
528 expectRedisClusterAsyncFree();
530 callConnectionRetryTimerCallback();
533 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, ConnectAckCalledIfConnected)
535 Engine::Callback storedCallback;
536 EXPECT_CALL(engineMock, postCallback(_))
538 .WillOnce(SaveArg<0>(&storedCallback));
539 dispatcher->waitConnectedAsync(std::bind(&AsyncHiredisClusterCommandDispatcherDisconnectedTest::connectAck,
545 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, CanDispatchCommands)
547 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
549 .WillOnce(Invoke([this](redisClusterAsyncContext* acc, redisClusterCallbackFn* cb, void* pd, const char *key,
550 int keylen, int argc, const char** argv, const size_t* argvlen)
552 EXPECT_STREQ(defaultNamespace.c_str(), key);
553 EXPECT_EQ(9, keylen);
554 EXPECT_EQ((int)contents.stack.size(), argc);
555 EXPECT_EQ(contents.sizes[0], argvlen[0]);
556 EXPECT_EQ(contents.sizes[1], argvlen[1]);
557 EXPECT_EQ(contents.sizes[2], argvlen[2]);
558 EXPECT_EQ(contents.sizes[3], argvlen[3]);
559 EXPECT_EQ(contents.sizes[4], argvlen[4]);
560 EXPECT_FALSE(std::memcmp(argv[0], contents.stack[0].c_str(), contents.sizes[0]));
561 EXPECT_FALSE(std::memcmp(argv[1], contents.stack[1].c_str(), contents.sizes[1]));
562 EXPECT_FALSE(std::memcmp(argv[2], contents.stack[2].c_str(), contents.sizes[2]));
563 EXPECT_FALSE(std::memcmp(argv[3], contents.stack[3].c_str(), contents.sizes[3]));
564 EXPECT_FALSE(std::memcmp(argv[4], contents.stack[4].c_str(), contents.sizes[4]));
565 cb(acc, &redisReplyBuilder.buildNilReply(), pd);
569 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
571 std::placeholders::_1,
572 std::placeholders::_2),
577 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, CanParseNilReply)
579 expectRedisClusterAsyncCommandArgv(redisReplyBuilder.buildNilReply());
580 EXPECT_CALL(*this, ack(std::error_code(), _))
582 .WillOnce(Invoke([](const std::error_code&, const Reply& reply)
584 EXPECT_EQ(Reply::Type::NIL, reply.getType());
585 EXPECT_EQ(0, reply.getInteger());
586 EXPECT_TRUE(reply.getString()->str.empty());
587 EXPECT_EQ(static_cast<ReplyStringLength>(0), reply.getString()->len);
588 EXPECT_TRUE(reply.getArray()->empty());
590 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
592 std::placeholders::_1,
593 std::placeholders::_2),
598 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, CanParseIntegerReply)
600 expectRedisClusterAsyncCommandArgv(redisReplyBuilder.buildIntegerReply());
601 EXPECT_CALL(*this, ack(std::error_code(), _))
603 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
605 auto expected(redisReplyBuilder.buildIntegerReply());
606 EXPECT_EQ(Reply::Type::INTEGER, reply.getType());
607 EXPECT_EQ(expected.integer, reply.getInteger());
609 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
611 std::placeholders::_1,
612 std::placeholders::_2),
617 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, CanParseStatusReply)
619 expectRedisClusterAsyncCommandArgv(redisReplyBuilder.buildStatusReply());
620 EXPECT_CALL(*this, ack(std::error_code(), _))
622 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
624 auto expected(redisReplyBuilder.buildStatusReply());
625 EXPECT_EQ(Reply::Type::STATUS, reply.getType());
626 EXPECT_EQ(expected.len, reply.getString()->len);
627 EXPECT_FALSE(std::memcmp(reply.getString()->str.c_str(), expected.str, expected.len));
629 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
631 std::placeholders::_1,
632 std::placeholders::_2),
637 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, CanParseStringReply)
639 expectRedisClusterAsyncCommandArgv(redisReplyBuilder.buildStringReply());
640 EXPECT_CALL(*this, ack(std::error_code(), _))
642 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
644 auto expected(redisReplyBuilder.buildStringReply());
645 EXPECT_EQ(Reply::Type::STRING, reply.getType());
646 EXPECT_EQ(expected.len, reply.getString()->len);
647 EXPECT_FALSE(std::memcmp(reply.getString()->str.c_str(), expected.str, expected.len));
649 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
651 std::placeholders::_1,
652 std::placeholders::_2),
657 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, CanParseArrayReply)
659 expectRedisClusterAsyncCommandArgv(redisReplyBuilder.buildArrayReply());
660 EXPECT_CALL(*this, ack(std::error_code(), _))
662 .WillOnce(Invoke([this](const std::error_code&, const Reply& reply)
664 auto array(reply.getArray());
665 EXPECT_EQ(Reply::Type::ARRAY, reply.getType());
666 EXPECT_EQ(Reply::Type::STRING, (*array)[0]->getType());
667 EXPECT_EQ(Reply::Type::NIL, (*array)[1]->getType());
669 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
671 std::placeholders::_1,
672 std::placeholders::_2),
677 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, CanHandleDispatchHiredisBufferErrors)
679 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
681 .WillOnce(Invoke([](redisClusterAsyncContext* acc, redisClusterCallbackFn*, void*, const char*, int, int,
682 const char**, const size_t*)
684 acc->err = REDIS_ERR;
687 Engine::Callback storedCallback;
688 EXPECT_CALL(engineMock, postCallback(_))
690 .WillOnce(SaveArg<0>(&storedCallback));
691 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
693 std::placeholders::_1,
694 std::placeholders::_2),
701 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, CanHandleDispatchHiredisCbErrors)
703 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
705 .WillOnce(Invoke([](redisClusterAsyncContext* acc, redisClusterCallbackFn* cb, void* pd, const char*, int, int,
706 const char**, const size_t*)
708 cb(acc, nullptr, pd);
712 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
714 std::placeholders::_1,
715 std::placeholders::_2),
720 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, DatasetStillBeingLoadedInMemoryIsRecognizedFromReply)
722 expectReplyError("LOADING Redis is loading the dataset in memory");
723 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING), _))
725 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
727 std::placeholders::_1,
728 std::placeholders::_2),
733 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, ClusterDownIsRecognizedFromReply)
735 //SDL checks only that reply starts with CLUSTERDOWN string
736 expectReplyError("CLUSTERDOWN");
737 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED), _))
739 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
741 std::placeholders::_1,
742 std::placeholders::_2),
746 expectReplyError("CLUSTERDOWN The cluster is down");
747 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED), _))
749 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
751 std::placeholders::_1,
752 std::placeholders::_2),
756 expectReplyError("CLUSTERDOW");
757 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR), _))
759 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
761 std::placeholders::_1,
762 std::placeholders::_2),
767 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, ProtocolErrorIsRecognizedFromReply)
769 expectReplyError("ERR Protocol error: invalid bulk length");
770 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR), _))
772 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
774 std::placeholders::_1,
775 std::placeholders::_2),
780 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, UnrecognizedReplyErrorIsConvertedToUnknownError)
782 expectReplyError("something sinister");
783 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR), _))
785 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
787 std::placeholders::_1,
788 std::placeholders::_2),
793 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, EmptyReplyErrorIsConvertedToUnknownError)
795 expectReplyError("");
796 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR), _))
798 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
800 std::placeholders::_1,
801 std::placeholders::_2),
806 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, IOErrorInContext)
808 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
810 .WillOnce(Invoke([](redisClusterAsyncContext* acc, redisClusterCallbackFn* cb, void* pd, const char*, int, int,
811 const char**, const size_t*)
813 acc->err = REDIS_ERR_IO;
815 cb(acc, nullptr, pd);
818 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::IO_ERROR), _))
820 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
822 std::placeholders::_1,
823 std::placeholders::_2),
828 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, EofErrorInContext)
830 expectContextError(REDIS_ERR_EOF);
831 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST), _))
833 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
835 std::placeholders::_1,
836 std::placeholders::_2),
841 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, ProtocolErrorInContext)
843 expectContextError(REDIS_ERR_PROTOCOL);
844 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR), _))
846 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
848 std::placeholders::_1,
849 std::placeholders::_2),
854 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, OomErrorInContext)
856 expectContextError(REDIS_ERR_OOM);
857 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY), _))
859 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
861 std::placeholders::_1,
862 std::placeholders::_2),
867 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, ClusterErrorNotConnectedInContext)
869 expectContextError(CLUSTER_ERROR_NOT_CONNECTED);
870 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED), _))
872 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
874 std::placeholders::_1,
875 std::placeholders::_2),
880 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, ClusterErrorConnectionLostInContext)
882 expectContextError(CLUSTER_ERROR_CONNECTION_LOST);
883 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST), _))
885 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
887 std::placeholders::_1,
888 std::placeholders::_2),
893 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, UnrecognizedContextErrorIsConvertedToUnknownError)
895 expectContextError(REDIS_ERR_OTHER);
896 EXPECT_CALL(*this, ack(std::error_code(AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR), _))
898 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::ack,
900 std::placeholders::_1,
901 std::placeholders::_2),
906 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, PendingClientCallbacksAreNotCalledAfterDisabled)
909 expectRedisClusterAsyncCommandArgvWithKey_SaveCb();
910 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherDeathTest::ack,
912 std::placeholders::_1,
913 std::placeholders::_2),
917 savedCb(&acc, &redisReplyBuilder.buildStringReply(), savedPd);
918 dispatcher->disableCommandCallbacks();
919 expectRedisClusterAsyncCommandArgvWithKey_SaveCb();
920 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherDeathTest::ack,
922 std::placeholders::_1,
923 std::placeholders::_2),
926 expectAckNotCalled();
927 savedCb(&acc, &redisReplyBuilder.buildStringReply(), savedPd);
930 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, DisconnectCallbackDetachesContextFromAdapter)
933 expectAdapterDetach();
934 disconnected(&acc, &ac, 0);
937 TEST_F(AsyncHiredisClusterCommandDispatcherConnectedTest, RegisteredClientDisconnectCallbackIsCalled)
940 dispatcher->registerDisconnectCb(std::bind(&AsyncHiredisClusterCommandDispatcherConnectedTest::disconnectCallback,
942 expectAdapterDetach();
943 expectDisconnectCallback();
944 disconnected(&acc, &ac, 0);
947 TEST_F(AsyncHiredisClusterCommandDispatcherWithPermanentCommandCallbacksTest, CanHandleMultipleRepliesForSameRedisCommand)
950 redisClusterCallbackFn* savedCb;
952 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
954 .WillOnce(Invoke([&savedCb, &savedPd](redisClusterAsyncContext*, redisClusterCallbackFn* cb, void* pd,
955 const char*, int, int, const char**, const size_t*)
961 Contents contents({ { "cmd", "key", "value" }, { 3, 3, 5 } });
962 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherDeathTest::ack,
964 std::placeholders::_1,
965 std::placeholders::_2),
968 EXPECT_CALL(*this, ack(std::error_code(), _))
971 rr.type = REDIS_REPLY_NIL;
972 savedCb(&acc, &rr, savedPd);
973 savedCb(&acc, &rr, savedPd);
974 savedCb(&acc, &rr, savedPd);
977 TEST_F(AsyncHiredisClusterCommandDispatcherDeathTest, CbRemovedAfterHiredisCb)
980 redisClusterCallbackFn* savedCb;
982 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
984 .WillOnce(Invoke([this, &savedCb, &savedPd](redisClusterAsyncContext* acc, redisClusterCallbackFn* cb, void* pd,
985 const char*, int, int, const char**, const size_t*)
989 cb(acc, &redisReplyBuilder.buildNilReply(), pd);
993 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherDeathTest::ack,
995 std::placeholders::_1,
996 std::placeholders::_2),
999 EXPECT_EXIT(savedCb(&acc, &redisReplyBuilder.buildNilReply(), savedPd), KilledBySignal(SIGABRT), "");
1002 TEST_F(AsyncHiredisClusterCommandDispatcherDeathTest, TooManyRepliesAborts)
1005 redisClusterCallbackFn* savedCb;
1007 EXPECT_CALL(hiredisClusterSystemMock, redisClusterAsyncCommandArgvWithKey(&acc, _, _, _, _, _, _, _))
1009 .WillOnce(Invoke([&savedCb, &savedPd](redisClusterAsyncContext*, redisClusterCallbackFn* cb, void* pd,
1010 const char*, int, int, const char**, const size_t*)
1016 Contents contents({ { "cmd", "key", "value" }, { 3, 3, 5 } });
1018 dispatcher->dispatchAsync(std::bind(&AsyncHiredisClusterCommandDispatcherDeathTest::ack,
1020 std::placeholders::_1,
1021 std::placeholders::_2),
1024 savedCb(&acc, &redisReplyBuilder.buildNilReply(), savedPd);
1025 EXPECT_EXIT(savedCb(&acc, &redisReplyBuilder.buildNilReply(), savedPd), KilledBySignal(SIGABRT), "");