Add Sentinel configuration reading
[ric-plt/sdl.git] / tst / syncstorageimpl_test.cpp
1 /*
2    Copyright (c) 2018-2019 Nokia.
3
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7
8        http://www.apache.org/licenses/LICENSE-2.0
9
10    Unless required by applicable law or agreed to in writing, software
11    distributed under the License is distributed on an "AS IS" BASIS,
12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    See the License for the specific language governing permissions and
14    limitations under the License.
15 */
16
17 #include <gtest/gtest.h>
18 #include "private/error.hpp"
19 #include "private/redis/asyncredisstorage.hpp"
20 #include "private/syncstorageimpl.hpp"
21 #include "private/tst/asyncstoragemock.hpp"
22 #include "private/tst/systemmock.hpp"
23 #include <sdl/backenderror.hpp>
24 #include <sdl/invalidnamespace.hpp>
25 #include <sdl/notconnected.hpp>
26 #include <sdl/operationinterrupted.hpp>
27 #include <sdl/rejectedbybackend.hpp>
28
29 using namespace shareddatalayer;
30 using namespace shareddatalayer::redis;
31 using namespace shareddatalayer::tst;
32 using namespace testing;
33
34 namespace
35 {
36     class SyncStorageImplTest: public testing::Test
37     {
38     public:
39         std::unique_ptr<SyncStorageImpl> syncStorage;
40         /* AsyncStorageMock ownership will be passed to implementation. To be able to do verification
41          * with the mock object also here after its ownership is passed we take raw pointer to
42          * AsyncStorageMock before passing it to implementation. Works fine, as implementation will
43          * not release injected mock object before test case execution finishes
44          */
45         std::unique_ptr<StrictMock<AsyncStorageMock>> asyncStorageMockPassedToImplementation;
46         StrictMock<AsyncStorageMock>* asyncStorageMockRawPtr;
47         StrictMock<SystemMock> systemMock;
48         AsyncStorage::ModifyAck savedModifyAck;
49         AsyncStorage::ModifyIfAck savedModifyIfAck;
50         AsyncStorage::GetAck savedGetAck;
51         AsyncStorage::FindKeysAck savedFindKeysAck;
52         AsyncStorage::ReadyAck savedReadyAck;
53         int pFd;
54         SyncStorage::DataMap dataMap;
55         SyncStorage::Keys keys;
56         const SyncStorage::Namespace ns;
57         SyncStorageImplTest():
58             asyncStorageMockPassedToImplementation(new StrictMock<AsyncStorageMock>()),
59             asyncStorageMockRawPtr(asyncStorageMockPassedToImplementation.get()),
60             pFd(10),
61             dataMap({{ "key1", { 0x0a, 0x0b, 0x0c } }, { "key2", { 0x0d, 0x0e, 0x0f, 0xff } }}),
62             keys({ "key1", "key2" }),
63             ns("someKnownNamespace")
64         {
65             expectConstructorCalls();
66             syncStorage.reset(new SyncStorageImpl(std::move(asyncStorageMockPassedToImplementation), systemMock));
67         }
68
69         void expectConstructorCalls()
70         {
71             InSequence dummy;
72             EXPECT_CALL(*asyncStorageMockRawPtr, fd())
73                 .Times(1)
74                 .WillOnce(Return(pFd));
75         }
76
77         void expectSdlReadinessCheck()
78         {
79             InSequence dummy;
80             expectWaitReadyAsync();
81             expectPollWait();
82             expectHandleEvents();
83         }
84
85         void expectPollWait()
86         {
87             EXPECT_CALL(systemMock, poll( _, 1, -1))
88                 .Times(1)
89                 .WillOnce(Invoke([](struct pollfd *fds, nfds_t, int)
90                                  {
91                                      fds->revents = POLLIN;
92                                      return 1;
93                                  }));
94         }
95
96         void expectPollError()
97         {
98             EXPECT_CALL(systemMock, poll( _, 1, -1))
99                 .Times(1)
100                 .WillOnce(Invoke([](struct pollfd *fds, nfds_t, int)
101                                  {
102                                      fds->revents = POLLIN;
103                                      return -1;
104                                  }));
105         }
106
107         void expectPollExceptionalCondition()
108         {
109             EXPECT_CALL(systemMock, poll( _, 1, -1))
110                 .Times(1)
111                 .WillOnce(Invoke([](struct pollfd *fds, nfds_t, int)
112                                  {
113                                      fds->revents = POLLPRI;
114                                      return 1;
115                                  }));
116         }
117
118         void expectHandleEvents()
119         {
120             EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
121                 .Times(1)
122                 .WillOnce(Invoke([this]()
123                                  {
124                                     savedReadyAck(std::error_code());
125                                  }));
126         }
127
128         void expectWaitReadyAsync()
129         {
130             EXPECT_CALL(*asyncStorageMockRawPtr, waitReadyAsync(ns,_))
131                 .Times(1)
132                 .WillOnce(SaveArg<1>(&savedReadyAck));
133         }
134
135
136         void expectModifyAckWithError()
137         {
138             EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
139                 .Times(1)
140                 .WillOnce(Invoke([this]()
141                                  {
142                                     savedModifyAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY);
143                                  }));
144         }
145
146         void expectModifyIfAck(const std::error_code& error, bool status)
147         {
148             EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
149                 .Times(1)
150                 .WillOnce(Invoke([this, error, status]()
151                                  {
152                                     savedModifyIfAck(error, status);
153                                  }));
154         }
155
156         void expectGetAckWithError()
157         {
158             EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
159                 .Times(1)
160                 .WillOnce(Invoke([this]()
161                                  {
162                                     savedGetAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, dataMap);
163                                  }));
164         }
165
166         void expectGetAck()
167         {
168             EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
169                 .Times(1)
170                 .WillOnce(Invoke([this]()
171                                  {
172                                     savedGetAck(std::error_code(), dataMap);
173                                  }));
174         }
175
176         void expectFindKeysAck()
177         {
178             EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
179                 .Times(1)
180                 .WillOnce(Invoke([this]()
181                                  {
182                                     savedFindKeysAck(std::error_code(), keys);
183                                  }));
184         }
185
186         void expectFindKeysAckWithError()
187         {
188             EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
189                 .Times(1)
190                 .WillOnce(Invoke([this]()
191                                  {
192                                     savedFindKeysAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, keys);
193                                  }));
194         }
195
196         void expectSetAsync(const SyncStorage::DataMap& dataMap)
197         {
198             EXPECT_CALL(*asyncStorageMockRawPtr, setAsync(ns, dataMap, _))
199                 .Times(1)
200                 .WillOnce(SaveArg<2>(&savedModifyAck));
201         }
202
203         void expectSetIfAsync(const SyncStorage::Key& key, const SyncStorage::Data& oldData, const SyncStorage::Data& newData)
204         {
205             EXPECT_CALL(*asyncStorageMockRawPtr, setIfAsync(ns, key, oldData, newData, _))
206                 .Times(1)
207                 .WillOnce(SaveArg<4>(&savedModifyIfAck));
208         }
209
210         void expectGetAsync(const SyncStorage::Keys& keys)
211         {
212             EXPECT_CALL(*asyncStorageMockRawPtr, getAsync(ns, keys, _))
213                 .Times(1)
214                 .WillOnce(SaveArg<2>(&savedGetAck));
215         }
216
217         void expectFindKeysAsync()
218         {
219             EXPECT_CALL(*asyncStorageMockRawPtr, findKeysAsync(ns, _, _))
220                 .Times(1)
221                 .WillOnce(SaveArg<2>(&savedFindKeysAck));
222         }
223
224         void expectRemoveAsync(const SyncStorage::Keys& keys)
225         {
226             EXPECT_CALL(*asyncStorageMockRawPtr, removeAsync(ns, keys, _))
227                 .Times(1)
228                 .WillOnce(SaveArg<2>(&savedModifyAck));
229         }
230
231         void expectRemoveIfAsync(const SyncStorage::Key& key, const SyncStorage::Data& data)
232         {
233             EXPECT_CALL(*asyncStorageMockRawPtr, removeIfAsync(ns, key, data, _))
234                 .Times(1)
235                 .WillOnce(SaveArg<3>(&savedModifyIfAck));
236         }
237
238         void expectRemoveAllAsync()
239         {
240             EXPECT_CALL(*asyncStorageMockRawPtr, removeAllAsync(ns, _))
241                 .Times(1)
242                 .WillOnce(SaveArg<1>(&savedModifyAck));
243         }
244
245         void expectSetIfNotExistsAsync(const SyncStorage::Key& key, const SyncStorage::Data& data)
246         {
247             EXPECT_CALL(*asyncStorageMockRawPtr, setIfNotExistsAsync(ns, key, data, _))
248                 .Times(1)
249                 .WillOnce(SaveArg<3>(&savedModifyIfAck));
250         }
251     };
252 }
253
254 TEST_F(SyncStorageImplTest, IsNotCopyable)
255 {
256     InSequence dummy;
257     EXPECT_FALSE(std::is_copy_constructible<SyncStorageImpl>::value);
258     EXPECT_FALSE(std::is_copy_assignable<SyncStorageImpl>::value);
259 }
260
261 TEST_F(SyncStorageImplTest, ImplementssyncStorage)
262 {
263     InSequence dummy;
264     EXPECT_TRUE((std::is_base_of<SyncStorage, SyncStorageImpl>::value));
265 }
266
267 TEST_F(SyncStorageImplTest, EventsAreNotHandledWhenPollReturnsError)
268 {
269     InSequence dummy;
270     expectSdlReadinessCheck();
271     expectSetAsync(dataMap);
272     expectPollError();
273     expectPollWait();
274     expectHandleEvents();
275     syncStorage->set(ns, dataMap);
276 }
277
278 TEST_F(SyncStorageImplTest, EventsAreNotHandledWhenThereIsAnExceptionalConditionOnTheFd)
279 {
280     InSequence dummy;
281     expectSdlReadinessCheck();
282     expectSetAsync(dataMap);
283     expectPollExceptionalCondition();
284     expectPollWait();
285     expectHandleEvents();
286     syncStorage->set(ns, dataMap);
287 }
288
289 TEST_F(SyncStorageImplTest, SetSuccessfully)
290 {
291     InSequence dummy;
292     expectSdlReadinessCheck();
293     expectSetAsync(dataMap);
294     expectPollWait();
295     expectHandleEvents();
296     syncStorage->set(ns, dataMap);
297 }
298
299 TEST_F(SyncStorageImplTest, SetCanThrowBackendError)
300 {
301     InSequence dummy;
302     expectSdlReadinessCheck();
303     expectSetAsync(dataMap);
304     expectPollWait();
305     expectModifyAckWithError();
306     EXPECT_THROW(syncStorage->set(ns, dataMap), BackendError);
307 }
308
309 TEST_F(SyncStorageImplTest, SetIfSuccessfully)
310 {
311     InSequence dummy;
312     expectSdlReadinessCheck();
313     expectSetAsync(dataMap);
314     expectPollWait();
315     expectHandleEvents();
316     syncStorage->set(ns, dataMap);
317     expectSdlReadinessCheck();
318     expectSetIfAsync("key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f });
319     expectPollWait();
320     expectHandleEvents();
321     syncStorage->setIf(ns, "key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f });
322 }
323
324 TEST_F(SyncStorageImplTest, SetIfCanThrowBackendError)
325 {
326     InSequence dummy;
327     expectSdlReadinessCheck();
328     expectSetAsync(dataMap);
329     expectPollWait();
330     expectHandleEvents();
331     syncStorage->set(ns, dataMap);
332     expectSdlReadinessCheck();
333     expectSetIfAsync("key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f });
334     expectPollWait();
335     expectModifyIfAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, false);
336     EXPECT_THROW(syncStorage->setIf(ns, "key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f }), BackendError);
337 }
338
339 TEST_F(SyncStorageImplTest, SetIfNotExistsSuccessfully)
340 {
341     InSequence dummy;
342     expectSdlReadinessCheck();
343     expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
344     expectPollWait();
345     expectModifyIfAck(std::error_code(), true);
346     EXPECT_TRUE(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }));
347 }
348
349 TEST_F(SyncStorageImplTest, SetIfNotExistsReturnsFalseIfKeyAlreadyExists)
350 {
351     InSequence dummy;
352     expectSdlReadinessCheck();
353     expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
354     expectPollWait();
355     expectModifyIfAck(std::error_code(), false);
356     EXPECT_FALSE(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }));
357 }
358
359 TEST_F(SyncStorageImplTest, SetIfNotExistsCanThrowBackendError)
360 {
361     InSequence dummy;
362     expectSdlReadinessCheck();
363     expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
364     expectPollWait();
365     expectModifyIfAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, false);
366     EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
367 }
368
369 TEST_F(SyncStorageImplTest, GetSuccessfully)
370 {
371     InSequence dummy;
372     expectSdlReadinessCheck();
373     expectGetAsync(keys);
374     expectPollWait();
375     expectGetAck();
376     auto map(syncStorage->get(ns, keys));
377     EXPECT_EQ(map, dataMap);
378 }
379
380 TEST_F(SyncStorageImplTest, GetCanThrowBackendError)
381 {
382     InSequence dummy;
383     expectSdlReadinessCheck();
384     expectGetAsync(keys);
385     expectPollWait();
386     expectGetAckWithError();
387     EXPECT_THROW(syncStorage->get(ns, keys), BackendError);
388 }
389
390 TEST_F(SyncStorageImplTest, RemoveSuccessfully)
391 {
392     InSequence dummy;
393     expectSdlReadinessCheck();
394     expectRemoveAsync(keys);
395     expectPollWait();
396     expectHandleEvents();
397     syncStorage->remove(ns, keys);
398 }
399
400 TEST_F(SyncStorageImplTest, RemoveCanThrowBackendError)
401 {
402     InSequence dummy;
403     expectSdlReadinessCheck();
404     expectRemoveAsync(keys);
405     expectPollWait();
406     expectModifyAckWithError();
407     EXPECT_THROW(syncStorage->remove(ns, keys), BackendError);
408 }
409
410 TEST_F(SyncStorageImplTest, RemoveIfSuccessfully)
411 {
412     InSequence dummy;
413     expectSdlReadinessCheck();
414     expectRemoveIfAsync("key1", { 0x0a, 0x0b, 0x0c });
415     expectPollWait();
416     expectModifyIfAck(std::error_code(), true);
417     EXPECT_TRUE(syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }));
418 }
419
420 TEST_F(SyncStorageImplTest, RemoveIfReturnsFalseIfKeyDoesnotMatch)
421 {
422     InSequence dummy;
423     expectSdlReadinessCheck();
424     expectRemoveIfAsync("key1", { 0x0a, 0x0b, 0x0c });
425     expectPollWait();
426     expectModifyIfAck(std::error_code(), false);
427     EXPECT_FALSE(syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }));
428 }
429
430 TEST_F(SyncStorageImplTest, RemoveIfCanThrowBackendError)
431 {
432     InSequence dummy;
433     expectSdlReadinessCheck();
434     expectRemoveIfAsync("key1", { 0x0a, 0x0b, 0x0c });
435     expectPollWait();
436     expectModifyIfAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, false);
437     EXPECT_THROW(syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
438 }
439
440 TEST_F(SyncStorageImplTest, FindKeysSuccessfully)
441 {
442     InSequence dummy;
443     expectSdlReadinessCheck();
444     expectFindKeysAsync();
445     expectPollWait();
446     expectFindKeysAck();
447     auto ids(syncStorage->findKeys(ns, "*"));
448     EXPECT_EQ(ids, keys);
449 }
450
451 TEST_F(SyncStorageImplTest, FindKeysAckCanThrowBackendError)
452 {
453     InSequence dummy;
454     expectSdlReadinessCheck();
455     expectFindKeysAsync();
456     expectPollWait();
457     expectFindKeysAckWithError();
458     EXPECT_THROW(syncStorage->findKeys(ns, "*"), BackendError);
459 }
460
461 TEST_F(SyncStorageImplTest, RemoveAllSuccessfully)
462 {
463     InSequence dummy;
464     expectSdlReadinessCheck();
465     expectRemoveAllAsync();
466     expectPollWait();
467     expectHandleEvents();
468     syncStorage->removeAll(ns);
469 }
470
471 TEST_F(SyncStorageImplTest, RemoveAllCanThrowBackendError)
472 {
473     InSequence dummy;
474     expectSdlReadinessCheck();
475     expectRemoveAllAsync();
476     expectPollWait();
477     expectModifyAckWithError();
478     EXPECT_THROW(syncStorage->removeAll(ns), BackendError);
479 }
480
481 TEST_F(SyncStorageImplTest, AllAsyncRedisStorageErrorCodesThrowCorrectException)
482 {
483     InSequence dummy;
484     std::error_code ec;
485
486     for (AsyncRedisStorage::ErrorCode arsec = AsyncRedisStorage::ErrorCode::SUCCESS; arsec < AsyncRedisStorage::ErrorCode::END_MARKER; ++arsec)
487     {
488         if (arsec != AsyncRedisStorage::ErrorCode::SUCCESS)
489         {
490             expectSdlReadinessCheck();
491             expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
492             expectPollWait();
493         }
494
495         switch (arsec)
496         {
497             case AsyncRedisStorage::ErrorCode::SUCCESS:
498                 break;
499             case AsyncRedisStorage::ErrorCode::INVALID_NAMESPACE:
500                 expectModifyIfAck(arsec, false);
501                 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), InvalidNamespace);
502                 break;
503             case AsyncRedisStorage::ErrorCode::REDIS_NOT_YET_DISCOVERED:
504                 expectModifyIfAck(arsec, false);
505                 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), NotConnected);
506                 break;
507             default:
508                 FAIL() << "No mapping for AsyncRedisStorage::ErrorCode value: " << arsec;
509                 break;
510         }
511     }
512 }
513
514 TEST_F(SyncStorageImplTest, AllDispatcherErrorCodesThrowCorrectException)
515 {
516     InSequence dummy;
517     std::error_code ec;
518
519     for (AsyncRedisCommandDispatcherErrorCode aec = AsyncRedisCommandDispatcherErrorCode::SUCCESS; aec < AsyncRedisCommandDispatcherErrorCode::END_MARKER; ++aec)
520     {
521         if (aec != AsyncRedisCommandDispatcherErrorCode::SUCCESS)
522         {
523             expectSdlReadinessCheck();
524             expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
525             expectPollWait();
526         }
527
528         switch (aec)
529         {
530             case AsyncRedisCommandDispatcherErrorCode::SUCCESS:
531                 break;
532             case AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR:
533                 expectModifyIfAck(aec, false);
534                 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
535                 break;
536             case AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST:
537                 expectModifyIfAck(aec, false);
538                 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), OperationInterrupted);
539                 break;
540             case AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR:
541                 expectModifyIfAck(aec, false);
542                 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), RejectedByBackend);
543                 break;
544             case AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY:
545                 expectModifyIfAck(aec, false);
546                 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
547                 break;
548             case AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING:
549                 expectModifyIfAck(aec, false);
550                 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), NotConnected);
551                 break;
552             case AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED:
553                 expectModifyIfAck(aec, false);
554                 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), NotConnected);
555                 break;
556             case AsyncRedisCommandDispatcherErrorCode::IO_ERROR:
557                 expectModifyIfAck(aec, false);
558                 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
559                 break;
560             case AsyncRedisCommandDispatcherErrorCode::WRITING_TO_SLAVE:
561                 expectModifyIfAck(aec, false);
562                 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
563                 break;
564             default:
565                 FAIL() << "No mapping for AsyncRedisCommandDispatcherErrorCode value: " << aec;
566                 break;
567         }
568     }
569 }
570
571 TEST_F(SyncStorageImplTest, CanThrowStdExceptionIfDispatcherErrorCodeCannotBeMappedToSdlException)
572 {
573     InSequence dummy;
574     expectSdlReadinessCheck();
575     expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
576     expectPollWait();
577     expectModifyIfAck(std::error_code(1, std::system_category()), false);
578     EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), std::range_error);
579 }