blob: 4176852d29004b947bfc85f98f09c5826134ac01 [file] [log] [blame]
Rolf Badorekef2bf512019-08-20 11:17:15 +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 "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
29using namespace shareddatalayer;
30using namespace shareddatalayer::redis;
31using namespace shareddatalayer::tst;
32using namespace testing;
33
34namespace
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
254TEST_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
261TEST_F(SyncStorageImplTest, ImplementssyncStorage)
262{
263 InSequence dummy;
264 EXPECT_TRUE((std::is_base_of<SyncStorage, SyncStorageImpl>::value));
265}
266
267TEST_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
278TEST_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
289TEST_F(SyncStorageImplTest, SetSuccessfully)
290{
291 InSequence dummy;
292 expectSdlReadinessCheck();
293 expectSetAsync(dataMap);
294 expectPollWait();
295 expectHandleEvents();
296 syncStorage->set(ns, dataMap);
297}
298
299TEST_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
309TEST_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
324TEST_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
339TEST_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_EQ(true, syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }));
347}
348
349TEST_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_EQ(false, syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }));
357}
358
359TEST_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
369TEST_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
380TEST_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
390TEST_F(SyncStorageImplTest, RemoveSuccessfully)
391{
392 InSequence dummy;
393 expectSdlReadinessCheck();
394 expectRemoveAsync(keys);
395 expectPollWait();
396 expectHandleEvents();
397 syncStorage->remove(ns, keys);
398}
399
400TEST_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
410TEST_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_EQ(true, syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }));
418}
419
420TEST_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_EQ(false, syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }));
428}
429
430TEST_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
440TEST_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
451TEST_F(SyncStorageImplTest, FindKeysAckCanThrowBackendError)
452{
453 InSequence dummy;
454 expectSdlReadinessCheck();
455 expectFindKeysAsync();
456 expectPollWait();
457 expectFindKeysAckWithError();
458 EXPECT_THROW(syncStorage->findKeys(ns, "*"), BackendError);
459}
460
461TEST_F(SyncStorageImplTest, RemoveAllSuccessfully)
462{
463 InSequence dummy;
464 expectSdlReadinessCheck();
465 expectRemoveAllAsync();
466 expectPollWait();
467 expectHandleEvents();
468 syncStorage->removeAll(ns);
469}
470
471TEST_F(SyncStorageImplTest, RemoveAllCanThrowBackendError)
472{
473 InSequence dummy;
474 expectSdlReadinessCheck();
475 expectRemoveAllAsync();
476 expectPollWait();
477 expectModifyAckWithError();
478 EXPECT_THROW(syncStorage->removeAll(ns), BackendError);
479}
480
481TEST_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
514TEST_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 default:
561 FAIL() << "No mapping for AsyncRedisCommandDispatcherErrorCode value: " << aec;
562 break;
563 }
564 }
565}
566
567TEST_F(SyncStorageImplTest, CanThrowStdExceptionIfDispatcherErrorCodeCannotBeMappedToSdlException)
568{
569 InSequence dummy;
570 expectSdlReadinessCheck();
571 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
572 expectPollWait();
573 expectModifyIfAck(std::error_code(1, std::system_category()), false);
574 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), std::range_error);
575}