blob: a59756d99cfeaafb2a87b04368c9b0c0fb1fe560 [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
Timo Tietavainena0745d22019-11-28 09:55:22 +020017/*
18 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 * platform project (RICP).
20*/
21
Rolf Badorek8324d022019-09-17 16:47:20 +030022#include <gtest/gtest.h>
23#include <arpa/inet.h>
Rolf Badorekb7f49712019-09-23 14:14:56 +030024#include <string>
Rolf Badorek8324d022019-09-17 16:47:20 +030025#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
36using namespace shareddatalayer;
37using namespace shareddatalayer::redis;
38using namespace shareddatalayer::tst;
39using namespace testing;
40
41namespace
42{
43 class AsyncSentinelDatabaseDiscoveryBaseTest: public testing::Test
44 {
45 public:
46 std::unique_ptr<AsyncSentinelDatabaseDiscovery> asyncSentinelDatabaseDiscovery;
47 std::shared_ptr<StrictMock<EngineMock>> engineMock;
Rolf Badorekb7f49712019-09-23 14:14:56 +030048 std::shared_ptr<StrictMock<AsyncCommandDispatcherMock>> subscriberMock;
Rolf Badorek8324d022019-09-17 16:47:20 +030049 std::shared_ptr<StrictMock<AsyncCommandDispatcherMock>> dispatcherMock;
50 std::shared_ptr<StrictMock<ContentsBuilderMock>> contentsBuilderMock;
51 std::shared_ptr<Logger> logger;
52 Contents contents;
Rolf Badorekb7f49712019-09-23 14:14:56 +030053 AsyncCommandDispatcher::ConnectAck subscriberConnectAck;
54 AsyncCommandDispatcher::DisconnectCb subscriberDisconnectCb;
Rolf Badorek8324d022019-09-17 16:47:20 +030055 AsyncCommandDispatcher::ConnectAck dispatcherConnectAck;
Rolf Badorekb7f49712019-09-23 14:14:56 +030056 AsyncCommandDispatcher::CommandCb savedSubscriberCommandCb;
57 AsyncCommandDispatcher::CommandCb savedDispatcherCommandCb;
58 ReplyMock masterInquiryReplyMock;
Rolf Badorek8324d022019-09-17 16:47:20 +030059 std::string someHost;
60 uint16_t somePort;
Rolf Badorekb7f49712019-09-23 14:14:56 +030061 std::string someOtherHost;
62 uint16_t someOtherPort;
Rolf Badorek8324d022019-09-17 16:47:20 +030063 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;
Rolf Badorekb7f49712019-09-23 14:14:56 +030069 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;
Rolf Badorek8324d022019-09-17 16:47:20 +030088
89 AsyncSentinelDatabaseDiscoveryBaseTest():
90 engineMock(std::make_shared<StrictMock<EngineMock>>()),
Rolf Badorek8324d022019-09-17 16:47:20 +030091 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),
Rolf Badorekb7f49712019-09-23 14:14:56 +030096 someOtherHost("someotherhost"),
97 someOtherPort(5678),
Rolf Badorek8324d022019-09-17 16:47:20 +030098 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>()),
Rolf Badorekb7f49712019-09-23 14:14:56 +0300102 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))
Rolf Badorek8324d022019-09-17 16:47:20 +0300114 {
115 masterInquiryReply.push_back(masterInquiryReplyHost);
116 masterInquiryReply.push_back(masterInquiryReplyPort);
Rolf Badorekb7f49712019-09-23 14:14:56 +0300117 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);
Rolf Badorek8324d022019-09-17 16:47:20 +0300123 }
124
125 virtual ~AsyncSentinelDatabaseDiscoveryBaseTest()
126 {
127 }
128
Rolf Badorekb7f49712019-09-23 14:14:56 +0300129 std::shared_ptr<AsyncCommandDispatcher> asyncCommandDispatcherCreator()
Rolf Badorek8324d022019-09-17 16:47:20 +0300130 {
131 // @TODO Add database info checking when configuration support for sentinel is added.
Rolf Badorekb7f49712019-09-23 14:14:56 +0300132 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;
Rolf Badorek8324d022019-09-17 16:47:20 +0300145 }
146
147 MOCK_METHOD0(newDispatcherCreated, void());
148
Rolf Badorekb7f49712019-09-23 14:14:56 +0300149 void expectDispatchersCreated()
Rolf Badorek8324d022019-09-17 16:47:20 +0300150 {
151 EXPECT_CALL(*this, newDispatcherCreated())
Rolf Badorekb7f49712019-09-23 14:14:56 +0300152 .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 }));
Rolf Badorek8324d022019-09-17 16:47:20 +0300173 }
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,
Rolf Badorekb7f49712019-09-23 14:14:56 +0300186 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,
Rolf Badorek8324d022019-09-17 16:47:20 +0300194 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
Rolf Badorekb7f49712019-09-23 14:14:56 +0300202 void expectSubscriberDispatchAsync()
203 {
204 EXPECT_CALL(*subscriberMock, dispatchAsync(_, _, contents))
205 .Times(1)
206 .WillOnce(SaveArg<0>(&savedSubscriberCommandCb));
207 }
208
209 void expectDispatcherDispatchAsync()
Rolf Badorek8324d022019-09-17 16:47:20 +0300210 {
211 EXPECT_CALL(*dispatcherMock, dispatchAsync(_, _, contents))
212 .Times(1)
Rolf Badorekb7f49712019-09-23 14:14:56 +0300213 .WillOnce(SaveArg<0>(&savedDispatcherCommandCb));
214 }
215
216 void expectSubscribeNotifications()
217 {
218 expectContentsBuild("SUBSCRIBE", "+switch-master");
219 expectSubscriberDispatchAsync();
Rolf Badorek8324d022019-09-17 16:47:20 +0300220 }
221
222 void expectMasterInquiry()
223 {
224 expectContentsBuild("SENTINEL", "get-master-addr-by-name", "mymaster");
Rolf Badorekb7f49712019-09-23 14:14:56 +0300225 expectDispatcherDispatchAsync();
Rolf Badorek8324d022019-09-17 16:47:20 +0300226 }
227
228 MOCK_METHOD1(stateChangedCb, void(const DatabaseInfo&));
229
Rolf Badorekb7f49712019-09-23 14:14:56 +0300230 void expectStateChangedCb(const std::string& host, uint16_t port)
Rolf Badorek8324d022019-09-17 16:47:20 +0300231 {
232 EXPECT_CALL(*this, stateChangedCb(_))
233 .Times(1)
Rolf Badorekb7f49712019-09-23 14:14:56 +0300234 .WillOnce(Invoke([this, host, port](const DatabaseInfo& databaseInfo)
Rolf Badorek8324d022019-09-17 16:47:20 +0300235 {
Rolf Badorekb7f49712019-09-23 14:14:56 +0300236 EXPECT_THAT(DatabaseConfiguration::Addresses({ HostAndPort(host, htons(port)) }),
Rolf Badorek8324d022019-09-17 16:47:20 +0300237 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
Rolf Badorek8324d022019-09-17 16:47:20 +0300244 void expectMasterIquiryReply()
245 {
Rolf Badorekb7f49712019-09-23 14:14:56 +0300246 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);
Rolf Badorek8324d022019-09-17 16:47:20 +0300252 }
253
254 void expectMasterInquiryRetryTimer()
255 {
256 EXPECT_CALL(*engineMock, armTimer(_, expectedMasterInquiryRetryTimerDuration, _))
257 .Times(1)
Rolf Badorekb7f49712019-09-23 14:14:56 +0300258 .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();
Rolf Badorek8324d022019-09-17 16:47:20 +0300281 }
282
283 void setDefaultResponsesForMasterInquiryReplyParsing()
284 {
Rolf Badorekb7f49712019-09-23 14:14:56 +0300285 ON_CALL(masterInquiryReplyMock, getType())
Rolf Badorek8324d022019-09-17 16:47:20 +0300286 .WillByDefault(Return(Reply::Type::ARRAY));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300287 ON_CALL(masterInquiryReplyMock, getArray())
Rolf Badorek8324d022019-09-17 16:47:20 +0300288 .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 }
Rolf Badorekb7f49712019-09-23 14:14:56 +0300298
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 }
Rolf Badorek8324d022019-09-17 16:47:20 +0300360 };
361
362 class AsyncSentinelDatabaseDiscoveryTest: public AsyncSentinelDatabaseDiscoveryBaseTest
363 {
364 public:
365 AsyncSentinelDatabaseDiscoveryTest()
366 {
Rolf Badorekb7f49712019-09-23 14:14:56 +0300367 expectDispatchersCreated();
Rolf Badorek8324d022019-09-17 16:47:20 +0300368 asyncSentinelDatabaseDiscovery.reset(
369 new AsyncSentinelDatabaseDiscovery(
370 engineMock,
371 logger,
Rolf Badorek2dcf9402019-10-01 18:33:58 +0300372 HostAndPort(someHost, somePort),
373 "mymaster",
Rolf Badorek8324d022019-09-17 16:47:20 +0300374 std::bind(&AsyncSentinelDatabaseDiscoveryBaseTest::asyncCommandDispatcherCreator,
Rolf Badorekb7f49712019-09-23 14:14:56 +0300375 this),
Rolf Badorek8324d022019-09-17 16:47:20 +0300376 contentsBuilderMock));
377 }
Rolf Badorekb7f49712019-09-23 14:14:56 +0300378
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 }
Rolf Badorek8324d022019-09-17 16:47:20 +0300400 };
401
402 using AsyncSentinelDatabaseDiscoveryDeathTest = AsyncSentinelDatabaseDiscoveryTest;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300403
404 using AsyncSentinelDatabaseDiscoveryInListeningModeDeathTest = AsyncSentinelDatabaseDiscoveryInListeningModeTest;
Rolf Badorek8324d022019-09-17 16:47:20 +0300405}
406
407TEST_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
414TEST_F(AsyncSentinelDatabaseDiscoveryBaseTest, ImplementsAsyncDatabaseDiscovery)
415{
416 InSequence dummy;
417 EXPECT_TRUE((std::is_base_of<AsyncDatabaseDiscovery, AsyncSentinelDatabaseDiscovery>::value));
418}
419
Rolf Badorekb7f49712019-09-23 14:14:56 +0300420TEST_F(AsyncSentinelDatabaseDiscoveryTest, SettingChangedCallbackTriggersSentinelNotificationsSubscriptionAndMasterInquiry)
Rolf Badorek8324d022019-09-17 16:47:20 +0300421{
422 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300423 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300424 dispatcherConnectAck();
425 expectMasterIquiryReply();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300426 expectStateChangedCb(someHost, somePort);
427 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300428}
429
Rolf Badorekb7f49712019-09-23 14:14:56 +0300430TEST_F(AsyncSentinelDatabaseDiscoveryTest, MasterInquiryErrorTriggersRetry)
Rolf Badorek8324d022019-09-17 16:47:20 +0300431{
432 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300433 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300434 dispatcherConnectAck();
435 expectMasterInquiryRetryTimer();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300436 savedDispatcherCommandCb(getWellKnownErrorCode(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300437 expectMasterInquiry();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300438 savedMasterInquiryRetryTimerCallback();
Rolf Badorek8324d022019-09-17 16:47:20 +0300439 expectMasterIquiryReply();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300440 expectStateChangedCb(someHost, somePort);
441 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300442}
443
444TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidReplyType)
445{
446 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300447 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300448 dispatcherConnectAck();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300449 ON_CALL(masterInquiryReplyMock, getType())
Rolf Badorek8324d022019-09-17 16:47:20 +0300450 .WillByDefault(Return(Reply::Type::NIL));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300451 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300452}
453
454TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidHostElementType)
455{
456 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300457 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300458 dispatcherConnectAck();
459 setDefaultResponsesForMasterInquiryReplyParsing();
460 ON_CALL(*masterInquiryReplyHost, getType())
461 .WillByDefault(Return(Reply::Type::NIL));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300462 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300463}
464
465TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_InvalidPortElementType)
466{
467 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300468 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300469 dispatcherConnectAck();
470 setDefaultResponsesForMasterInquiryReplyParsing();
471 ON_CALL(*masterInquiryReplyPort, getType())
472 .WillByDefault(Return(Reply::Type::NIL));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300473 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300474}
475
476TEST_F(AsyncSentinelDatabaseDiscoveryDeathTest, MasterInquiryParsingErrorAborts_PortCantBeCastedToInt)
477{
478 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300479 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300480 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));
Rolf Badorekb7f49712019-09-23 14:14:56 +0300486 EXPECT_EXIT(savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock), KilledBySignal(SIGABRT), ".*Master inquiry reply parsing error");
Rolf Badorek8324d022019-09-17 16:47:20 +0300487}
488
489TEST_F(AsyncSentinelDatabaseDiscoveryTest, CallbackIsNotCalledAfterCleared)
490{
491 InSequence dummy;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300492 setStateChangedCbExpectsBeforeMasterInquiry();
Rolf Badorek8324d022019-09-17 16:47:20 +0300493 dispatcherConnectAck();
494 expectMasterInquiryRetryTimer();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300495 savedDispatcherCommandCb(getWellKnownErrorCode(), masterInquiryReplyMock);
Rolf Badorek8324d022019-09-17 16:47:20 +0300496 expectMasterInquiry();
Rolf Badorekb7f49712019-09-23 14:14:56 +0300497 savedMasterInquiryRetryTimerCallback();
Rolf Badorek8324d022019-09-17 16:47:20 +0300498 expectMasterIquiryReply();
499 asyncSentinelDatabaseDiscovery->clearStateChangedCb();
500 EXPECT_CALL(*this, stateChangedCb(_))
501 .Times(0);
Rolf Badorekb7f49712019-09-23 14:14:56 +0300502 savedDispatcherCommandCb(std::error_code(), masterInquiryReplyMock);
503}
504
505TEST_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
518TEST_F(AsyncSentinelDatabaseDiscoveryInListeningModeTest, SubscribeCommandErrorTriggersRetry)
519{
520 InSequence dummy;
521 expectSubscribeRetryTimer();
522 savedSubscriberCommandCb(getWellKnownErrorCode(), subscribeReplyMock);
523 expectSubscribeNotifications();
524 savedSubscribeRetryTimerCallback();
525}
526
527TEST_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
535TEST_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
544TEST_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
555TEST_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
564TEST_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
575TEST_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
586TEST_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);
Rolf Badorek8324d022019-09-17 16:47:20 +0300601}