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