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.
18 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 * platform project (RICP).
22 #include <gtest/gtest.h>
23 #include "private/error.hpp"
24 #include "private/redis/asyncredisstorage.hpp"
25 #include "private/syncstorageimpl.hpp"
26 #include "private/tst/asyncstoragemock.hpp"
27 #include "private/tst/systemmock.hpp"
28 #include <sdl/backenderror.hpp>
29 #include <sdl/invalidnamespace.hpp>
30 #include <sdl/notconnected.hpp>
31 #include <sdl/operationinterrupted.hpp>
32 #include <sdl/rejectedbybackend.hpp>
34 using namespace shareddatalayer;
35 using namespace shareddatalayer::redis;
36 using namespace shareddatalayer::tst;
37 using namespace testing;
41 class SyncStorageImplTest: public testing::Test
44 std::unique_ptr<SyncStorageImpl> syncStorage;
45 /* AsyncStorageMock ownership will be passed to implementation. To be able to do verification
46 * with the mock object also here after its ownership is passed we take raw pointer to
47 * AsyncStorageMock before passing it to implementation. Works fine, as implementation will
48 * not release injected mock object before test case execution finishes
50 std::unique_ptr<StrictMock<AsyncStorageMock>> asyncStorageMockPassedToImplementation;
51 StrictMock<AsyncStorageMock>* asyncStorageMockRawPtr;
52 StrictMock<SystemMock> systemMock;
53 AsyncStorage::ModifyAck savedModifyAck;
54 AsyncStorage::ModifyIfAck savedModifyIfAck;
55 AsyncStorage::GetAck savedGetAck;
56 AsyncStorage::FindKeysAck savedFindKeysAck;
57 AsyncStorage::ReadyAck savedReadyAck;
59 SyncStorage::DataMap dataMap;
60 SyncStorage::Keys keys;
61 const SyncStorage::Namespace ns;
62 SyncStorageImplTest():
63 asyncStorageMockPassedToImplementation(new StrictMock<AsyncStorageMock>()),
64 asyncStorageMockRawPtr(asyncStorageMockPassedToImplementation.get()),
66 dataMap({{ "key1", { 0x0a, 0x0b, 0x0c } }, { "key2", { 0x0d, 0x0e, 0x0f, 0xff } }}),
67 keys({ "key1", "key2" }),
68 ns("someKnownNamespace")
70 expectConstructorCalls();
71 syncStorage.reset(new SyncStorageImpl(std::move(asyncStorageMockPassedToImplementation), systemMock));
74 void expectConstructorCalls()
77 EXPECT_CALL(*asyncStorageMockRawPtr, fd())
79 .WillOnce(Return(pFd));
82 void expectSdlReadinessCheck()
85 expectWaitReadyAsync();
92 EXPECT_CALL(systemMock, poll( _, 1, -1))
94 .WillOnce(Invoke([](struct pollfd *fds, nfds_t, int)
96 fds->revents = POLLIN;
101 void expectPollError()
103 EXPECT_CALL(systemMock, poll( _, 1, -1))
105 .WillOnce(Invoke([](struct pollfd *fds, nfds_t, int)
107 fds->revents = POLLIN;
112 void expectPollExceptionalCondition()
114 EXPECT_CALL(systemMock, poll( _, 1, -1))
116 .WillOnce(Invoke([](struct pollfd *fds, nfds_t, int)
118 fds->revents = POLLPRI;
123 void expectHandleEvents()
125 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
127 .WillOnce(Invoke([this]()
129 savedReadyAck(std::error_code());
133 void expectWaitReadyAsync()
135 EXPECT_CALL(*asyncStorageMockRawPtr, waitReadyAsync(ns,_))
137 .WillOnce(SaveArg<1>(&savedReadyAck));
141 void expectModifyAckWithError()
143 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
145 .WillOnce(Invoke([this]()
147 savedModifyAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY);
151 void expectModifyIfAck(const std::error_code& error, bool status)
153 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
155 .WillOnce(Invoke([this, error, status]()
157 savedModifyIfAck(error, status);
161 void expectGetAckWithError()
163 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
165 .WillOnce(Invoke([this]()
167 savedGetAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, dataMap);
173 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
175 .WillOnce(Invoke([this]()
177 savedGetAck(std::error_code(), dataMap);
181 void expectFindKeysAck()
183 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
185 .WillOnce(Invoke([this]()
187 savedFindKeysAck(std::error_code(), keys);
191 void expectFindKeysAckWithError()
193 EXPECT_CALL(*asyncStorageMockRawPtr, handleEvents())
195 .WillOnce(Invoke([this]()
197 savedFindKeysAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, keys);
201 void expectSetAsync(const SyncStorage::DataMap& dataMap)
203 EXPECT_CALL(*asyncStorageMockRawPtr, setAsync(ns, dataMap, _))
205 .WillOnce(SaveArg<2>(&savedModifyAck));
208 void expectSetIfAsync(const SyncStorage::Key& key, const SyncStorage::Data& oldData, const SyncStorage::Data& newData)
210 EXPECT_CALL(*asyncStorageMockRawPtr, setIfAsync(ns, key, oldData, newData, _))
212 .WillOnce(SaveArg<4>(&savedModifyIfAck));
215 void expectGetAsync(const SyncStorage::Keys& keys)
217 EXPECT_CALL(*asyncStorageMockRawPtr, getAsync(ns, keys, _))
219 .WillOnce(SaveArg<2>(&savedGetAck));
222 void expectFindKeysAsync()
224 EXPECT_CALL(*asyncStorageMockRawPtr, findKeysAsync(ns, _, _))
226 .WillOnce(SaveArg<2>(&savedFindKeysAck));
229 void expectRemoveAsync(const SyncStorage::Keys& keys)
231 EXPECT_CALL(*asyncStorageMockRawPtr, removeAsync(ns, keys, _))
233 .WillOnce(SaveArg<2>(&savedModifyAck));
236 void expectRemoveIfAsync(const SyncStorage::Key& key, const SyncStorage::Data& data)
238 EXPECT_CALL(*asyncStorageMockRawPtr, removeIfAsync(ns, key, data, _))
240 .WillOnce(SaveArg<3>(&savedModifyIfAck));
243 void expectRemoveAllAsync()
245 EXPECT_CALL(*asyncStorageMockRawPtr, removeAllAsync(ns, _))
247 .WillOnce(SaveArg<1>(&savedModifyAck));
250 void expectSetIfNotExistsAsync(const SyncStorage::Key& key, const SyncStorage::Data& data)
252 EXPECT_CALL(*asyncStorageMockRawPtr, setIfNotExistsAsync(ns, key, data, _))
254 .WillOnce(SaveArg<3>(&savedModifyIfAck));
259 TEST_F(SyncStorageImplTest, IsNotCopyable)
262 EXPECT_FALSE(std::is_copy_constructible<SyncStorageImpl>::value);
263 EXPECT_FALSE(std::is_copy_assignable<SyncStorageImpl>::value);
266 TEST_F(SyncStorageImplTest, ImplementssyncStorage)
269 EXPECT_TRUE((std::is_base_of<SyncStorage, SyncStorageImpl>::value));
272 TEST_F(SyncStorageImplTest, EventsAreNotHandledWhenPollReturnsError)
275 expectSdlReadinessCheck();
276 expectSetAsync(dataMap);
279 expectHandleEvents();
280 syncStorage->set(ns, dataMap);
283 TEST_F(SyncStorageImplTest, EventsAreNotHandledWhenThereIsAnExceptionalConditionOnTheFd)
286 expectSdlReadinessCheck();
287 expectSetAsync(dataMap);
288 expectPollExceptionalCondition();
290 expectHandleEvents();
291 syncStorage->set(ns, dataMap);
294 TEST_F(SyncStorageImplTest, SetSuccessfully)
297 expectSdlReadinessCheck();
298 expectSetAsync(dataMap);
300 expectHandleEvents();
301 syncStorage->set(ns, dataMap);
304 TEST_F(SyncStorageImplTest, SetCanThrowBackendError)
307 expectSdlReadinessCheck();
308 expectSetAsync(dataMap);
310 expectModifyAckWithError();
311 EXPECT_THROW(syncStorage->set(ns, dataMap), BackendError);
314 TEST_F(SyncStorageImplTest, SetIfSuccessfully)
317 expectSdlReadinessCheck();
318 expectSetAsync(dataMap);
320 expectHandleEvents();
321 syncStorage->set(ns, dataMap);
322 expectSdlReadinessCheck();
323 expectSetIfAsync("key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f });
325 expectHandleEvents();
326 syncStorage->setIf(ns, "key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f });
329 TEST_F(SyncStorageImplTest, SetIfCanThrowBackendError)
332 expectSdlReadinessCheck();
333 expectSetAsync(dataMap);
335 expectHandleEvents();
336 syncStorage->set(ns, dataMap);
337 expectSdlReadinessCheck();
338 expectSetIfAsync("key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f });
340 expectModifyIfAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, false);
341 EXPECT_THROW(syncStorage->setIf(ns, "key1", { 0x0a, 0x0b, 0x0c }, { 0x0d, 0x0e, 0x0f }), BackendError);
344 TEST_F(SyncStorageImplTest, SetIfNotExistsSuccessfully)
347 expectSdlReadinessCheck();
348 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
350 expectModifyIfAck(std::error_code(), true);
351 EXPECT_TRUE(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }));
354 TEST_F(SyncStorageImplTest, SetIfNotExistsReturnsFalseIfKeyAlreadyExists)
357 expectSdlReadinessCheck();
358 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
360 expectModifyIfAck(std::error_code(), false);
361 EXPECT_FALSE(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }));
364 TEST_F(SyncStorageImplTest, SetIfNotExistsCanThrowBackendError)
367 expectSdlReadinessCheck();
368 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
370 expectModifyIfAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, false);
371 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
374 TEST_F(SyncStorageImplTest, GetSuccessfully)
377 expectSdlReadinessCheck();
378 expectGetAsync(keys);
381 auto map(syncStorage->get(ns, keys));
382 EXPECT_EQ(map, dataMap);
385 TEST_F(SyncStorageImplTest, GetCanThrowBackendError)
388 expectSdlReadinessCheck();
389 expectGetAsync(keys);
391 expectGetAckWithError();
392 EXPECT_THROW(syncStorage->get(ns, keys), BackendError);
395 TEST_F(SyncStorageImplTest, RemoveSuccessfully)
398 expectSdlReadinessCheck();
399 expectRemoveAsync(keys);
401 expectHandleEvents();
402 syncStorage->remove(ns, keys);
405 TEST_F(SyncStorageImplTest, RemoveCanThrowBackendError)
408 expectSdlReadinessCheck();
409 expectRemoveAsync(keys);
411 expectModifyAckWithError();
412 EXPECT_THROW(syncStorage->remove(ns, keys), BackendError);
415 TEST_F(SyncStorageImplTest, RemoveIfSuccessfully)
418 expectSdlReadinessCheck();
419 expectRemoveIfAsync("key1", { 0x0a, 0x0b, 0x0c });
421 expectModifyIfAck(std::error_code(), true);
422 EXPECT_TRUE(syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }));
425 TEST_F(SyncStorageImplTest, RemoveIfReturnsFalseIfKeyDoesnotMatch)
428 expectSdlReadinessCheck();
429 expectRemoveIfAsync("key1", { 0x0a, 0x0b, 0x0c });
431 expectModifyIfAck(std::error_code(), false);
432 EXPECT_FALSE(syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }));
435 TEST_F(SyncStorageImplTest, RemoveIfCanThrowBackendError)
438 expectSdlReadinessCheck();
439 expectRemoveIfAsync("key1", { 0x0a, 0x0b, 0x0c });
441 expectModifyIfAck(AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY, false);
442 EXPECT_THROW(syncStorage->removeIf(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
445 TEST_F(SyncStorageImplTest, FindKeysSuccessfully)
448 expectSdlReadinessCheck();
449 expectFindKeysAsync();
452 auto ids(syncStorage->findKeys(ns, "*"));
453 EXPECT_EQ(ids, keys);
456 TEST_F(SyncStorageImplTest, FindKeysAckCanThrowBackendError)
459 expectSdlReadinessCheck();
460 expectFindKeysAsync();
462 expectFindKeysAckWithError();
463 EXPECT_THROW(syncStorage->findKeys(ns, "*"), BackendError);
466 TEST_F(SyncStorageImplTest, RemoveAllSuccessfully)
469 expectSdlReadinessCheck();
470 expectRemoveAllAsync();
472 expectHandleEvents();
473 syncStorage->removeAll(ns);
476 TEST_F(SyncStorageImplTest, RemoveAllCanThrowBackendError)
479 expectSdlReadinessCheck();
480 expectRemoveAllAsync();
482 expectModifyAckWithError();
483 EXPECT_THROW(syncStorage->removeAll(ns), BackendError);
486 TEST_F(SyncStorageImplTest, AllAsyncRedisStorageErrorCodesThrowCorrectException)
491 for (AsyncRedisStorage::ErrorCode arsec = AsyncRedisStorage::ErrorCode::SUCCESS; arsec < AsyncRedisStorage::ErrorCode::END_MARKER; ++arsec)
493 if (arsec != AsyncRedisStorage::ErrorCode::SUCCESS)
495 expectSdlReadinessCheck();
496 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
502 case AsyncRedisStorage::ErrorCode::SUCCESS:
504 case AsyncRedisStorage::ErrorCode::INVALID_NAMESPACE:
505 expectModifyIfAck(arsec, false);
506 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), InvalidNamespace);
508 case AsyncRedisStorage::ErrorCode::REDIS_NOT_YET_DISCOVERED:
509 expectModifyIfAck(arsec, false);
510 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), NotConnected);
513 FAIL() << "No mapping for AsyncRedisStorage::ErrorCode value: " << arsec;
519 TEST_F(SyncStorageImplTest, AllDispatcherErrorCodesThrowCorrectException)
524 for (AsyncRedisCommandDispatcherErrorCode aec = AsyncRedisCommandDispatcherErrorCode::SUCCESS; aec < AsyncRedisCommandDispatcherErrorCode::END_MARKER; ++aec)
526 if (aec != AsyncRedisCommandDispatcherErrorCode::SUCCESS)
528 expectSdlReadinessCheck();
529 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
535 case AsyncRedisCommandDispatcherErrorCode::SUCCESS:
537 case AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR:
538 expectModifyIfAck(aec, false);
539 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
541 case AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST:
542 expectModifyIfAck(aec, false);
543 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), OperationInterrupted);
545 case AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR:
546 expectModifyIfAck(aec, false);
547 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), RejectedByBackend);
549 case AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY:
550 expectModifyIfAck(aec, false);
551 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
553 case AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING:
554 expectModifyIfAck(aec, false);
555 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), NotConnected);
557 case AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED:
558 expectModifyIfAck(aec, false);
559 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), NotConnected);
561 case AsyncRedisCommandDispatcherErrorCode::IO_ERROR:
562 expectModifyIfAck(aec, false);
563 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
565 case AsyncRedisCommandDispatcherErrorCode::WRITING_TO_SLAVE:
566 expectModifyIfAck(aec, false);
567 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), BackendError);
570 FAIL() << "No mapping for AsyncRedisCommandDispatcherErrorCode value: " << aec;
576 TEST_F(SyncStorageImplTest, CanThrowStdExceptionIfDispatcherErrorCodeCannotBeMappedToSdlException)
579 expectSdlReadinessCheck();
580 expectSetIfNotExistsAsync("key1", { 0x0a, 0x0b, 0x0c });
582 expectModifyIfAck(std::error_code(1, std::system_category()), false);
583 EXPECT_THROW(syncStorage->setIfNotExists(ns, "key1", { 0x0a, 0x0b, 0x0c }), std::range_error);