diff --git a/services/backup/src/DatabaseManager.cpp b/services/backup/src/DatabaseManager.cpp index 80188fd69..7564e0467 100644 --- a/services/backup/src/DatabaseManager.cpp +++ b/services/backup/src/DatabaseManager.cpp @@ -1,160 +1,173 @@ #include "DatabaseManager.h" #include "Constants.h" #include "GlobalTools.h" #include "Tools.h" #include #include #include #include +#include #include namespace comm { namespace network { namespace database { DatabaseManager &DatabaseManager::getInstance() { static DatabaseManager instance; return instance; } void DatabaseManager::putBackupItem(const BackupItem &item) { Aws::DynamoDB::Model::PutItemRequest request; request.SetTableName(BackupItem::tableName); request.AddItem( BackupItem::FIELD_USER_ID, Aws::DynamoDB::Model::AttributeValue(item.getUserID())); request.AddItem( BackupItem::FIELD_CREATED, Aws::DynamoDB::Model::AttributeValue( std::to_string(tools::getCurrentTimestamp()))); request.AddItem( BackupItem::FIELD_BACKUP_ID, Aws::DynamoDB::Model::AttributeValue(item.getBackupID())); request.AddItem( BackupItem::FIELD_RECOVERY_DATA, Aws::DynamoDB::Model::AttributeValue(item.getRecoveryData())); request.AddItem( BackupItem::FIELD_COMPACTION_HOLDER, Aws::DynamoDB::Model::AttributeValue(item.getCompactionHolder())); if (!item.getAttachmentHolders().empty()) { request.AddItem( BackupItem::FIELD_ATTACHMENT_HOLDERS, Aws::DynamoDB::Model::AttributeValue(item.getAttachmentHolders())); } this->innerPutItem(std::make_shared(item), request); } std::shared_ptr DatabaseManager::findBackupItem( const std::string &userID, const std::string &backupID) { Aws::DynamoDB::Model::GetItemRequest request; request.AddKey( BackupItem::FIELD_USER_ID, Aws::DynamoDB::Model::AttributeValue(userID)); request.AddKey( BackupItem::FIELD_BACKUP_ID, Aws::DynamoDB::Model::AttributeValue(backupID)); - return std::move(this->innerFindItem(request)); + return this->innerFindItem(request); } std::shared_ptr DatabaseManager::findLastBackupItem(const std::string &userID) { std::shared_ptr item = createItemByType(); Aws::DynamoDB::Model::QueryRequest req; req.SetTableName(BackupItem::tableName); req.SetKeyConditionExpression(BackupItem::FIELD_USER_ID + " = :valueToMatch"); AttributeValues attributeValues; attributeValues.emplace(":valueToMatch", userID); req.SetExpressionAttributeValues(attributeValues); req.SetIndexName("userID-created-index"); req.SetLimit(1); req.SetScanIndexForward(false); const Aws::DynamoDB::Model::QueryOutcome &outcome = getDynamoDBClient()->Query(req); if (!outcome.IsSuccess()) { throw std::runtime_error(outcome.GetError().GetMessage()); } const Aws::Vector &items = outcome.GetResult().GetItems(); if (items.empty()) { return nullptr; } return std::make_shared(items[0]); } void DatabaseManager::removeBackupItem(std::shared_ptr item) { if (item == nullptr) { return; } this->innerRemoveItem(*item); } void DatabaseManager::putLogItem(const LogItem &item) { Aws::DynamoDB::Model::PutItemRequest request; request.SetTableName(LogItem::tableName); request.AddItem( LogItem::FIELD_BACKUP_ID, Aws::DynamoDB::Model::AttributeValue(item.getBackupID())); request.AddItem( LogItem::FIELD_LOG_ID, Aws::DynamoDB::Model::AttributeValue(item.getLogID())); request.AddItem( LogItem::FIELD_PERSISTED_IN_BLOB, Aws::DynamoDB::Model::AttributeValue( std::to_string(item.getPersistedInBlob()))); request.AddItem( LogItem::FIELD_VALUE, Aws::DynamoDB::Model::AttributeValue(item.getValue())); if (!item.getAttachmentHolders().empty()) { request.AddItem( LogItem::FIELD_ATTACHMENT_HOLDERS, Aws::DynamoDB::Model::AttributeValue(item.getAttachmentHolders())); } this->innerPutItem(std::make_shared(item), request); } +std::shared_ptr DatabaseManager::findLogItem( + const std::string &backupID, + const std::string &logID) { + Aws::DynamoDB::Model::GetItemRequest request; + request.AddKey( + LogItem::FIELD_BACKUP_ID, Aws::DynamoDB::Model::AttributeValue(backupID)); + request.AddKey( + LogItem::FIELD_LOG_ID, Aws::DynamoDB::Model::AttributeValue(logID)); + + return this->innerFindItem(request); +} + std::vector> DatabaseManager::findLogItemsForBackup(const std::string &backupID) { std::vector> result; std::shared_ptr item = createItemByType(); Aws::DynamoDB::Model::QueryRequest req; req.SetTableName(LogItem::tableName); req.SetKeyConditionExpression(LogItem::FIELD_BACKUP_ID + " = :valueToMatch"); AttributeValues attributeValues; attributeValues.emplace(":valueToMatch", backupID); req.SetExpressionAttributeValues(attributeValues); const Aws::DynamoDB::Model::QueryOutcome &outcome = getDynamoDBClient()->Query(req); if (!outcome.IsSuccess()) { throw std::runtime_error(outcome.GetError().GetMessage()); } const Aws::Vector &items = outcome.GetResult().GetItems(); for (auto &item : items) { result.push_back(std::make_shared(item)); } return result; } void DatabaseManager::removeLogItem(std::shared_ptr item) { if (item == nullptr) { return; } this->innerRemoveItem(*item); } } // namespace database } // namespace network } // namespace comm diff --git a/services/backup/src/DatabaseManager.h b/services/backup/src/DatabaseManager.h index 0c9c5db2b..81d5848af 100644 --- a/services/backup/src/DatabaseManager.h +++ b/services/backup/src/DatabaseManager.h @@ -1,38 +1,40 @@ #pragma once #include "DatabaseEntitiesTools.h" #include "DatabaseManagerBase.h" #include "DynamoDBTools.h" #include #include #include #include #include #include namespace comm { namespace network { namespace database { // this class should be thread-safe in case any shared resources appear class DatabaseManager : public DatabaseManagerBase { public: static DatabaseManager &getInstance(); void putBackupItem(const BackupItem &item); std::shared_ptr findBackupItem(const std::string &userID, const std::string &backupID); std::shared_ptr findLastBackupItem(const std::string &userID); void removeBackupItem(std::shared_ptr item); void putLogItem(const LogItem &item); + std::shared_ptr + findLogItem(const std::string &backupID, const std::string &logID); std::vector> findLogItemsForBackup(const std::string &backupID); void removeLogItem(std::shared_ptr item); }; } // namespace database } // namespace network } // namespace comm diff --git a/services/backup/test/DatabaseManagerTest.cpp b/services/backup/test/DatabaseManagerTest.cpp index 08a27fcbf..61d155cd9 100644 --- a/services/backup/test/DatabaseManagerTest.cpp +++ b/services/backup/test/DatabaseManagerTest.cpp @@ -1,105 +1,133 @@ #include #include "DatabaseManager.h" #include "GlobalTools.h" #include "Tools.h" #include #include #include #include using namespace comm::network::database; class DatabaseManagerTest : public testing::Test { protected: virtual void SetUp() { Aws::InitAPI({}); } virtual void TearDown() { Aws::ShutdownAPI({}); } }; std::string generateName(const std::string prefix = "") { return prefix + "-" + std::to_string(comm::network::tools::getCurrentTimestamp()); } BackupItem generateBackupItem(const std::string &userID, const std::string &backupID) { return BackupItem( userID, backupID, comm::network::tools::getCurrentTimestamp(), "xxx", "xxx", {""}); } LogItem generateLogItem(const std::string &backupID, const std::string &logID) { return LogItem(backupID, logID, false, "xxx", {""}); } TEST_F(DatabaseManagerTest, TestOperationsOnBackupItems) { const std::string userID = generateName("user001"); std::vector backupIDs = {"backup001", "backup002", "backup003"}; for (const std::string &backupID : backupIDs) { DatabaseManager::getInstance().putBackupItem( generateBackupItem(userID, backupID)); } std::shared_ptr item; while (!backupIDs.empty()) { item = DatabaseManager::getInstance().findLastBackupItem(userID); EXPECT_NE(item, nullptr); EXPECT_EQ(item->getBackupID(), backupIDs.back()); backupIDs.pop_back(); DatabaseManager::getInstance().removeBackupItem(item); }; EXPECT_EQ(DatabaseManager::getInstance().findLastBackupItem(userID), nullptr); } TEST_F(DatabaseManagerTest, TestOperationsOnLogItems) { const std::string backupID1 = generateName("backup001"); const std::string backupID2 = generateName("backup002"); std::vector logIDs1 = {"log001", "log002", "log003"}; for (const std::string &logID : logIDs1) { - DatabaseManager::getInstance().putLogItem( - generateLogItem(backupID1, logID)); + LogItem generatedItem = generateLogItem(backupID1, logID); + DatabaseManager::getInstance().putLogItem(generatedItem); + std::shared_ptr foundItem = + DatabaseManager::getInstance().findLogItem(backupID1, logID); + EXPECT_NE(foundItem, nullptr); + EXPECT_EQ(foundItem->getBackupID(), generatedItem.getBackupID()); + EXPECT_EQ(foundItem->getLogID(), generatedItem.getLogID()); + EXPECT_EQ( + foundItem->getPersistedInBlob(), generatedItem.getPersistedInBlob()); + EXPECT_EQ(foundItem->getValue(), generatedItem.getValue()); + EXPECT_EQ( + foundItem->getAttachmentHolders(), + generatedItem.getAttachmentHolders()); } std::vector logIDs2 = {"log021", "log022"}; for (const std::string &logID : logIDs2) { - DatabaseManager::getInstance().putLogItem( - generateLogItem(backupID2, logID)); + LogItem generatedItem = generateLogItem(backupID2, logID); + DatabaseManager::getInstance().putLogItem(generatedItem); + std::shared_ptr foundItem = + DatabaseManager::getInstance().findLogItem(backupID2, logID); + EXPECT_NE(foundItem, nullptr); + EXPECT_EQ(foundItem->getBackupID(), generatedItem.getBackupID()); + EXPECT_EQ(foundItem->getLogID(), generatedItem.getLogID()); + EXPECT_EQ( + foundItem->getPersistedInBlob(), generatedItem.getPersistedInBlob()); + EXPECT_EQ(foundItem->getValue(), generatedItem.getValue()); + EXPECT_EQ( + foundItem->getAttachmentHolders(), + generatedItem.getAttachmentHolders()); } std::vector> items1 = DatabaseManager::getInstance().findLogItemsForBackup(backupID1); std::vector> items2 = DatabaseManager::getInstance().findLogItemsForBackup(backupID2); EXPECT_EQ(items1.size(), 3); EXPECT_EQ(items2.size(), 2); for (size_t i = 0; i < items1.size(); ++i) { EXPECT_EQ(logIDs1.at(i), items1.at(i)->getLogID()); DatabaseManager::getInstance().removeLogItem(items1.at(i)); + EXPECT_EQ( + DatabaseManager::getInstance().findLogItem(backupID1, logIDs1.at(i)), + nullptr); } EXPECT_EQ( DatabaseManager::getInstance().findLogItemsForBackup(backupID1).size(), 0); for (size_t i = 0; i < items2.size(); ++i) { EXPECT_EQ(logIDs2.at(i), items2.at(i)->getLogID()); DatabaseManager::getInstance().removeLogItem(items2.at(i)); + EXPECT_EQ( + DatabaseManager::getInstance().findLogItem(backupID2, logIDs2.at(i)), + nullptr); } EXPECT_EQ( DatabaseManager::getInstance().findLogItemsForBackup(backupID2).size(), 0); }