ab482846710c781d7a4c93d986d4d66662be8435
[ric-plt/sdl.git] / tst / asyncsentineldatabasediscovery_test.cpp
1 /*
2    Copyright (c) 2018-2019 Nokia.
3
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
7
8        http://www.apache.org/licenses/LICENSE-2.0
9
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.
15 */
16
17 #include <gtest/gtest.h>
18 #include <arpa/inet.h>
19 #include <string>
20 #include <sdl/asyncstorage.hpp>
21 #include "private/createlogger.hpp"
22 #include "private/hostandport.hpp"
23 #include "private/timer.hpp"
24 #include "private/redis/asyncsentineldatabasediscovery.hpp"
25 #include "private/tst/asynccommanddispatchermock.hpp"
26 #include "private/tst/contentsbuildermock.hpp"
27 #include "private/tst/enginemock.hpp"
28 #include "private/tst/replymock.hpp"
29 #include "private/tst/wellknownerrorcode.hpp"
30
31 using namespace shareddatalayer;
32 using namespace shareddatalayer::redis;
33 using namespace shareddatalayer::tst;
34 using namespace testing;
35
36 namespace
37 {
38     class AsyncSentinelDatabaseDiscoveryBaseTest: public testing::Test
39     {
40     public:
41         std::unique_ptr<AsyncSentinelDatabaseDiscovery> asyncSentinelDatabaseDiscovery;
42         std::shared_ptr<StrictMock<EngineMock>> engineMock;
43         std::shared_ptr<StrictMock<AsyncCommandDispatcherMock>> subscriberMock;
44         std::shared_ptr<StrictMock<AsyncCommandDispatcherMock>> dispatcherMock;
45         std::shared_ptr<StrictMock<ContentsBuilderMock>> contentsBuilderMock;
46         std::shared_ptr<Logger> logger;
47         Contents contents;
48         AsyncCommandDispatcher::ConnectAck subscriberConnectAck;
49         AsyncCommandDispatcher::DisconnectCb subscriberDisconnectCb;
50         AsyncCommandDispatcher::ConnectAck dispatcherConnectAck;
51         AsyncCommandDispatcher::CommandCb savedSubscriberCommandCb;
52         AsyncCommandDispatcher::CommandCb savedDispatcherCommandCb;
53         ReplyMock masterInquiryReplyMock;
54         std::string someHost;
55         uint16_t somePort;
56         std::string someOtherHost;
57         uint16_t someOtherPort;
58         Reply::DataItem hostDataItem;
59         Reply::DataItem portDataItem;
60         std::shared_ptr<ReplyMock> masterInquiryReplyHost;
61         std::shared_ptr<ReplyMock> masterInquiryReplyPort;
62         Reply::ReplyVector masterInquiryReply;
63         Timer::Duration expectedMasterInquiryRetryTimerDuration;
64         Timer::Callback savedMasterInquiryRetryTimerCallback;
65         // Mocks for SUBSCRIBE command replies are a bit complicated, because reply might have several
66         // meanings/structures: https://redis.io/topics/pubsub#format-of-pushed-messages
67         ReplyMock subscribeReplyMock;
68         std::shared_ptr<ReplyMock> subscribeReplyArrayElement0;
69         std::shared_ptr<ReplyMock> subscribeReplyArrayElement1;
70         std::shared_ptr<ReplyMock> subscribeReplyArrayElement2;
71         Reply::ReplyVector subscribeReplyVector;
72         Reply::DataItem subscribeDataItem;
73         ReplyMock notificationReplyMock;
74         std::shared_ptr<ReplyMock> notificationReplyArrayElement0;
75         std::shared_ptr<ReplyMock> notificationReplyArrayElement1;
76         std::shared_ptr<ReplyMock> notificationReplyArrayElement2;
77         Reply::ReplyVector notificationReplyVector;
78         Reply::DataItem notificationDataItem;
79         std::string notificationMessage;
80         Reply::DataItem notificationMessageDataItem;
81         Timer::Duration expectedSubscribeRetryTimerDuration;
82         Timer::Callback savedSubscribeRetryTimerCallback;
83
84         AsyncSentinelDatabaseDiscoveryBaseTest():
85             engineMock(std::make_shared<StrictMock<EngineMock>>()),
86             contentsBuilderMock(std::make_shared<StrictMock<ContentsBuilderMock>>(AsyncStorage::SEPARATOR)),
87             logger(createLogger(SDL_LOG_PREFIX)),
88             contents({{"aaa","bbb"},{3,3}}),
89             someHost("somehost"),
90             somePort(1234),
91             someOtherHost("someotherhost"),
92             someOtherPort(5678),
93             hostDataItem({someHost,ReplyStringLength(someHost.length())}),
94             portDataItem({std::to_string(somePort),ReplyStringLength(std::to_string(somePort).length())}),
95             masterInquiryReplyHost(std::make_shared<ReplyMock>()),
96             masterInquiryReplyPort(std::make_shared<ReplyMock>()),
97             expectedMasterInquiryRetryTimerDuration(std::chrono::seconds(1)),
98             subscribeReplyArrayElement0(std::make_shared<ReplyMock>()),
99             subscribeReplyArrayElement1(std::make_shared<ReplyMock>()),
100             subscribeReplyArrayElement2(std::make_shared<ReplyMock>()),
101             subscribeDataItem({"subscribe",9}),
102             notificationReplyArrayElement0(std::make_shared<ReplyMock>()),
103             notificationReplyArrayElement1(std::make_shared<ReplyMock>()),
104             notificationReplyArrayElement2(std::make_shared<ReplyMock>()),
105             notificationDataItem({"message",7}),
106             notificationMessage("mymaster " + someHost + " " + std::to_string(somePort) + " " + someOtherHost + " " + std::to_string(someOtherPort)),
107             notificationMessageDataItem({notificationMessage, ReplyStringLength(notificationMessage.length())}),
108             expectedSubscribeRetryTimerDuration(std::chrono::seconds(1))
109         {
110             masterInquiryReply.push_back(masterInquiryReplyHost);
111             masterInquiryReply.push_back(masterInquiryReplyPort);
112             subscribeReplyVector.push_back(subscribeReplyArrayElement0);
113             subscribeReplyVector.push_back(subscribeReplyArrayElement1);
114             subscribeReplyVector.push_back(subscribeReplyArrayElement2);
115             notificationReplyVector.push_back(notificationReplyArrayElement0);
116             notificationReplyVector.push_back(notificationReplyArrayElement1);
117             notificationReplyVector.push_back(notificationReplyArrayElement2);
118         }
119
120         virtual ~AsyncSentinelDatabaseDiscoveryBaseTest()
121         {
122         }
123
124         std::shared_ptr<AsyncCommandDispatcher> asyncCommandDispatcherCreator()
125         {
126             // @TODO Add database info checking when configuration support for sentinel is added.
127             if (!subscriberMock)
128             {
129                 subscriberMock = std::make_shared<StrictMock<AsyncCommandDispatcherMock>>();
130                 newDispatcherCreated();
131                 return subscriberMock;
132             }
133             if (!dispatcherMock)
134             {
135                 dispatcherMock = std::make_shared<StrictMock<AsyncCommandDispatcherMock>>();
136                 newDispatcherCreated();
137                 return dispatcherMock;
138             }
139             return nullptr;
140         }
141
142         MOCK_METHOD0(newDispatcherCreated, void());
143
144         void expectDispatchersCreated()
145         {
146             EXPECT_CALL(*this, newDispatcherCreated())
147                 .Times(2);
148         }
149
150         void expectSubscriberWaitConnectedAsync()
151         {
152             EXPECT_CALL(*subscriberMock, waitConnectedAsync(_))
153                 .Times(1)
154                 .WillOnce(Invoke([this](const AsyncCommandDispatcher::ConnectAck& connectAck)
155                         {
156                             subscriberConnectAck = connectAck;
157                         }));
158         }
159
160         void expectSubscriberRegisterDisconnectCb()
161         {
162             EXPECT_CALL(*subscriberMock, registerDisconnectCb(_))
163                 .Times(1)
164                 .WillOnce(Invoke([this](const AsyncCommandDispatcher::DisconnectCb& disconnectCb)
165                         {
166                             subscriberDisconnectCb = disconnectCb;
167                         }));
168         }
169
170         void expectDispatcherWaitConnectedAsync()
171         {
172             EXPECT_CALL(*dispatcherMock, waitConnectedAsync(_))
173                 .Times(1)
174                 .WillOnce(Invoke([this](const AsyncCommandDispatcher::ConnectAck& connectAck)
175                         {
176                             dispatcherConnectAck = connectAck;
177                         }));
178         }
179
180         void expectContentsBuild(const std::string& string,
181                                  const std::string& string2)
182         {
183             EXPECT_CALL(*contentsBuilderMock, build(string, string2))
184                 .Times(1)
185                 .WillOnce(Return(contents));
186         }
187
188         void expectContentsBuild(const std::string& string,
189                                  const std::string& string2,
190                                  const std::string& string3)
191         {
192             EXPECT_CALL(*contentsBuilderMock, build(string, string2, string3))
193                 .Times(1)
194                 .WillOnce(Return(contents));
195         }
196
197         void expectSubscriberDispatchAsync()
198         {
199             EXPECT_CALL(*subscriberMock, dispatchAsync(_, _, contents))
200                 .Times(1)
201                 .WillOnce(SaveArg<0>(&savedSubscriberCommandCb));
202         }
203
204         void expectDispatcherDispatchAsync()
205         {
206             EXPECT_CALL(*dispatcherMock, dispatchAsync(_, _, contents))
207                 .Times(1)
208                 .WillOnce(SaveArg<0>(&savedDispatcherCommandCb));
209         }
210
211         void expectSubscribeNotifications()
212         {
213             expectContentsBuild("SUBSCRIBE", "+switch-master");
214             expectSubscriberDispatchAsync();
215         }
216
217         void expectMasterInquiry()
218         {
219             expectContentsBuild("SENTINEL", "get-master-addr-by-name", "mymaster");
220             expectDispatcherDispatchAsync();
221         }
222
223         MOCK_METHOD1(stateChangedCb, void(const DatabaseInfo&));
224
225         void expectStateChangedCb(const std::string& host, uint16_t port)
226         {
227             EXPECT_CALL(*this, stateChangedCb(_))
228                 .Times(1)
229                 .WillOnce(Invoke([this, host, port](const DatabaseInfo& databaseInfo)
230                                  {
231                                      EXPECT_THAT(DatabaseConfiguration::Addresses({ HostAndPort(host, htons(port)) }),
232                                                  ContainerEq(databaseInfo.hosts));
233                                      EXPECT_EQ(DatabaseInfo::Type::SINGLE, databaseInfo.type);
234                                      EXPECT_EQ(boost::none, databaseInfo.ns);
235                                      EXPECT_EQ(DatabaseInfo::Discovery::SENTINEL, databaseInfo.discovery);
236                                  }));
237         }
238
239         void expectMasterIquiryReply()
240         {
241             expectGetType(masterInquiryReplyMock, Reply::Type::ARRAY);
242             expectGetArray(masterInquiryReplyMock, masterInquiryReply);
243             expectGetType(*masterInquiryReplyHost, Reply::Type::STRING);
244             expectGetString(*masterInquiryReplyHost, hostDataItem);
245             expectGetType(*masterInquiryReplyPort, Reply::Type::STRING);
246             expectGetString(*masterInquiryReplyPort, portDataItem);
247         }
248
249         void expectMasterInquiryRetryTimer()
250         {
251             EXPECT_CALL(*engineMock, armTimer(_, expectedMasterInquiryRetryTimerDuration, _))
252                 .Times(1)
253                 .WillOnce(SaveArg<2>(&savedMasterInquiryRetryTimerCallback));
254         }
255
256         void expectSubscribeRetryTimer()
257         {
258             EXPECT_CALL(*engineMock, armTimer(_, expectedSubscribeRetryTimerDuration, _))
259                 .Times(1)
260                 .WillOnce(SaveArg<2>(&savedSubscribeRetryTimerCallback));
261         }
262
263         void setStateChangedCbExpectsBeforeMasterInquiry()
264         {
265             expectSubscriberRegisterDisconnectCb();
266             expectSubscriberWaitConnectedAsync();
267             asyncSentinelDatabaseDiscovery->setStateChangedCb(std::bind(&AsyncSentinelDatabaseDiscoveryBaseTest::stateChangedCb,
268                     this,
269                     std::placeholders::_1));
270             expectSubscribeNotifications();
271             subscriberConnectAck();
272             expectSubscribeReply();
273             expectDispatcherWaitConnectedAsync();
274             savedSubscriberCommandCb(std::error_code(), subscribeReplyMock);
275             expectMasterInquiry();
276         }
277
278         void setDefaultResponsesForMasterInquiryReplyParsing()
279         {
280             ON_CALL(masterInquiryReplyMock, getType())
281                 .WillByDefault(Return(Reply::Type::ARRAY));
282             ON_CALL(masterInquiryReplyMock, getArray())
283                 .WillByDefault(Return(&masterInquiryReply));
284             ON_CALL(*masterInquiryReplyHost, getType())
285                 .WillByDefault(Return(Reply::Type::STRING));
286             ON_CALL(*masterInquiryReplyHost, getString())
287                 .WillByDefault(Return(&hostDataItem));
288             ON_CALL(*masterInquiryReplyPort, getType())
289                 .WillByDefault(Return(Reply::Type::STRING));
290             ON_CALL(*masterInquiryReplyHost, getString())
291                 .WillByDefault(Return(&portDataItem));
292         }
293
294         void expectGetType(ReplyMock& mock, const Reply::Type& type)
295         {
296             EXPECT_CALL(mock, getType())
297                 .Times(1)
298                 .WillOnce(Return(type));
299         }
300
301         void expectGetString(ReplyMock& mock, const Reply::DataItem& item)
302         {
303             EXPECT_CALL(mock, getString())
304                 .Times(1)
305                 .WillOnce(Return(&item));
306         }
307
308         void expectGetInteger(ReplyMock& mock, int value)
309         {
310             EXPECT_CALL(mock, getInteger())
311                 .Times(1)
312                 .WillOnce(Return(value));
313         }
314
315         void expectGetArray(ReplyMock& mock, Reply::ReplyVector& replyVector)
316         {
317             EXPECT_CALL(mock, getArray())
318                 .Times(1)
319                 .WillOnce(Return(&replyVector));
320         }
321
322         void expectSubscribeReply()
323         {
324             expectGetType(subscribeReplyMock, Reply::Type::ARRAY);
325             expectGetArray(subscribeReplyMock, subscribeReplyVector);
326             expectGetType(*subscribeReplyArrayElement0, Reply::Type::STRING);
327             expectGetString(*subscribeReplyArrayElement0, subscribeDataItem);
328         }
329
330         void expectNotificationReply()
331         {
332             expectGetType(notificationReplyMock, Reply::Type::ARRAY);
333             expectGetArray(notificationReplyMock, notificationReplyVector);
334             expectGetType(*notificationReplyArrayElement0, Reply::Type::STRING);
335             expectGetString(*notificationReplyArrayElement0, notificationDataItem);
336             expectGetType(*notificationReplyArrayElement2, Reply::Type::STRING);
337             expectGetString(*notificationReplyArrayElement2, notificationMessageDataItem);
338         }
339
340         void setDefaultResponsesForNotificationReplyParsing()
341         {
342             ON_CALL(notificationReplyMock, getType())
343                 .WillByDefault(Return(Reply::Type::ARRAY));
344             ON_CALL(notificationReplyMock, getArray())
345                 .WillByDefault(Return(&notificationReplyVector));
346             ON_CALL(*notificationReplyArrayElement0, getType())
347                 .WillByDefault(Return(Reply::Type::STRING));
348             ON_CALL(*notificationReplyArrayElement0, getString())
349                 .WillByDefault(Return(&notificationDataItem));
350             ON_CALL(*notificationReplyArrayElement2, getType())
351                 .WillByDefault(Return(Reply::Type::STRING));
352             ON_CALL(*notificationReplyArrayElement2, getString())
353                 .WillByDefault(Return(&notificationMessageDataItem));
354         }
355     };
356
357     class AsyncSentinelDatabaseDiscoveryTest: public AsyncSentinelDatabaseDiscoveryBaseTest
358     {
359     public:
360         AsyncSentinelDatabaseDiscoveryTest()
361         {
362             expectDispatchersCreated();
363             asyncSentinelDatabaseDiscovery.reset(
364                     new AsyncSentinelDatabaseDiscovery(
365                             engineMock,
366                             logger,
367                             std::bind(&AsyncSentinelDatabaseDiscoveryBaseTest::asyncCommandDispatcherCreator,
368                                       this),
369                             contentsBuilderMock));
370         }
371
372         ~AsyncSentinelDatabaseDiscoveryTest()
373         {
374             EXPECT_CALL(*subscriberMock, disableCommandCallbacks())
375                 .Times(1);
376             EXPECT_CALL(*dispatcherMock, disableCommandCallbacks())
377                 .Times(1);
378         }
379     };
380
381     class AsyncSentinelDatabaseDiscoveryInListeningModeTest: public AsyncSentinelDatabaseDiscoveryTest
382     {
383     public:
384         AsyncSentinelDatabaseDiscoveryInListeningModeTest()
385         {
386             InSequence dummy;
387             setStateChangedCbExpectsBeforeMasterInquiry();
388             dispatcherConnectAck();
389             expectMasterIquiryReply();
390             expectStateChangedCb(someHost, somePort);
391             savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
392         }
393     };
394
395     using AsyncSentinelDatabaseDiscoveryDeathTest = AsyncSentinelDatabaseDiscoveryTest;
396
397     using AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest = AsyncSentinelDatabaseDiscoveryInListeningModeTest;
398 }
399
400 TEST_F(AsyncSentinelDatabaseDiscoveryBaseTest, IsNotCopyable)
401 {
402     InSequence dummy;
403     EXPECT_FALSE(std::is_copy_constructible<AsyncSentinelDatabaseDiscovery>::value);
404     EXPECT_FALSE(std::is_copy_assignable<AsyncSentinelDatabaseDiscovery>::value);
405 }
406
407 TEST_F(AsyncSentinelDatabaseDiscoveryBaseTest, ImplementsAsyncDatabaseDiscovery)
408 {
409     InSequence dummy;
410     EXPECT_TRUE((std::is_base_of<AsyncDatabaseDiscovery, AsyncSentinelDatabaseDiscovery>::value));
411 }
412
413 TEST_F(AsyncSentinelDatabaseDiscoveryTest, SettingChangedCallbackTriggersSentinelNotificationsSubscriptionAndMasterInquiry)
414 {
415     InSequence dummy;
416     setStateChangedCbExpectsBeforeMasterInquiry();
417     dispatcherConnectAck();
418     expectMasterIquiryReply();
419     expectStateChangedCb(someHost, somePort);
420     savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
421 }
422
423 TEST_F(AsyncSentinelDatabaseDiscoveryTest, MasterInquiryErrorTriggersRetry)
424 {
425     InSequence dummy;
426     setStateChangedCbExpectsBeforeMasterInquiry();
427     dispatcherConnectAck();
428     expectMasterInquiryRetryTimer();
429     savedDispatcherCommandCb(getWellKnownErrorCode(), masterInquiryReplyMock);
430     expectMasterInquiry();
431     savedMasterInquiryRetryTimerCallback();
432     expectMasterIquiryReply();
433     expectStateChangedCb(someHost, somePort);
434     savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
435 }
436
437 TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidReplyType)
438 {
439     InSequence dummy;
440     setStateChangedCbExpectsBeforeMasterInquiry();
441     dispatcherConnectAck();
442     ON_CALL(masterInquiryReplyMock, getType())
443         .WillByDefault(Return(Reply::Type::NIL));
444     EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
445 }
446
447 TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidHostElementType)
448 {
449     InSequence dummy;
450     setStateChangedCbExpectsBeforeMasterInquiry();
451     dispatcherConnectAck();
452     setDefaultResponsesForMasterInquiryReplyParsing();
453     ON_CALL(*masterInquiryReplyHost, getType())
454         .WillByDefault(Return(Reply::Type::NIL));
455     EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
456 }
457
458 TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidPortElementType)
459 {
460     InSequence dummy;
461     setStateChangedCbExpectsBeforeMasterInquiry();
462     dispatcherConnectAck();
463     setDefaultResponsesForMasterInquiryReplyParsing();
464     ON_CALL(*masterInquiryReplyPort, getType())
465         .WillByDefault(Return(Reply::Type::NIL));
466     EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
467 }
468
469 TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_PortCantBeCastedToInt)
470 {
471     InSequence dummy;
472     setStateChangedCbExpectsBeforeMasterInquiry();
473     dispatcherConnectAck();
474     setDefaultResponsesForMasterInquiryReplyParsing();
475     std::string invalidPort("invalidPort");
476     Reply::DataItem invalidPortDataItem({invalidPort,ReplyStringLength(invalidPort.length())});
477     ON_CALL(*masterInquiryReplyPort, getString())
478         .WillByDefault(Return(&invalidPortDataItem));
479     EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
480 }
481
482 TEST_F(AsyncSentinelDatabaseDiscoveryTest, CallbackIsNotCalledAfterCleared)
483 {
484     InSequence dummy;
485     setStateChangedCbExpectsBeforeMasterInquiry();
486     dispatcherConnectAck();
487     expectMasterInquiryRetryTimer();
488     savedDispatcherCommandCb(getWellKnownErrorCode(), masterInquiryReplyMock);
489     expectMasterInquiry();
490     savedMasterInquiryRetryTimerCallback();
491     expectMasterIquiryReply();
492     asyncSentinelDatabaseDiscovery->clearStateChangedCb();
493     EXPECT_CALL(*this, stateChangedCb(_))
494         .Times(0);
495     savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
496 }
497
498 TEST_F(AsyncSentinelDatabaseDiscoveryTest, ChangeNotificationFromSentinel)
499 {
500     InSequence dummy;
501     setStateChangedCbExpectsBeforeMasterInquiry();
502     dispatcherConnectAck();
503     expectMasterIquiryReply();
504     expectStateChangedCb(someHost, somePort);
505     savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
506     expectNotificationReply();
507     expectStateChangedCb(someOtherHost, someOtherPort);
508     savedSubscriberCommandCb(std::error_code(), notificationReplyMock);
509 }
510
511 TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeTest, SubscribeCommandErrorTriggersRetry)
512 {
513     InSequence dummy;
514     expectSubscribeRetryTimer();
515     savedSubscriberCommandCb(getWellKnownErrorCode(), subscribeReplyMock);
516     expectSubscribeNotifications();
517     savedSubscribeRetryTimerCallback();
518 }
519
520 TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidReplyType)
521 {
522     InSequence dummy;
523     ON_CALL(notificationReplyMock, getType())
524         .WillByDefault(Return(Reply::Type::NIL));
525     EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*SUBSCRIBE command reply parsing error");
526 }
527
528 TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidKindElementType)
529 {
530     InSequence dummy;
531     setDefaultResponsesForNotificationReplyParsing();
532     ON_CALL(*notificationReplyArrayElement0, getType())
533         .WillByDefault(Return(Reply::Type::NIL));
534     EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*SUBSCRIBE command reply parsing error");
535 }
536
537 TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidKind)
538 {
539     InSequence dummy;
540     setDefaultResponsesForNotificationReplyParsing();
541     std::string invalidKind("invalidKind");
542     Reply::DataItem invalidKindDataItem({invalidKind,ReplyStringLength(invalidKind.length())});
543     ON_CALL(*notificationReplyArrayElement0, getString())
544         .WillByDefault(Return(&invalidKindDataItem));
545     EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*SUBSCRIBE command reply parsing error");
546 }
547
548 TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidMessageElementType)
549 {
550     InSequence dummy;
551     setDefaultResponsesForNotificationReplyParsing();
552     ON_CALL(*notificationReplyArrayElement2, getType())
553         .WillByDefault(Return(Reply::Type::NIL));
554     EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*SUBSCRIBE command reply parsing error");
555 }
556
557 TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidMessageStructure)
558 {
559     InSequence dummy;
560     setDefaultResponsesForNotificationReplyParsing();
561     std::string invalidMessage("mymaster oldHost 1234 5678");
562     auto invalidMessageDataItem(Reply::DataItem({invalidMessage, ReplyStringLength(invalidMessage.length())}));
563     ON_CALL(*notificationReplyArrayElement2, getString())
564         .WillByDefault(Return(&invalidMessageDataItem));
565     EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*Notification message parsing error");
566 }
567
568 TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidPort)
569 {
570     InSequence dummy;
571     setDefaultResponsesForNotificationReplyParsing();
572     std::string invalidMessage("mymaster oldHost 1234 newHost invalidPort");
573     auto invalidMessageDataItem(Reply::DataItem({invalidMessage, ReplyStringLength(invalidMessage.length())}));
574     ON_CALL(*notificationReplyArrayElement2, getString())
575         .WillByDefault(Return(&invalidMessageDataItem));
576     EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*Notification message parsing error");
577 }
578
579 TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeTest, SubscriberDisconnectCallbackTriggersSubscriptionRenewal)
580 {
581     InSequence dummy;
582     expectSubscriberWaitConnectedAsync();
583     subscriberDisconnectCb();
584     expectSubscribeNotifications();
585     subscriberConnectAck();
586     expectSubscribeReply();
587     expectDispatcherWaitConnectedAsync();
588     savedSubscriberCommandCb(std::error_code(), subscribeReplyMock);
589     expectMasterInquiry();
590     dispatcherConnectAck();
591     expectMasterIquiryReply();
592     expectStateChangedCb(someHost, somePort);
593     savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
594 }