blob: ab482846710c781d7a4c93d986d4d66662be8435 [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,
367 std::bind(&AsyncSentinelDatabaseDiscoveryBaseTest::asyncCommandDispatcherCreator,
Rolf Badorekb7f49712019-09-23 14:14:56 +0300368 this),
Rolf Badorek8324d022019-09-17 16:47:20 +0300369 contentsBuilderMock));
370 }
Rolf Badorekb7f49712019-09-23 14:14:56 +0300371
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 }
Rolf Badorek8324d022019-09-17 16:47:20 +0300393 };
394
395 using AsyncSentinelDatabaseDiscoveryDeathTest = AsyncSentinelDatabaseDiscoveryTest;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300396
397 using AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest = AsyncSentinelDatabaseDiscoveryInListeningModeTest;
Rolf Badorek8324d022019-09-17 16:47:20 +0300398}
399
400TEST_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
407TEST_F(AsyncSentinelDatabaseDiscoveryBaseTest, ImplementsAsyncDatabaseDiscovery)
408{
409 InSequence dummy;
410 EXPECT_TRUE((std::is_base_of<AsyncDatabaseDiscovery, AsyncSentinelDatabaseDiscovery>::value));
411}
412
Rolf Badorekb7f49712019-09-23 14:14:56 +0300413TEST_F(AsyncSentinelDatabaseDiscoveryTest, SettingChangedCallbackTriggersSentinelNotificationsSubscriptionAndMasterInquiry)
Rolf Badorek8324d022019-09-17 16:47:20 +0300414{
415 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300416 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300417 dispatcherConnectAck();
418 expectMasterIquiryReply();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300419 expectStateChangedCb(someHost, somePort);
420 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300421}
422
Rolf Badorekb7f49712019-09-23 14:14:56 +0300423TEST_F(AsyncSentinelDatabaseDiscoveryTest, MasterInquiryErrorTriggersRetry)
Rolf Badorek8324d022019-09-17 16:47:20 +0300424{
425 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300426 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300427 dispatcherConnectAck();
428 expectMasterInquiryRetryTimer();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300429 savedDispatcherCommandCb(getWellKnownErrorCode(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300430 expectMasterInquiry();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300431 savedMasterInquiryRetryTimerCallback();
Rolf Badorek8324d022019-09-17 16:47:20 +0300432 expectMasterIquiryReply();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300433 expectStateChangedCb(someHost, somePort);
434 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300435}
436
437TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidReplyType)
438{
439 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300440 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300441 dispatcherConnectAck();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300442 ON_CALL(masterInquiryReplyMock, getType())
Rolf Badorek8324d022019-09-17 16:47:20 +0300443 .WillByDefault(Return(Reply::Type::NIL));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300444 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300445}
446
447TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidHostElementType)
448{
449 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300450 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300451 dispatcherConnectAck();
452 setDefaultResponsesForMasterInquiryReplyParsing();
453 ON_CALL(*masterInquiryReplyHost, getType())
454 .WillByDefault(Return(Reply::Type::NIL));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300455 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300456}
457
458TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidPortElementType)
459{
460 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300461 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300462 dispatcherConnectAck();
463 setDefaultResponsesForMasterInquiryReplyParsing();
464 ON_CALL(*masterInquiryReplyPort, getType())
465 .WillByDefault(Return(Reply::Type::NIL));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300466 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300467}
468
469TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_PortCantBeCastedToInt)
470{
471 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300472 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300473 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));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300479 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300480}
481
482TEST_F(AsyncSentinelDatabaseDiscoveryTest, CallbackIsNotCalledAfterCleared)
483{
484 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300485 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300486 dispatcherConnectAck();
487 expectMasterInquiryRetryTimer();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300488 savedDispatcherCommandCb(getWellKnownErrorCode(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300489 expectMasterInquiry();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300490 savedMasterInquiryRetryTimerCallback();
Rolf Badorek8324d022019-09-17 16:47:20 +0300491 expectMasterIquiryReply();
492 asyncSentinelDatabaseDiscovery->clearStateChangedCb();
493 EXPECT_CALL(*this, stateChangedCb(_))
494 .Times(0);
Rolf Badorekb7f49712019-09-23 14:14:56 +0300495 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
496}
497
498TEST_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
511TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeTest, SubscribeCommandErrorTriggersRetry)
512{
513 InSequence dummy;
514 expectSubscribeRetryTimer();
515 savedSubscriberCommandCb(getWellKnownErrorCode(), subscribeReplyMock);
516 expectSubscribeNotifications();
517 savedSubscribeRetryTimerCallback();
518}
519
520TEST_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
528TEST_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
537TEST_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
548TEST_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
557TEST_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
568TEST_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
579TEST_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);
Rolf Badorek8324d022019-09-17 16:47:20 +0300594}