2 Copyright (c) 2018-2019 Nokia.
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
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>
29 using namespace shareddatalayer;
30 using namespace shareddatalayer::redis;
31 using namespace shareddatalayer::tst;
32 using namespace testing;
36 class SyncStorageImplTest: public testing::Test
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
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;
54 SyncStorage::DataMap dataMap;
55 SyncStorage::Keys keys;
56 const SyncStorage::Namespace ns;
57 SyncStorageImplTest():
58 asyncStorageMockPassedToImplementation(new StrictMock<AsyncStorageMock>()),
59 asyncStorageMockRawPtr(asyncStorageMockPassedToImplementation.get()),
61 dataMap({{ "key1", { 0x0a, 0x0b, 0x0c } }, { "key2", { 0x0d, 0x0e, 0x0f, 0xff } }}),
62 keys({ "key1", "key2" }),
63 ns("someKnownNamespace")
65 expectConstructorCalls();
66 syncStorage.reset(new SyncStorageImpl(std::move(asyncStorageMockPassedToImplementation), systemMock));
69 void expectConstructorCalls()
72 EXPECT_CALL(*asyncStorageMockRawPtr, fd())
74 .WillOnce(Return(pFd));
77 void expectSdlReadinessCheck()
80 expectWaitReadyAsync();
87 EXPECT_CALL(systemMock, poll( _, 1, -1))
89 .WillOnce(Invoke([](struct pollfd *fds, nfds_t, int)
91 fds->revents = POLLIN;
96 void expectPollError()
98 EXPECT_CALL(systemMock, poll( _, 1, -1))
100 .WillOnce(Invoke([](struct pollfd *fds, nfds_t, int)
102 fds->revents = POLLIN;
107 void expectPollExceptionalCondition()
109 EXPECT_CALL(systemMock, poll( _, 1, -1))
111 .WillOnce(Invoke([](struct pollfd *fds, nfds_t, int)
113 fds->revents = POLLPRI;
118 void expectHandleEvents()
120 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
122 .WillOnce(Invoke([this]()
124 savedReadyAck(std::error_code());
128 void expectWaitReadyAsync()
130 EXPECT_CALL(*asyncStorageMockRawPtr, waitReadyAsync(ns,_))
132 .WillOnce(SaveArg<1>(&savedReadyAck));
136 void expectModifyAckWithError()
138 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
140 .WillOnce(Invoke([this]()
142 savedModifyAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY);
146 void expectModifyIfAck(const std::error_code& error, bool status)
148 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
150 .WillOnce(Invoke([this, error, status]()
152 savedModifyIfAck(error, status);
156 void expectGetAckWithError()
158 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
160 .WillOnce(Invoke([this]()
162 savedGetAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, dataMap);
168 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
170 .WillOnce(Invoke([this]()
172 savedGetAck(std::error_code(), dataMap);
176 void expectFindKeysAck()
178 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
180 .WillOnce(Invoke([this]()
182 savedFindKeysAck(std::error_code(), keys);
186 void expectFindKeysAckWithError()
188 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
190 .WillOnce(Invoke([this]()
192 savedFindKeysAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, keys);
196 void expectSetAsync(const SyncStorage::DataMap& dataMap)
198 EXPECT_CALL(*asyncStorageMockRawPtr, setAsync(ns, dataMap, _))
200 .WillOnce(SaveArg<2>(&savedModifyAck));
203 void expectSetIfAsync(const SyncStorage::Key& key, const SyncStorage::Data& oldData, const SyncStorage::Data& newData)
205 EXPECT_CALL(*asyncStorageMockRawPtr, setIfAsync(ns, key, oldData, newData, _))
207 .WillOnce(SaveArg<4>(&savedModifyIfAck));
210 void expectGetAsync(const SyncStorage::Keys& keys)
212 EXPECT_CALL(*asyncStorageMockRawPtr, getAsync(ns, keys, _))
214 .WillOnce(SaveArg<2>(&savedGetAck));
217 void expectFindKeysAsync()
219 EXPECT_CALL(*asyncStorageMockRawPtr, findKeysAsync(ns, _, _))
221 .WillOnce(SaveArg<2>(&savedFindKeysAck));
224 void expectRemoveAsync(const SyncStorage::Keys& keys)
226 EXPECT_CALL(*asyncStorageMockRawPtr, removeAsync(ns, keys, _))
228 .WillOnce(SaveArg<2>(&savedModifyAck));
231 void expectRemoveIfAsync(const SyncStorage::Key& key, const SyncStorage::Data& data)
233 EXPECT_CALL(*asyncStorageMockRawPtr, removeIfAsync(ns, key, data, _))
235 .WillOnce(SaveArg<3>(&savedModifyIfAck));
238 void expectRemoveAllAsync()
240 EXPECT_CALL(*asyncStorageMockRawPtr, removeAllAsync(ns, _))
242 .WillOnce(SaveArg<1>(&savedModifyAck));
245 void expectSetIfNotExistsAsync(const SyncStorage::Key& key, const SyncStorage::Data& data)
247 EXPECT_CALL(*asyncStorageMockRawPtr, setIfNotExistsAsync(ns, key, data, _))
249 .WillOnce(SaveArg<3>(&savedModifyIfAck));
254 TEST_F(SyncStorageImplTest, IsNotCopyable)
257 EXPECT_FALSE(std::is_copy_constructible<SyncStorageImpl>::value);
258 EXPECT_FALSE(std::is_copy_assignable<SyncStorageImpl>::value);
261 TEST_F(SyncStorageImplTest, ImplementssyncStorage)
264 EXPECT_TRUE((std::is_base_of<SyncStorage, SyncStorageImpl>::value));
267 TEST_F(SyncStorageImplTest, EventsAreNotHandledWhenPollReturnsError)
270 expectSdlReadinessCheck();
271 expectSetAsync(dataMap);
274 expectHandleEvents();
275 syncStorage->set(ns, dataMap);
278 TEST_F(SyncStorageImplTest, EventsAreNotHandledWhenThereIsAnExceptionalConditionOnTheFd)
281 expectSdlReadinessCheck();
282 expectSetAsync(dataMap);
283 expectPollExceptionalCondition();
285 expectHandleEvents();
286 syncStorage->set(ns, dataMap);
289 TEST_F(SyncStorageImplTest, SetSuccessfully)
292 expectSdlReadinessCheck();
293 expectSetAsync(dataMap);
295 expectHandleEvents();
296 syncStorage->set(ns, dataMap);
299 TEST_F(SyncStorageImplTest, SetCanThrowBackendError)
302 expectSdlReadinessCheck();
303 expectSetAsync(dataMap);
305 expectModifyAckWithError();
306 EXPECT_THROW(syncStorage->set(ns, dataMap), BackendError);
309 TEST_F(SyncStorageImplTest, SetIfSuccessfully)
312 expectSdlReadinessCheck();
313 expectSetAsync(dataMap);
315 expectHandleEvents();
316 syncStorage->set(ns, dataMap);
317 expectSdlReadinessCheck();
318 expectSetIfAsync("key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f });
320 expectHandleEvents();
321 syncStorage->setIf(ns, "key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f });
324 TEST_F(SyncStorageImplTest, SetIfCanThrowBackendError)
327 expectSdlReadinessCheck();
328 expectSetAsync(dataMap);
330 expectHandleEvents();
331 syncStorage->set(ns, dataMap);
332 expectSdlReadinessCheck();
333 expectSetIfAsync("key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f });
335 expectModifyIfAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, false);
336 EXPECT_THROW(syncStorage->setIf(ns, "key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f }), BackendError);
339 TEST_F(SyncStorageImplTest, SetIfNotExistsSuccessfully)
342 expectSdlReadinessCheck();
343 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
345 expectModifyIfAck(std::error_code(), true);
346 EXPECT_EQ(true, syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }));
349 TEST_F(SyncStorageImplTest, SetIfNotExistsReturnsFalseIfKeyAlreadyExists)
352 expectSdlReadinessCheck();
353 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
355 expectModifyIfAck(std::error_code(), false);
356 EXPECT_EQ(false, syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }));
359 TEST_F(SyncStorageImplTest, SetIfNotExistsCanThrowBackendError)
362 expectSdlReadinessCheck();
363 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
365 expectModifyIfAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, false);
366 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
369 TEST_F(SyncStorageImplTest, GetSuccessfully)
372 expectSdlReadinessCheck();
373 expectGetAsync(keys);
376 auto map(syncStorage->get(ns, keys));
377 EXPECT_EQ(map, dataMap);
380 TEST_F(SyncStorageImplTest, GetCanThrowBackendError)
383 expectSdlReadinessCheck();
384 expectGetAsync(keys);
386 expectGetAckWithError();
387 EXPECT_THROW(syncStorage->get(ns, keys), BackendError);
390 TEST_F(SyncStorageImplTest, RemoveSuccessfully)
393 expectSdlReadinessCheck();
394 expectRemoveAsync(keys);
396 expectHandleEvents();
397 syncStorage->remove(ns, keys);
400 TEST_F(SyncStorageImplTest, RemoveCanThrowBackendError)
403 expectSdlReadinessCheck();
404 expectRemoveAsync(keys);
406 expectModifyAckWithError();
407 EXPECT_THROW(syncStorage->remove(ns, keys), BackendError);
410 TEST_F(SyncStorageImplTest, RemoveIfSuccessfully)
413 expectSdlReadinessCheck();
414 expectRemoveIfAsync("key1", { 0x0a, 0x0b, 0x0c });
416 expectModifyIfAck(std::error_code(), true);
417 EXPECT_EQ(true, syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }));
420 TEST_F(SyncStorageImplTest, RemoveIfReturnsFalseIfKeyDoesnotMatch)
423 expectSdlReadinessCheck();
424 expectRemoveIfAsync("key1", { 0x0a, 0x0b, 0x0c });
426 expectModifyIfAck(std::error_code(), false);
427 EXPECT_EQ(false, syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }));
430 TEST_F(SyncStorageImplTest, RemoveIfCanThrowBackendError)
433 expectSdlReadinessCheck();
434 expectRemoveIfAsync("key1", { 0x0a, 0x0b, 0x0c });
436 expectModifyIfAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, false);
437 EXPECT_THROW(syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
440 TEST_F(SyncStorageImplTest, FindKeysSuccessfully)
443 expectSdlReadinessCheck();
444 expectFindKeysAsync();
447 auto ids(syncStorage->findKeys(ns, "*"));
448 EXPECT_EQ(ids, keys);
451 TEST_F(SyncStorageImplTest, FindKeysAckCanThrowBackendError)
454 expectSdlReadinessCheck();
455 expectFindKeysAsync();
457 expectFindKeysAckWithError();
458 EXPECT_THROW(syncStorage->findKeys(ns, "*"), BackendError);
461 TEST_F(SyncStorageImplTest, RemoveAllSuccessfully)
464 expectSdlReadinessCheck();
465 expectRemoveAllAsync();
467 expectHandleEvents();
468 syncStorage->removeAll(ns);
471 TEST_F(SyncStorageImplTest, RemoveAllCanThrowBackendError)
474 expectSdlReadinessCheck();
475 expectRemoveAllAsync();
477 expectModifyAckWithError();
478 EXPECT_THROW(syncStorage->removeAll(ns), BackendError);
481 TEST_F(SyncStorageImplTest, AllAsyncRedisStorageErrorCodesThrowCorrectException)
486 for (AsyncRedisStorage::ErrorCode arsec = AsyncRedisStorage::ErrorCode::SUCCESS; arsec < AsyncRedisStorage::ErrorCode::END_MARKER; ++arsec)
488 if (arsec != AsyncRedisStorage::ErrorCode::SUCCESS)
490 expectSdlReadinessCheck();
491 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
497 case AsyncRedisStorage::ErrorCode::SUCCESS:
499 case AsyncRedisStorage::ErrorCode::INVALID_NAMESPACE:
500 expectModifyIfAck(arsec, false);
501 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), InvalidNamespace);
503 case AsyncRedisStorage::ErrorCode::REDIS_NOT_YET_DISCOVERED:
504 expectModifyIfAck(arsec, false);
505 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), NotConnected);
508 FAIL() << "No mapping for AsyncRedisStorage::ErrorCode value: " << arsec;
514 TEST_F(SyncStorageImplTest, AllDispatcherErrorCodesThrowCorrectException)
519 for (AsyncRedisCommandDispatcherErrorCode aec = AsyncRedisCommandDispatcherErrorCode::SUCCESS; aec < AsyncRedisCommandDispatcherErrorCode::END_MARKER; ++aec)
521 if (aec != AsyncRedisCommandDispatcherErrorCode::SUCCESS)
523 expectSdlReadinessCheck();
524 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
530 case AsyncRedisCommandDispatcherErrorCode::SUCCESS:
532 case AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR:
533 expectModifyIfAck(aec, false);
534 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
536 case AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST:
537 expectModifyIfAck(aec, false);
538 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), OperationInterrupted);
540 case AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR:
541 expectModifyIfAck(aec, false);
542 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), RejectedByBackend);
544 case AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY:
545 expectModifyIfAck(aec, false);
546 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
548 case AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING:
549 expectModifyIfAck(aec, false);
550 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), NotConnected);
552 case AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED:
553 expectModifyIfAck(aec, false);
554 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), NotConnected);
556 case AsyncRedisCommandDispatcherErrorCode::IO_ERROR:
557 expectModifyIfAck(aec, false);
558 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
561 FAIL() << "No mapping for AsyncRedisCommandDispatcherErrorCode value: " << aec;
567 TEST_F(SyncStorageImplTest, CanThrowStdExceptionIfDispatcherErrorCodeCannotBeMappedToSdlException)
570 expectSdlReadinessCheck();
571 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
573 expectModifyIfAck(std::error_code(1, std::system_category()), false);
574 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), std::range_error);