blob: f6c43fa216763cdbc2acbd70eea573dad3cb3e1c [file] [log] [blame]
Rolf Badorek8324d022019-09-17 16:47:20 +03001/*
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>
Rolf Badorekb7f49712019-09-23 14:14:56 +030019#include <string>
Rolf Badorek8324d022019-09-17 16:47:20 +030020#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
31using namespace shareddatalayer;
32using namespace shareddatalayer::redis;
33using namespace shareddatalayer::tst;
34using namespace testing;
35
36namespace
37{
38 class AsyncSentinelDatabaseDiscoveryBaseTest: public testing::Test
39 {
40 public:
41 std::unique_ptr<AsyncSentinelDatabaseDiscovery> asyncSentinelDatabaseDiscovery;
42 std::shared_ptr<StrictMock<EngineMock>> engineMock;
Rolf Badorekb7f49712019-09-23 14:14:56 +030043 std::shared_ptr<StrictMock<AsyncCommandDispatcherMock>> subscriberMock;
Rolf Badorek8324d022019-09-17 16:47:20 +030044 std::shared_ptr<StrictMock<AsyncCommandDispatcherMock>> dispatcherMock;
45 std::shared_ptr<StrictMock<ContentsBuilderMock>> contentsBuilderMock;
46 std::shared_ptr<Logger> logger;
47 Contents contents;
Rolf Badorekb7f49712019-09-23 14:14:56 +030048 AsyncCommandDispatcher::ConnectAck subscriberConnectAck;
49 AsyncCommandDispatcher::DisconnectCb subscriberDisconnectCb;
Rolf Badorek8324d022019-09-17 16:47:20 +030050 AsyncCommandDispatcher::ConnectAck dispatcherConnectAck;
Rolf Badorekb7f49712019-09-23 14:14:56 +030051 AsyncCommandDispatcher::CommandCb savedSubscriberCommandCb;
52 AsyncCommandDispatcher::CommandCb savedDispatcherCommandCb;
53 ReplyMock masterInquiryReplyMock;
Rolf Badorek8324d022019-09-17 16:47:20 +030054 std::string someHost;
55 uint16_t somePort;
Rolf Badorekb7f49712019-09-23 14:14:56 +030056 std::string someOtherHost;
57 uint16_t someOtherPort;
Rolf Badorek8324d022019-09-17 16:47:20 +030058 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;
Rolf Badorekb7f49712019-09-23 14:14:56 +030064 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;
Rolf Badorek8324d022019-09-17 16:47:20 +030083
84 AsyncSentinelDatabaseDiscoveryBaseTest():
85 engineMock(std::make_shared<StrictMock<EngineMock>>()),
Rolf Badorek8324d022019-09-17 16:47:20 +030086 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),
Rolf Badorekb7f49712019-09-23 14:14:56 +030091 someOtherHost("someotherhost"),
92 someOtherPort(5678),
Rolf Badorek8324d022019-09-17 16:47:20 +030093 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>()),
Rolf Badorekb7f49712019-09-23 14:14:56 +030097 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))
Rolf Badorek8324d022019-09-17 16:47:20 +0300109 {
110 masterInquiryReply.push_back(masterInquiryReplyHost);
111 masterInquiryReply.push_back(masterInquiryReplyPort);
Rolf Badorekb7f49712019-09-23 14:14:56 +0300112 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);
Rolf Badorek8324d022019-09-17 16:47:20 +0300118 }
119
120 virtual ~AsyncSentinelDatabaseDiscoveryBaseTest()
121 {
122 }
123
Rolf Badorekb7f49712019-09-23 14:14:56 +0300124 std::shared_ptr<AsyncCommandDispatcher> asyncCommandDispatcherCreator()
Rolf Badorek8324d022019-09-17 16:47:20 +0300125 {
126 // @TODO Add database info checking when configuration support for sentinel is added.
Rolf Badorekb7f49712019-09-23 14:14:56 +0300127 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;
Rolf Badorek8324d022019-09-17 16:47:20 +0300140 }
141
142 MOCK_METHOD0(newDispatcherCreated, void());
143
Rolf Badorekb7f49712019-09-23 14:14:56 +0300144 void expectDispatchersCreated()
Rolf Badorek8324d022019-09-17 16:47:20 +0300145 {
146 EXPECT_CALL(*this, newDispatcherCreated())
Rolf Badorekb7f49712019-09-23 14:14:56 +0300147 .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 }));
Rolf Badorek8324d022019-09-17 16:47:20 +0300168 }
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,
Rolf Badorekb7f49712019-09-23 14:14:56 +0300181 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,
Rolf Badorek8324d022019-09-17 16:47:20 +0300189 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
Rolf Badorekb7f49712019-09-23 14:14:56 +0300197 void expectSubscriberDispatchAsync()
198 {
199 EXPECT_CALL(*subscriberMock, dispatchAsync(_, _, contents))
200 .Times(1)
201 .WillOnce(SaveArg<0>(&savedSubscriberCommandCb));
202 }
203
204 void expectDispatcherDispatchAsync()
Rolf Badorek8324d022019-09-17 16:47:20 +0300205 {
206 EXPECT_CALL(*dispatcherMock, dispatchAsync(_, _, contents))
207 .Times(1)
Rolf Badorekb7f49712019-09-23 14:14:56 +0300208 .WillOnce(SaveArg<0>(&savedDispatcherCommandCb));
209 }
210
211 void expectSubscribeNotifications()
212 {
213 expectContentsBuild("SUBSCRIBE", "+switch-master");
214 expectSubscriberDispatchAsync();
Rolf Badorek8324d022019-09-17 16:47:20 +0300215 }
216
217 void expectMasterInquiry()
218 {
219 expectContentsBuild("SENTINEL", "get-master-addr-by-name", "mymaster");
Rolf Badorekb7f49712019-09-23 14:14:56 +0300220 expectDispatcherDispatchAsync();
Rolf Badorek8324d022019-09-17 16:47:20 +0300221 }
222
223 MOCK_METHOD1(stateChangedCb, void(const DatabaseInfo&));
224
Rolf Badorekb7f49712019-09-23 14:14:56 +0300225 void expectStateChangedCb(const std::string& host, uint16_t port)
Rolf Badorek8324d022019-09-17 16:47:20 +0300226 {
227 EXPECT_CALL(*this, stateChangedCb(_))
228 .Times(1)
Rolf Badorekb7f49712019-09-23 14:14:56 +0300229 .WillOnce(Invoke([this, host, port](const DatabaseInfo& databaseInfo)
Rolf Badorek8324d022019-09-17 16:47:20 +0300230 {
Rolf Badorekb7f49712019-09-23 14:14:56 +0300231 EXPECT_THAT(DatabaseConfiguration::Addresses({ HostAndPort(host, htons(port)) }),
Rolf Badorek8324d022019-09-17 16:47:20 +0300232 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
Rolf Badorek8324d022019-09-17 16:47:20 +0300239 void expectMasterIquiryReply()
240 {
Rolf Badorekb7f49712019-09-23 14:14:56 +0300241 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);
Rolf Badorek8324d022019-09-17 16:47:20 +0300247 }
248
249 void expectMasterInquiryRetryTimer()
250 {
251 EXPECT_CALL(*engineMock, armTimer(_, expectedMasterInquiryRetryTimerDuration, _))
252 .Times(1)
Rolf Badorekb7f49712019-09-23 14:14:56 +0300253 .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();
Rolf Badorek8324d022019-09-17 16:47:20 +0300276 }
277
278 void setDefaultResponsesForMasterInquiryReplyParsing()
279 {
Rolf Badorekb7f49712019-09-23 14:14:56 +0300280 ON_CALL(masterInquiryReplyMock, getType())
Rolf Badorek8324d022019-09-17 16:47:20 +0300281 .WillByDefault(Return(Reply::Type::ARRAY));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300282 ON_CALL(masterInquiryReplyMock, getArray())
Rolf Badorek8324d022019-09-17 16:47:20 +0300283 .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 }
Rolf Badorekb7f49712019-09-23 14:14:56 +0300293
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 }
Rolf Badorek8324d022019-09-17 16:47:20 +0300355 };
356
357 class AsyncSentinelDatabaseDiscoveryTest: public AsyncSentinelDatabaseDiscoveryBaseTest
358 {
359 public:
360 AsyncSentinelDatabaseDiscoveryTest()
361 {
Rolf Badorekb7f49712019-09-23 14:14:56 +0300362 expectDispatchersCreated();
Rolf Badorek8324d022019-09-17 16:47:20 +0300363 asyncSentinelDatabaseDiscovery.reset(
364 new AsyncSentinelDatabaseDiscovery(
365 engineMock,
366 logger,
Rolf Badorek2dcf9402019-10-01 18:33:58 +0300367 HostAndPort(someHost, somePort),
368 "mymaster",
Rolf Badorek8324d022019-09-17 16:47:20 +0300369 std::bind(&AsyncSentinelDatabaseDiscoveryBaseTest::asyncCommandDispatcherCreator,
Rolf Badorekb7f49712019-09-23 14:14:56 +0300370 this),
Rolf Badorek8324d022019-09-17 16:47:20 +0300371 contentsBuilderMock));
372 }
Rolf Badorekb7f49712019-09-23 14:14:56 +0300373
374 ~AsyncSentinelDatabaseDiscoveryTest()
375 {
376 EXPECT_CALL(*subscriberMock, disableCommandCallbacks())
377 .Times(1);
378 EXPECT_CALL(*dispatcherMock, disableCommandCallbacks())
379 .Times(1);
380 }
381 };
382
383 class AsyncSentinelDatabaseDiscoveryInListeningModeTest: public AsyncSentinelDatabaseDiscoveryTest
384 {
385 public:
386 AsyncSentinelDatabaseDiscoveryInListeningModeTest()
387 {
388 InSequence dummy;
389 setStateChangedCbExpectsBeforeMasterInquiry();
390 dispatcherConnectAck();
391 expectMasterIquiryReply();
392 expectStateChangedCb(someHost, somePort);
393 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
394 }
Rolf Badorek8324d022019-09-17 16:47:20 +0300395 };
396
397 using AsyncSentinelDatabaseDiscoveryDeathTest = AsyncSentinelDatabaseDiscoveryTest;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300398
399 using AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest = AsyncSentinelDatabaseDiscoveryInListeningModeTest;
Rolf Badorek8324d022019-09-17 16:47:20 +0300400}
401
402TEST_F(AsyncSentinelDatabaseDiscoveryBaseTest, IsNotCopyable)
403{
404 InSequence dummy;
405 EXPECT_FALSE(std::is_copy_constructible<AsyncSentinelDatabaseDiscovery>::value);
406 EXPECT_FALSE(std::is_copy_assignable<AsyncSentinelDatabaseDiscovery>::value);
407}
408
409TEST_F(AsyncSentinelDatabaseDiscoveryBaseTest, ImplementsAsyncDatabaseDiscovery)
410{
411 InSequence dummy;
412 EXPECT_TRUE((std::is_base_of<AsyncDatabaseDiscovery, AsyncSentinelDatabaseDiscovery>::value));
413}
414
Rolf Badorekb7f49712019-09-23 14:14:56 +0300415TEST_F(AsyncSentinelDatabaseDiscoveryTest, SettingChangedCallbackTriggersSentinelNotificationsSubscriptionAndMasterInquiry)
Rolf Badorek8324d022019-09-17 16:47:20 +0300416{
417 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300418 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300419 dispatcherConnectAck();
420 expectMasterIquiryReply();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300421 expectStateChangedCb(someHost, somePort);
422 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300423}
424
Rolf Badorekb7f49712019-09-23 14:14:56 +0300425TEST_F(AsyncSentinelDatabaseDiscoveryTest, MasterInquiryErrorTriggersRetry)
Rolf Badorek8324d022019-09-17 16:47:20 +0300426{
427 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300428 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300429 dispatcherConnectAck();
430 expectMasterInquiryRetryTimer();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300431 savedDispatcherCommandCb(getWellKnownErrorCode(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300432 expectMasterInquiry();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300433 savedMasterInquiryRetryTimerCallback();
Rolf Badorek8324d022019-09-17 16:47:20 +0300434 expectMasterIquiryReply();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300435 expectStateChangedCb(someHost, somePort);
436 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300437}
438
439TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidReplyType)
440{
441 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300442 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300443 dispatcherConnectAck();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300444 ON_CALL(masterInquiryReplyMock, getType())
Rolf Badorek8324d022019-09-17 16:47:20 +0300445 .WillByDefault(Return(Reply::Type::NIL));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300446 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300447}
448
449TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidHostElementType)
450{
451 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300452 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300453 dispatcherConnectAck();
454 setDefaultResponsesForMasterInquiryReplyParsing();
455 ON_CALL(*masterInquiryReplyHost, getType())
456 .WillByDefault(Return(Reply::Type::NIL));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300457 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300458}
459
460TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidPortElementType)
461{
462 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300463 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300464 dispatcherConnectAck();
465 setDefaultResponsesForMasterInquiryReplyParsing();
466 ON_CALL(*masterInquiryReplyPort, getType())
467 .WillByDefault(Return(Reply::Type::NIL));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300468 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300469}
470
471TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_PortCantBeCastedToInt)
472{
473 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300474 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300475 dispatcherConnectAck();
476 setDefaultResponsesForMasterInquiryReplyParsing();
477 std::string invalidPort("invalidPort");
478 Reply::DataItem invalidPortDataItem({invalidPort,ReplyStringLength(invalidPort.length())});
479 ON_CALL(*masterInquiryReplyPort, getString())
480 .WillByDefault(Return(&invalidPortDataItem));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300481 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300482}
483
484TEST_F(AsyncSentinelDatabaseDiscoveryTest, CallbackIsNotCalledAfterCleared)
485{
486 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300487 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300488 dispatcherConnectAck();
489 expectMasterInquiryRetryTimer();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300490 savedDispatcherCommandCb(getWellKnownErrorCode(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300491 expectMasterInquiry();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300492 savedMasterInquiryRetryTimerCallback();
Rolf Badorek8324d022019-09-17 16:47:20 +0300493 expectMasterIquiryReply();
494 asyncSentinelDatabaseDiscovery->clearStateChangedCb();
495 EXPECT_CALL(*this, stateChangedCb(_))
496 .Times(0);
Rolf Badorekb7f49712019-09-23 14:14:56 +0300497 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
498}
499
500TEST_F(AsyncSentinelDatabaseDiscoveryTest, ChangeNotificationFromSentinel)
501{
502 InSequence dummy;
503 setStateChangedCbExpectsBeforeMasterInquiry();
504 dispatcherConnectAck();
505 expectMasterIquiryReply();
506 expectStateChangedCb(someHost, somePort);
507 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
508 expectNotificationReply();
509 expectStateChangedCb(someOtherHost, someOtherPort);
510 savedSubscriberCommandCb(std::error_code(), notificationReplyMock);
511}
512
513TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeTest, SubscribeCommandErrorTriggersRetry)
514{
515 InSequence dummy;
516 expectSubscribeRetryTimer();
517 savedSubscriberCommandCb(getWellKnownErrorCode(), subscribeReplyMock);
518 expectSubscribeNotifications();
519 savedSubscribeRetryTimerCallback();
520}
521
522TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidReplyType)
523{
524 InSequence dummy;
525 ON_CALL(notificationReplyMock, getType())
526 .WillByDefault(Return(Reply::Type::NIL));
527 EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*SUBSCRIBE command reply parsing error");
528}
529
530TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidKindElementType)
531{
532 InSequence dummy;
533 setDefaultResponsesForNotificationReplyParsing();
534 ON_CALL(*notificationReplyArrayElement0, getType())
535 .WillByDefault(Return(Reply::Type::NIL));
536 EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*SUBSCRIBE command reply parsing error");
537}
538
539TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidKind)
540{
541 InSequence dummy;
542 setDefaultResponsesForNotificationReplyParsing();
543 std::string invalidKind("invalidKind");
544 Reply::DataItem invalidKindDataItem({invalidKind,ReplyStringLength(invalidKind.length())});
545 ON_CALL(*notificationReplyArrayElement0, getString())
546 .WillByDefault(Return(&invalidKindDataItem));
547 EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*SUBSCRIBE command reply parsing error");
548}
549
550TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidMessageElementType)
551{
552 InSequence dummy;
553 setDefaultResponsesForNotificationReplyParsing();
554 ON_CALL(*notificationReplyArrayElement2, getType())
555 .WillByDefault(Return(Reply::Type::NIL));
556 EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*SUBSCRIBE command reply parsing error");
557}
558
559TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidMessageStructure)
560{
561 InSequence dummy;
562 setDefaultResponsesForNotificationReplyParsing();
563 std::string invalidMessage("mymaster oldHost 1234 5678");
564 auto invalidMessageDataItem(Reply::DataItem({invalidMessage, ReplyStringLength(invalidMessage.length())}));
565 ON_CALL(*notificationReplyArrayElement2, getString())
566 .WillByDefault(Return(&invalidMessageDataItem));
567 EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*Notification message parsing error");
568}
569
570TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest, SubscribeReplyParsingErrorAborts_InvalidPort)
571{
572 InSequence dummy;
573 setDefaultResponsesForNotificationReplyParsing();
574 std::string invalidMessage("mymaster oldHost 1234 newHost invalidPort");
575 auto invalidMessageDataItem(Reply::DataItem({invalidMessage, ReplyStringLength(invalidMessage.length())}));
576 ON_CALL(*notificationReplyArrayElement2, getString())
577 .WillByDefault(Return(&invalidMessageDataItem));
578 EXPECT_EXIT(savedSubscriberCommandCb(std::error_code(), notificationReplyMock), KilledBySignal(SIGABRT), ".*Notification message parsing error");
579}
580
581TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeTest, SubscriberDisconnectCallbackTriggersSubscriptionRenewal)
582{
583 InSequence dummy;
584 expectSubscriberWaitConnectedAsync();
585 subscriberDisconnectCb();
586 expectSubscribeNotifications();
587 subscriberConnectAck();
588 expectSubscribeReply();
589 expectDispatcherWaitConnectedAsync();
590 savedSubscriberCommandCb(std::error_code(), subscribeReplyMock);
591 expectMasterInquiry();
592 dispatcherConnectAck();
593 expectMasterIquiryReply();
594 expectStateChangedCb(someHost, somePort);
595 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300596}