From 0fa3bb1d87d12ff0b6dad570a2506d0a696e8f23 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Wed, 12 Nov 2014 18:02:34 +0100
Subject: [PATCH 01/16] Move migration tool to its parent directory
This patch drops creation of additional directory "cynara" in /usr/sbin.
According to FHS, there must not be placed any directories. Migration
scripts will get common prefix ("cynara-db-") and will be placed there
directly.
What is more, regardless of its actual contents, no executable in
/usr/sbin has file extension. This patch removes extension from main
migration tool script.
Change-Id: I4f5ccbf1e86815d4b4aa4e785dc01d8188d90fd5
---
migration/CMakeLists.txt | 4 ++--
migration/{cynara-db-migration.sh => cynara-db-migration} | 2 +-
packaging/cynara.spec | 8 ++++----
3 files changed, 7 insertions(+), 7 deletions(-)
rename migration/{cynara-db-migration.sh => cynara-db-migration} (98%)
diff --git a/migration/CMakeLists.txt b/migration/CMakeLists.txt
index b9bc9bf..48ee5f0 100644
--- a/migration/CMakeLists.txt
+++ b/migration/CMakeLists.txt
@@ -18,7 +18,7 @@
#
INSTALL(FILES
- ${CMAKE_SOURCE_DIR}/migration/cynara-db-migration.sh
+ ${CMAKE_SOURCE_DIR}/migration/cynara-db-migration
DESTINATION
- ${SBIN_INSTALL_DIR}/cynara/
+ ${SBIN_INSTALL_DIR}
)
diff --git a/migration/cynara-db-migration.sh b/migration/cynara-db-migration
similarity index 98%
rename from migration/cynara-db-migration.sh
rename to migration/cynara-db-migration
index 8cbebbf..5ab6409 100644
--- a/migration/cynara-db-migration.sh
+++ b/migration/cynara-db-migration
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-# @file migration/cynara-db-migration.sh
+# @file migration/cynara-db-migration
# @author Pawel Wieczorek
# @brief Migration tool for Cynara's database
#
diff --git a/packaging/cynara.spec b/packaging/cynara.spec
index bc51ae6..eea1b48 100644
--- a/packaging/cynara.spec
+++ b/packaging/cynara.spec
@@ -242,10 +242,10 @@ if [ $1 -gt 1 ] ; then
fi
fi
- %{_sbindir}/cynara/cynara-db-migration.sh upgrade -f ${OLD_VERSION} -t %{version}
+ %{_sbindir}/cynara-db-migration upgrade -f ${OLD_VERSION} -t %{version}
else
# install
- %{_sbindir}/cynara/cynara-db-migration.sh install -t %{version}
+ %{_sbindir}/cynara-db-migration install -t %{version}
fi
%post
@@ -271,7 +271,7 @@ fi
%postun
if [ $1 = 0 ]; then
- %{_sbindir}/cynara/cynara-db-migration.sh uninstall -f %{version}
+ %{_sbindir}/cynara-db-migration uninstall -f %{version}
userdel -r %{user_name} > /dev/null 2>&1
groupdel %{user_name} > /dev/null 2>&1
systemctl daemon-reload
@@ -385,7 +385,7 @@ fi
%files -n cynara-db-migration
%manifest cynara-db-migration.manifest
-%attr(700,root,root) %{_sbindir}/cynara/cynara-db-migration.sh
+%attr(700,root,root) %{_sbindir}/cynara-db-migration
%files -n cyad
%manifest cyad.manifest
--
2.7.4
From b114c892e4127260afbaaf304da68fec747ca36c Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Thu, 4 Dec 2014 11:45:40 +0100
Subject: [PATCH 02/16] Move storage consts to PatchConfig::StoragePath
Put all default values of Cynara storage consts into config namespace.
Change-Id: If0bfaca58708b575bfada41448f000272e54182e
---
src/common/config/PathConfig.cpp | 7 ++++++-
src/common/config/PathConfig.h | 7 ++++++-
src/storage/InMemoryStorageBackend.cpp | 11 +++++++----
src/storage/Integrity.cpp | 10 ++++++----
test/CMakeLists.txt | 1 +
5 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/src/common/config/PathConfig.cpp b/src/common/config/PathConfig.cpp
index 8dd0491..2e2309b 100644
--- a/src/common/config/PathConfig.cpp
+++ b/src/common/config/PathConfig.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,6 +54,11 @@ const std::string agent(clientPath + "cynara-agent.socket");
namespace StoragePath {
const std::string dbDir(statePath + "db/");
const std::string lockFile(statePath);
+const std::string indexFilename("buckets");
+const std::string guardFilename("guard");
+const std::string checksumFilename("checksum");
+const std::string bucketFilenamePrefix("_");
+const std::string backupFilenameSuffix("~");
} // namespace StoragePath
namespace PluginPath {
diff --git a/src/common/config/PathConfig.h b/src/common/config/PathConfig.h
index da5671f..0ba109f 100644
--- a/src/common/config/PathConfig.h
+++ b/src/common/config/PathConfig.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,6 +42,11 @@ extern const std::string agent;
namespace StoragePath {
extern const std::string dbDir;
extern const std::string lockFile;
+extern const std::string indexFilename;
+extern const std::string guardFilename;
+extern const std::string checksumFilename;
+extern const std::string bucketFilenamePrefix;
+extern const std::string backupFilenameSuffix;
} // namespace StoragePath
namespace PluginPath {
diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp
index 77676f0..4073963 100644
--- a/src/storage/InMemoryStorageBackend.cpp
+++ b/src/storage/InMemoryStorageBackend.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
#include
#include
+#include
#include
#include
#include
@@ -50,9 +51,11 @@
namespace Cynara {
-const std::string InMemoryStorageBackend::m_indexFilename = "buckets";
-const std::string InMemoryStorageBackend::m_backupFilenameSuffix = "~";
-const std::string InMemoryStorageBackend::m_bucketFilenamePrefix = "_";
+const std::string InMemoryStorageBackend::m_indexFilename(PathConfig::StoragePath::indexFilename);
+const std::string InMemoryStorageBackend::m_backupFilenameSuffix(
+ PathConfig::StoragePath::backupFilenameSuffix);
+const std::string InMemoryStorageBackend::m_bucketFilenamePrefix(
+ PathConfig::StoragePath::bucketFilenamePrefix);
void InMemoryStorageBackend::load(void) {
Integrity integrity(m_dbPath, m_indexFilename, m_backupFilenameSuffix, m_bucketFilenamePrefix);
diff --git a/src/storage/Integrity.cpp b/src/storage/Integrity.cpp
index 8057e9c..aebc1fd 100644
--- a/src/storage/Integrity.cpp
+++ b/src/storage/Integrity.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,15 +29,16 @@
#include
#include
-#include
+#include
#include
#include
+#include
#include "Integrity.h"
namespace Cynara {
-const std::string Integrity::m_guardFilename = "guard";
+const std::string Integrity::m_guardFilename(PathConfig::StoragePath::guardFilename);
bool Integrity::backupGuardExists(void) const {
struct stat buffer;
@@ -104,7 +105,8 @@ void Integrity::deleteNonIndexedFiles(BucketPresenceTester tester) {
while (errno = 0, (direntPtr = readdir(dirPtr)) != nullptr) {
std::string filename = direntPtr->d_name;
//ignore all special files (working dir, parent dir, index)
- if ("." == filename || ".." == filename || "buckets" == filename) {
+ if ("." == filename || ".." == filename ||
+ PathConfig::StoragePath::indexFilename == filename) {
continue;
}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 8032ee3..fe62294 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -23,6 +23,7 @@ ADD_DEFINITIONS("-DCYNARA_NO_LOGS")
SET(CYNARA_SRC ${PROJECT_SOURCE_DIR}/src)
SET(CYNARA_SOURCES_FOR_TESTS
+ ${CYNARA_SRC}/common/config/PathConfig.cpp
${CYNARA_SRC}/common/containers/BinaryQueue.cpp
${CYNARA_SRC}/common/protocol/ProtocolAdmin.cpp
${CYNARA_SRC}/common/protocol/ProtocolFrame.cpp
--
2.7.4
From 6ed5755961d571d0b9c21d99242c45a37d25333d Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Mon, 12 Jan 2015 13:45:21 +0100
Subject: [PATCH 03/16] Move bucket separators to PathConfig::StoragePath
This patch removes both bucket separators - for fields as well as for
records - from StorageSerializer. To this point they could be accessed
using provided static member functions. This is no longer possible, as
StorageSerializer has to be rewritten using templates.
Change-Id: Ib010bd0b125a1a93da9983d9bdd7b8f75cbbc191
---
src/common/config/PathConfig.cpp | 4 +++-
src/common/config/PathConfig.h | 4 +++-
src/cyad/AdminPolicyParser.cpp | 6 +++---
src/storage/BucketDeserializer.cpp | 8 ++++----
src/storage/StorageDeserializer.cpp | 8 ++++----
src/storage/StorageSerializer.cpp | 5 +----
src/storage/StorageSerializer.h | 19 ++++---------------
7 files changed, 22 insertions(+), 32 deletions(-)
diff --git a/src/common/config/PathConfig.cpp b/src/common/config/PathConfig.cpp
index 2e2309b..6039622 100644
--- a/src/common/config/PathConfig.cpp
+++ b/src/common/config/PathConfig.cpp
@@ -57,8 +57,10 @@ const std::string lockFile(statePath);
const std::string indexFilename("buckets");
const std::string guardFilename("guard");
const std::string checksumFilename("checksum");
-const std::string bucketFilenamePrefix("_");
const std::string backupFilenameSuffix("~");
+const std::string bucketFilenamePrefix("_");
+const char fieldSeparator(';');
+const char recordSeparator('\n');
} // namespace StoragePath
namespace PluginPath {
diff --git a/src/common/config/PathConfig.h b/src/common/config/PathConfig.h
index 0ba109f..8655e95 100644
--- a/src/common/config/PathConfig.h
+++ b/src/common/config/PathConfig.h
@@ -45,8 +45,10 @@ extern const std::string lockFile;
extern const std::string indexFilename;
extern const std::string guardFilename;
extern const std::string checksumFilename;
-extern const std::string bucketFilenamePrefix;
extern const std::string backupFilenameSuffix;
+extern const std::string bucketFilenamePrefix;
+extern const char fieldSeparator;
+extern const char recordSeparator;
} // namespace StoragePath
namespace PluginPath {
diff --git a/src/cyad/AdminPolicyParser.cpp b/src/cyad/AdminPolicyParser.cpp
index 530ca90..4f42a87 100644
--- a/src/cyad/AdminPolicyParser.cpp
+++ b/src/cyad/AdminPolicyParser.cpp
@@ -20,9 +20,9 @@
* @brief Parses policies from input stream
*/
+#include
#include
#include
-#include
#include "AdminPolicyParser.h"
@@ -35,7 +35,7 @@ CynaraAdminPolicies parse(const std::shared_ptr &input,
CynaraAdminPolicies policies;
auto nextToken = [] (const std::string &line, std::size_t &beginToken) -> std::string {
- auto endToken = line.find(StorageSerializer::fieldSeparator(), beginToken);
+ auto endToken = line.find(PathConfig::StoragePath::fieldSeparator, beginToken);
if (endToken != std::string::npos) {
auto token = line.substr(beginToken, endToken - beginToken);
beginToken = endToken + 1;
@@ -57,7 +57,7 @@ CynaraAdminPolicies parse(const std::shared_ptr &input,
for (std::size_t lineNum = 1; !input->eof(); ++lineNum) {
std::string line;
- std::getline(*input, line, StorageSerializer::recordSeparator());
+ std::getline(*input, line, PathConfig::StoragePath::recordSeparator);
if (line.empty())
break;
diff --git a/src/storage/BucketDeserializer.cpp b/src/storage/BucketDeserializer.cpp
index 68a3f4e..610e527 100644
--- a/src/storage/BucketDeserializer.cpp
+++ b/src/storage/BucketDeserializer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,13 +25,13 @@
#include
#include
+#include
#include
#include
#include
#include
#include
-#include
#include "BucketDeserializer.h"
@@ -43,7 +43,7 @@ PolicyCollection BucketDeserializer::loadPolicies(void) {
// TODO: Get someone smart to do error checking on stream
for (std::size_t lineNum = 1; !m_inStream->eof(); ++lineNum) {
std::string line;
- std::getline(*m_inStream, line, StorageSerializer::recordSeparator());
+ std::getline(*m_inStream, line, PathConfig::StoragePath::recordSeparator);
if (line.empty())
break;
@@ -67,7 +67,7 @@ PolicyKey BucketDeserializer::parseKey(const std::string &line, std::size_t &beg
std::array keyFeatures;
for (std::size_t tokenNum = 0; tokenNum < keyFeatures.size(); ++tokenNum) {
- auto endToken = line.find(StorageSerializer::fieldSeparator(), beginToken);
+ auto endToken = line.find(PathConfig::StoragePath::fieldSeparator, beginToken);
if (endToken != std::string::npos) {
keyFeatures[tokenNum] = line.substr(beginToken, endToken - beginToken);
beginToken = endToken + 1;
diff --git a/src/storage/StorageDeserializer.cpp b/src/storage/StorageDeserializer.cpp
index 166a406..5d9933e 100644
--- a/src/storage/StorageDeserializer.cpp
+++ b/src/storage/StorageDeserializer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,13 +24,13 @@
#include
#include
+#include
#include
#include
#include
#include
#include
-#include
#include "StorageDeserializer.h"
@@ -46,7 +46,7 @@ void StorageDeserializer::initBuckets(Buckets &buckets) {
for (std::size_t lineNum = 1; !m_inStream->eof(); ++lineNum) {
std::string line;
- std::getline(*m_inStream, line, StorageSerializer::recordSeparator());
+ std::getline(*m_inStream, line, PathConfig::StoragePath::recordSeparator);
if (line.empty())
break;
@@ -80,7 +80,7 @@ void StorageDeserializer::loadBuckets(Buckets &buckets) {
PolicyBucketId StorageDeserializer::parseBucketId(const std::string &line,
std::size_t &beginToken) {
- auto bucketNameEndToken = line.find(StorageSerializer::fieldSeparator(), beginToken);
+ auto bucketNameEndToken = line.find(PathConfig::StoragePath::fieldSeparator, beginToken);
if (bucketNameEndToken != std::string::npos) {
auto bucketName = line.substr(beginToken, bucketNameEndToken - beginToken);
beginToken = bucketNameEndToken + 1;
diff --git a/src/storage/StorageSerializer.cpp b/src/storage/StorageSerializer.cpp
index 132f2c6..9f701dd 100644
--- a/src/storage/StorageSerializer.cpp
+++ b/src/storage/StorageSerializer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,9 +35,6 @@
namespace Cynara {
-char StorageSerializer::m_fieldSeparator = ';';
-char StorageSerializer::m_recordSeparator = '\n';
-
StorageSerializer::StorageSerializer(std::shared_ptr os) : m_outStream(os) {
}
diff --git a/src/storage/StorageSerializer.h b/src/storage/StorageSerializer.h
index 8e21f9b..42982b2 100644
--- a/src/storage/StorageSerializer.h
+++ b/src/storage/StorageSerializer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
#include
#include
+#include
#include
#include
#include
@@ -56,13 +57,13 @@ protected:
inline void dumpFields(const Arg1 &arg1, const Args&... args) {
dump(arg1);
if (sizeof...(Args) > 0) {
- *m_outStream << fieldSeparator();
+ *m_outStream << PathConfig::StoragePath::fieldSeparator;
}
dumpFields(args...);
}
inline void dumpFields(void) {
- *m_outStream << recordSeparator();
+ *m_outStream << PathConfig::StoragePath::recordSeparator;
}
void dump(const PolicyKeyFeature &keyFeature);
@@ -72,18 +73,6 @@ protected:
private:
std::shared_ptr m_outStream;
-
- static char m_fieldSeparator;
- static char m_recordSeparator;
-
-public:
- static const char &fieldSeparator(void) {
- return m_fieldSeparator;
- }
-
- static const char &recordSeparator(void) {
- return m_recordSeparator;
- }
};
} /* namespace Cynara */
--
2.7.4
From 26587d28c78d36eb3f6d6ded73024058a0c73129 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Wed, 18 Feb 2015 15:36:33 +0100
Subject: [PATCH 04/16] Fix InMemoryStorageBackend unit tests
One of InMemoryStorageBackend unit tests - load_from_backup from
InMemeoryStorageBackendFixture group - gave inconclusive results. After
first execution of "cynara-tests" some contents of CYNARA_TESTS_DIR/db6
were removed. It was caused by insufficient mocking in
FakeInMemoryStorageBackend class.
This patch removes performing changes on filesystem from this test. It
also adjusts Integrity class to new PathConfig::StoragePath contents in
order to simplify its usage.
Change-Id: Ic5206ad337269996615ce36d60105b9c4ac32314
---
src/storage/InMemoryStorageBackend.cpp | 31 +++++++++++++---------
src/storage/InMemoryStorageBackend.h | 7 +++--
src/storage/Integrity.cpp | 7 ++++-
src/storage/Integrity.h | 18 ++++++-------
.../fakeinmemorystoragebackend.h | 1 +
.../inmemorystoragebackend.cpp | 12 +++++++++
6 files changed, 51 insertions(+), 25 deletions(-)
diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp
index 4073963..45b7874 100644
--- a/src/storage/InMemoryStorageBackend.cpp
+++ b/src/storage/InMemoryStorageBackend.cpp
@@ -57,9 +57,12 @@ const std::string InMemoryStorageBackend::m_backupFilenameSuffix(
const std::string InMemoryStorageBackend::m_bucketFilenamePrefix(
PathConfig::StoragePath::bucketFilenamePrefix);
+InMemoryStorageBackend::InMemoryStorageBackend(const std::string &path) : m_dbPath(path) {
+ m_integrity.reset(new Integrity(path));
+}
+
void InMemoryStorageBackend::load(void) {
- Integrity integrity(m_dbPath, m_indexFilename, m_backupFilenameSuffix, m_bucketFilenamePrefix);
- bool isBackupValid = integrity.backupGuardExists();
+ bool isBackupValid = m_integrity->backupGuardExists();
std::string bucketSuffix = "";
std::string indexFilename = m_dbPath + m_indexFilename;
@@ -89,12 +92,7 @@ void InMemoryStorageBackend::load(void) {
this->buckets().insert({ defaultPolicyBucketId, PolicyBucket(defaultPolicyBucketId) });
}
- if (isBackupValid) {
- integrity.revalidatePrimaryDatabase(buckets());
- }
- //in case there were unnecessary files in db directory
- integrity.deleteNonIndexedFiles(std::bind(&InMemoryStorageBackend::hasBucket, this,
- std::placeholders::_1));
+ postLoadCleanup(isBackupValid);
}
void InMemoryStorageBackend::save(void) {
@@ -106,11 +104,9 @@ void InMemoryStorageBackend::save(void) {
storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
this, std::placeholders::_1));
- Integrity integrity(m_dbPath, m_indexFilename, m_backupFilenameSuffix, m_bucketFilenamePrefix);
-
- integrity.syncDatabase(buckets(), true);
- integrity.createBackupGuard();
- integrity.revalidatePrimaryDatabase(buckets());
+ m_integrity->syncDatabase(buckets(), true);
+ m_integrity->createBackupGuard();
+ m_integrity->revalidatePrimaryDatabase(buckets());
//guard is removed during revalidation
}
@@ -267,4 +263,13 @@ std::shared_ptr InMemoryStorageBackend::bucketDumpStreamOpene
return std::make_shared(bucketStream);
}
+void InMemoryStorageBackend::postLoadCleanup(bool isBackupValid) {
+ if (isBackupValid) {
+ m_integrity->revalidatePrimaryDatabase(buckets());
+ }
+ //in case there were unnecessary files in db directory
+ m_integrity->deleteNonIndexedFiles(std::bind(&InMemoryStorageBackend::hasBucket, this,
+ std::placeholders::_1));
+}
+
} /* namespace Cynara */
diff --git a/src/storage/InMemoryStorageBackend.h b/src/storage/InMemoryStorageBackend.h
index 872486b..723c61d 100644
--- a/src/storage/InMemoryStorageBackend.h
+++ b/src/storage/InMemoryStorageBackend.h
@@ -35,6 +35,7 @@
#include
#include
+#include
#include
#include
@@ -42,8 +43,7 @@ namespace Cynara {
class InMemoryStorageBackend : public StorageBackend {
public:
- InMemoryStorageBackend(const std::string &path) : m_dbPath(path) {
- }
+ InMemoryStorageBackend(const std::string &path);
virtual ~InMemoryStorageBackend() {};
virtual void load(void);
@@ -73,9 +73,12 @@ protected:
const std::string &filename);
std::shared_ptr bucketDumpStreamOpener(const PolicyBucketId &bucketId);
+ virtual void postLoadCleanup(bool isBackupValid);
+
private:
std::string m_dbPath;
Buckets m_buckets;
+ IntegrityUniquePtr m_integrity;
static const std::string m_indexFilename;
static const std::string m_backupFilenameSuffix;
static const std::string m_bucketFilenamePrefix;
diff --git a/src/storage/Integrity.cpp b/src/storage/Integrity.cpp
index aebc1fd..82e8f5a 100644
--- a/src/storage/Integrity.cpp
+++ b/src/storage/Integrity.cpp
@@ -38,7 +38,12 @@
namespace Cynara {
-const std::string Integrity::m_guardFilename(PathConfig::StoragePath::guardFilename);
+namespace StorageConfig = PathConfig::StoragePath;
+
+const std::string Integrity::m_guardFilename(StorageConfig::guardFilename);
+const std::string Integrity::m_indexFilename(StorageConfig::indexFilename);
+const std::string Integrity::m_backupFilenameSuffix(StorageConfig::backupFilenameSuffix);
+const std::string Integrity::m_bucketFilenamePrefix(StorageConfig::bucketFilenamePrefix);
bool Integrity::backupGuardExists(void) const {
struct stat buffer;
diff --git a/src/storage/Integrity.h b/src/storage/Integrity.h
index 4b677b0..d06eada 100644
--- a/src/storage/Integrity.h
+++ b/src/storage/Integrity.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,21 +24,21 @@
#define SRC_STORAGE_INTEGRITY_H_
#include
+#include
#include
#include
namespace Cynara {
+class Integrity;
+typedef std::unique_ptr IntegrityUniquePtr;
+
class Integrity
{
public:
typedef std::function BucketPresenceTester;
- Integrity(const std::string &path, const std::string &index, const std::string &backupSuffix,
- const std::string &bucketPrefix)
- : m_dbPath(path), m_indexFilename(index), m_backupFilenameSuffix(backupSuffix),
- m_bucketFilenamePrefix(bucketPrefix) {
- }
+ Integrity(const std::string &path) : m_dbPath(path) {}
virtual ~Integrity() {};
virtual bool backupGuardExists(void) const;
@@ -60,9 +60,9 @@ protected:
private:
const std::string m_dbPath;
- const std::string m_indexFilename;
- const std::string m_backupFilenameSuffix;
- const std::string m_bucketFilenamePrefix;
+ static const std::string m_indexFilename;
+ static const std::string m_backupFilenameSuffix;
+ static const std::string m_bucketFilenamePrefix;
static const std::string m_guardFilename;
};
diff --git a/test/storage/inmemorystoragebackend/fakeinmemorystoragebackend.h b/test/storage/inmemorystoragebackend/fakeinmemorystoragebackend.h
index 52b4fe3..cb01dc2 100644
--- a/test/storage/inmemorystoragebackend/fakeinmemorystoragebackend.h
+++ b/test/storage/inmemorystoragebackend/fakeinmemorystoragebackend.h
@@ -30,6 +30,7 @@ class FakeInMemoryStorageBackend : public Cynara::InMemoryStorageBackend {
public:
using Cynara::InMemoryStorageBackend::InMemoryStorageBackend;
MOCK_METHOD0(buckets, Cynara::Buckets&(void));
+ MOCK_METHOD1(postLoadCleanup, void(bool isBackupValid));
};
diff --git a/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp b/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp
index a684b22..8e19743 100644
--- a/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp
+++ b/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp
@@ -195,9 +195,11 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicyFromNonexistentBucket) {
// Database dir is empty
TEST_F(InMemeoryStorageBackendFixture, load_no_db) {
using ::testing::ReturnRef;
+ using ::testing::Return;
auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/empty_db/";
FakeInMemoryStorageBackend backend(testDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
+ EXPECT_CALL(backend, postLoadCleanup(false)).WillOnce(Return());
backend.load();
ASSERT_DB_VIRGIN(m_buckets);
}
@@ -205,9 +207,11 @@ TEST_F(InMemeoryStorageBackendFixture, load_no_db) {
// Database dir contains index with default bucket, but no file for this bucket
TEST_F(InMemeoryStorageBackendFixture, load_no_default) {
using ::testing::ReturnRef;
+ using ::testing::Return;
auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db2/";
FakeInMemoryStorageBackend backend(testDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
+ EXPECT_CALL(backend, postLoadCleanup(false)).WillOnce(Return());
backend.load();
ASSERT_DB_VIRGIN(m_buckets);
}
@@ -215,9 +219,11 @@ TEST_F(InMemeoryStorageBackendFixture, load_no_default) {
// Database contains index with default bucket and an empty bucket file
TEST_F(InMemeoryStorageBackendFixture, load_default_only) {
using ::testing::ReturnRef;
+ using ::testing::Return;
auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db3/";
FakeInMemoryStorageBackend backend(testDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
+ EXPECT_CALL(backend, postLoadCleanup(false)).WillOnce(Return());
backend.load();
ASSERT_DB_VIRGIN(m_buckets);
}
@@ -226,12 +232,14 @@ TEST_F(InMemeoryStorageBackendFixture, load_default_only) {
// There are files for both buckets present
TEST_F(InMemeoryStorageBackendFixture, load_2_buckets) {
using ::testing::ReturnRef;
+ using ::testing::Return;
using ::testing::IsEmpty;
auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db4/";
FakeInMemoryStorageBackend backend(testDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
+ EXPECT_CALL(backend, postLoadCleanup(false)).WillOnce(Return());
backend.load();
std::vector bucketIds = { "", "additional" };
@@ -249,9 +257,11 @@ TEST_F(InMemeoryStorageBackendFixture, load_2_buckets) {
// Database contains index with 2 buckets; 1st bucket is valid, but second is corrupted
TEST_F(InMemeoryStorageBackendFixture, second_bucket_corrupted) {
using ::testing::ReturnRef;
+ using ::testing::Return;
auto testDbPath = std::string(CYNARA_TESTS_DIR) + "/db5/";
FakeInMemoryStorageBackend backend(testDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
+ EXPECT_CALL(backend, postLoadCleanup(false)).WillOnce(Return());
backend.load();
ASSERT_DB_VIRGIN(m_buckets);
}
@@ -265,6 +275,7 @@ TEST_F(InMemeoryStorageBackendFixture, second_bucket_corrupted) {
*/
TEST_F(InMemeoryStorageBackendFixture, load_from_backup) {
using ::testing::ReturnRef;
+ using ::testing::Return;
using ::testing::IsEmpty;
using ::testing::InSequence;
@@ -275,6 +286,7 @@ TEST_F(InMemeoryStorageBackendFixture, load_from_backup) {
// Calls are expected in a specific order
InSequence s;
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
+ EXPECT_CALL(backend, postLoadCleanup(true)).WillOnce(Return());
backend.load();
}
--
2.7.4
From 8bd144d36aa499e5bcfc472e4f5108fff9563df1 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Fri, 16 Jan 2015 15:38:05 +0100
Subject: [PATCH 05/16] Introduce ChecksumGenerator (chsgen)
A commandline-tool for computing checksums for Cynara's database
contents.
Change-Id: Iaddf799b84b82562734275991561ea0091852f2d
---
CMakeLists.txt | 1 +
packaging/cynara-db-chsgen.manifest | 5 ++
packaging/cynara.spec | 4 ++
src/CMakeLists.txt | 3 +-
src/chsgen/CMakeLists.txt | 38 ++++++++++++
src/chsgen/ChecksumGenerator.cpp | 119 ++++++++++++++++++++++++++++++++++++
src/chsgen/ChecksumGenerator.h | 57 +++++++++++++++++
src/chsgen/main.cpp | 43 +++++++++++++
8 files changed, 269 insertions(+), 1 deletion(-)
create mode 100644 packaging/cynara-db-chsgen.manifest
create mode 100644 src/chsgen/CMakeLists.txt
create mode 100644 src/chsgen/ChecksumGenerator.cpp
create mode 100644 src/chsgen/ChecksumGenerator.h
create mode 100644 src/chsgen/main.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b6db3e7..116c14f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -95,6 +95,7 @@ SET(TARGET_LIB_CREDS_SOCKET "cynara-creds-socket")
SET(TARGET_LIB_SESSION "cynara-session")
SET(TARGET_LIB_CYNARA_STORAGE "cynara-storage")
SET(TARGET_CYAD "cyad")
+SET(TARGET_CHSGEN "cynara-db-chsgen")
ADD_SUBDIRECTORY(src)
ADD_SUBDIRECTORY(pkgconfig)
diff --git a/packaging/cynara-db-chsgen.manifest b/packaging/cynara-db-chsgen.manifest
new file mode 100644
index 0000000..a76fdba
--- /dev/null
+++ b/packaging/cynara-db-chsgen.manifest
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/packaging/cynara.spec b/packaging/cynara.spec
index eea1b48..48d939a 100644
--- a/packaging/cynara.spec
+++ b/packaging/cynara.spec
@@ -18,6 +18,7 @@ Source1009: libcynara-creds-socket.manifest
Source1010: libcynara-session.manifest
Source1011: cynara-db-migration.manifest
Source1012: cyad.manifest
+Source1013: cynara-db-chsgen.manifest
Requires: default-ac-domains
Requires(pre): pwdutils
Requires(pre): cynara-db-migration >= %{version}-%{release}
@@ -171,6 +172,7 @@ cp -a %{SOURCE1009} .
cp -a %{SOURCE1010} .
cp -a %{SOURCE1011} .
cp -a %{SOURCE1012} .
+cp -a %{SOURCE1013} .
cp -a test/db/db* .
%build
@@ -385,7 +387,9 @@ fi
%files -n cynara-db-migration
%manifest cynara-db-migration.manifest
+%manifest cynara-db-chsgen.manifest
%attr(700,root,root) %{_sbindir}/cynara-db-migration
+%attr(700,root,root) %{_sbindir}/cynara-db-chsgen
%files -n cyad
%manifest cyad.manifest
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4bcf18c..1018e51 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@ ADD_SUBDIRECTORY(client)
ADD_SUBDIRECTORY(client-async)
ADD_SUBDIRECTORY(client-common)
ADD_SUBDIRECTORY(cyad)
+ADD_SUBDIRECTORY(chsgen)
ADD_SUBDIRECTORY(admin)
ADD_SUBDIRECTORY(agent)
ADD_SUBDIRECTORY(storage)
diff --git a/src/chsgen/CMakeLists.txt b/src/chsgen/CMakeLists.txt
new file mode 100644
index 0000000..748d950
--- /dev/null
+++ b/src/chsgen/CMakeLists.txt
@@ -0,0 +1,38 @@
+# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# @file CMakeLists.txt
+# @author Pawel Wieczorek
+#
+
+SET(CHSGEN_PATH ${CYNARA_PATH}/chsgen)
+
+SET(CHSGEN_SOURCES
+ ${CHSGEN_PATH}/ChecksumGenerator.cpp
+ ${CHSGEN_PATH}/main.cpp
+ )
+
+INCLUDE_DIRECTORIES(
+ ${CYNARA_PATH}
+ ${CYNARA_PATH}/include
+ )
+
+ADD_EXECUTABLE(${TARGET_CHSGEN} ${CHSGEN_SOURCES})
+
+TARGET_LINK_LIBRARIES(${TARGET_CHSGEN}
+ ${TARGET_CYNARA_COMMON}
+ crypt
+ )
+
+INSTALL(TARGETS ${TARGET_CHSGEN} DESTINATION ${SBIN_INSTALL_DIR})
diff --git a/src/chsgen/ChecksumGenerator.cpp b/src/chsgen/ChecksumGenerator.cpp
new file mode 100644
index 0000000..6255403
--- /dev/null
+++ b/src/chsgen/ChecksumGenerator.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file src/chsgen/ChecksumGenerator.cpp
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief A micro-tool for computing checksums for Cynara's database contents
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "ChecksumGenerator.h"
+
+namespace Cynara {
+
+namespace StorageConfig = PathConfig::StoragePath;
+
+const char ChecksumGenerator::m_fieldSeparator(StorageConfig::fieldSeparator);
+const char ChecksumGenerator::m_recordSeparator(StorageConfig::recordSeparator);
+const std::string ChecksumGenerator::m_backupFilenameSuffix(StorageConfig::backupFilenameSuffix);
+
+ChecksumGenerator::ChecksumGenerator(int argc, char * const *argv) : m_copyStream(std::string()) {
+ m_filename = (1 < argc ? argv[1] : std::string());
+}
+
+int ChecksumGenerator::run(void) {
+ try {
+ openFileStream();
+ copyFileStream();
+ printRecord();
+ return CYNARA_API_SUCCESS;
+ } catch (const FileNotFoundException &ex) {
+ std::cerr << ex.message() << std::endl;
+ return CYNARA_API_INVALID_COMMANDLINE_PARAM;
+ } catch (const UnexpectedErrorException &ex) {
+ std::cerr << ex.message() << std::endl;
+ return CYNARA_API_UNKNOWN_ERROR;
+ } catch (const std::ios_base::failure &ex) {
+ std::cerr << ex.what() << std::endl;
+ return CYNARA_API_UNKNOWN_ERROR;
+ } catch (const std::length_error &ex) {
+ std::cerr << ex.what() << std::endl;
+ return CYNARA_API_UNKNOWN_ERROR;
+ }
+}
+
+const std::string ChecksumGenerator::generate(const std::string &data) {
+ auto checksum = crypt(data.c_str(), "$1$");
+
+ if (nullptr != checksum) {
+ return std::string(checksum);
+ } else {
+ int err = errno;
+ if (err == ENOSYS) {
+ LOGE("'crypt' function was not implemented; error [%d] : <%s>", err, strerror(err));
+ } else {
+ LOGE("'crypt' function error [%d] : <%s>", err, strerror(err));
+ }
+ throw UnexpectedErrorException(err, strerror(err));
+ }
+};
+
+void ChecksumGenerator::openFileStream(void) {
+ m_inputStream.open(m_filename);
+
+ if (!m_inputStream.is_open()) {
+ throw FileNotFoundException(m_filename);
+ }
+}
+
+void ChecksumGenerator::copyFileStream(void) {
+ std::copy(std::istreambuf_iterator(m_inputStream),
+ std::istreambuf_iterator(),
+ std::ostreambuf_iterator(m_copyStream));
+ m_inputStream.seekg(0);
+}
+
+void ChecksumGenerator::printRecord(void) const {
+ std::string filename(basename(m_filename.c_str()));
+ getBasicFilename(filename);
+
+ std::cout << filename << m_fieldSeparator << generate(m_copyStream.str())
+ << m_recordSeparator;
+}
+
+void ChecksumGenerator::getBasicFilename(std::string &filename) const {
+ auto backupSuffixPos = filename.rfind(m_backupFilenameSuffix);
+
+ if (std::string::npos != backupSuffixPos &&
+ filename.size() == backupSuffixPos + m_backupFilenameSuffix.size()) {
+ filename.erase(backupSuffixPos);
+ }
+}
+
+} /* namespace Cynara */
diff --git a/src/chsgen/ChecksumGenerator.h b/src/chsgen/ChecksumGenerator.h
new file mode 100644
index 0000000..a3e96e0
--- /dev/null
+++ b/src/chsgen/ChecksumGenerator.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file src/chsgen/ChecksumGenerator.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief A micro-tool for computing checksums for Cynara's database contents
+ */
+
+#ifndef SRC_CHSGEN_CHECKSUMGENERATOR_H_
+#define SRC_CHSGEN_CHECKSUMGENERATOR_H_
+
+#include
+#include
+#include
+
+namespace Cynara {
+
+class ChecksumGenerator {
+public:
+ ChecksumGenerator(int argc, char * const *argv);
+ ~ChecksumGenerator() {}
+
+ int run(void);
+
+private:
+ static const std::string generate(const std::string &data);
+
+ void openFileStream(void);
+ void copyFileStream(void);
+ void printRecord(void) const;
+ void getBasicFilename(std::string &filename) const;
+
+ std::ifstream m_inputStream;
+ std::stringstream m_copyStream;
+ std::string m_filename;
+ static const char m_fieldSeparator;
+ static const char m_recordSeparator;
+ static const std::string m_backupFilenameSuffix;
+};
+
+} /* namespace Cynara */
+
+#endif /* SRC_CHSGEN_CHECKSUMGENERATOR_H_ */
diff --git a/src/chsgen/main.cpp b/src/chsgen/main.cpp
new file mode 100644
index 0000000..d91e889
--- /dev/null
+++ b/src/chsgen/main.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file src/chsgen/main.cpp
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief A micro-tool for computing checksums for Cynara's database contents
+ */
+
+#include
+#include
+
+#include
+
+#include
+
+int main(int argc, char **argv) {
+ if (2 != argc) {
+ std::cerr << "Invalid commandline parameters for chsgen" << std::endl;
+ return CYNARA_API_INVALID_COMMANDLINE_PARAM;
+ }
+
+ try {
+ Cynara::ChecksumGenerator chsgen(argc, argv);
+ return chsgen.run();
+ } catch (const std::bad_alloc &) {
+ std::cerr << "Chsgen could not allocate memory" << std::endl;
+ return CYNARA_API_OUT_OF_MEMORY;
+ }
+}
--
2.7.4
From baa776b7fb4066a2ee540d87ff8d76a6f443f7bc Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Wed, 18 Feb 2015 13:23:54 +0100
Subject: [PATCH 06/16] Add tests for ChecksumGenerator (chsgen)
This patch adds tests for calling "cynara-db-chsgen" executable.
Following call scenarios are checked:
* no filename,
* create checksum records for primary database contents,
* create checksum records for backup database contents.
Change-Id: I398f6865610598ab558b22a9cf3cdc620dc057b8
---
test/CMakeLists.txt | 6 +-
test/chsgen/ChsgenCommandlineTest.h | 31 +++++++++
test/chsgen/checksumgenerator.cpp | 121 ++++++++++++++++++++++++++++++++++++
3 files changed, 157 insertions(+), 1 deletion(-)
create mode 100644 test/chsgen/ChsgenCommandlineTest.h
create mode 100644 test/chsgen/checksumgenerator.cpp
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index fe62294..450993f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -49,6 +49,7 @@ SET(CYNARA_SOURCES_FOR_TESTS
${CYNARA_SRC}/common/types/PolicyDescription.cpp
${CYNARA_SRC}/common/types/PolicyResult.cpp
${CYNARA_SRC}/common/types/PolicyType.cpp
+ ${CYNARA_SRC}/chsgen/ChecksumGenerator.cpp
${CYNARA_SRC}/cyad/AdminPolicyParser.cpp
${CYNARA_SRC}/cyad/CommandlineParser/CmdlineErrors.cpp
${CYNARA_SRC}/cyad/CommandlineParser/CmdlineOpts.cpp
@@ -71,6 +72,7 @@ SET(CYNARA_SOURCES_FOR_TESTS
SET(CYNARA_TESTS_SOURCES
TestEventListenerProxy.cpp
+ chsgen/checksumgenerator.cpp
common/exceptions/bucketrecordcorrupted.cpp
common/protocols/admin/admincheckrequest.cpp
common/protocols/admin/admincheckresponse.cpp
@@ -121,6 +123,8 @@ ADD_EXECUTABLE(${TARGET_CYNARA_TESTS}
)
TARGET_LINK_LIBRARIES(${TARGET_CYNARA_TESTS}
- ${PKGS_LDFLAGS} ${PKGS_LIBRARIES}
+ ${PKGS_LDFLAGS}
+ ${PKGS_LIBRARIES}
+ crypt
)
INSTALL(TARGETS ${TARGET_CYNARA_TESTS} DESTINATION ${BIN_INSTALL_DIR})
diff --git a/test/chsgen/ChsgenCommandlineTest.h b/test/chsgen/ChsgenCommandlineTest.h
new file mode 100644
index 0000000..cbca399
--- /dev/null
+++ b/test/chsgen/ChsgenCommandlineTest.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file test/chsgen/ChsgenCommandlineTest.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Fixture for ChecksumGenerator tests
+ */
+
+#ifndef TEST_CHSGEN_CHSGENCOMMANDLINETEST_H_
+#define TEST_CHSGEN_CHSGENCOMMANDLINETEST_H_
+
+#include
+
+class ChsgenCommandlineTest : public QuietCommandlineTest {
+};
+
+#endif /* TEST_CHSGEN_CHSGENCOMMANDLINETEST_H_ */
diff --git a/test/chsgen/checksumgenerator.cpp b/test/chsgen/checksumgenerator.cpp
new file mode 100644
index 0000000..1d390d6
--- /dev/null
+++ b/test/chsgen/checksumgenerator.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file test/chsgen/checksumgenerator.cpp
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Tests of ChecksumGenerator
+ */
+
+#include
+
+#include
+
+#include
+
+#include
+
+#include "ChsgenCommandlineTest.h"
+
+namespace {
+
+const std::string execName("./cynara-db-chsgen");
+const std::string backupFilenameSuffix(Cynara::PathConfig::StoragePath::backupFilenameSuffix);
+const char fieldSeparator(Cynara::PathConfig::StoragePath::fieldSeparator);
+
+} // namespace
+
+/**
+ * @brief Verify if passing no filenames to checksum generator returns error message
+ * @test Expected result:
+ * - CYNARA_API_INVALID_COMMANDLINE_PARAM returned from checksum generator
+ * - empty output stream
+ * - message from caught exception in error stream
+ */
+TEST_F(ChsgenCommandlineTest, noFile) {
+ using ::testing::StartsWith;
+
+ std::string err;
+ std::string out;
+
+ clearOutput();
+ prepare_argv({ execName });
+
+ Cynara::ChecksumGenerator chsgen(this->argc(), this->argv());
+ const auto ret = chsgen.run();
+ getOutput(out, err);
+
+ ASSERT_EQ(CYNARA_API_INVALID_COMMANDLINE_PARAM, ret);
+ ASSERT_TRUE(out.empty());
+ ASSERT_THAT(err, StartsWith("File " + std::string() + " not found or corrupted badly"));
+}
+
+/**
+ * @brief Verify if checksum generator returns valid records
+ * @test Expected result:
+ * - CYNARA_API_SUCCESS returned from checksum generator
+ * - valid record in output stream
+ * - empty error stream
+ */
+TEST_F(ChsgenCommandlineTest, recordGeneration) {
+ using ::testing::StartsWith;
+
+ std::string err;
+ std::string out;
+
+ for (const std::string &file : { "_", "buckets" }) {
+ clearOutput();
+ prepare_argv({ execName, std::string(CYNARA_TESTS_DIR) + "/db3/" + file });
+ SCOPED_TRACE(file);
+
+ Cynara::ChecksumGenerator chsgen(this->argc(), this->argv());
+ const auto ret = chsgen.run();
+ getOutput(out, err);
+
+ ASSERT_EQ(CYNARA_API_SUCCESS, ret);
+ ASSERT_THAT(out, StartsWith(file + fieldSeparator + "$1$"));
+ ASSERT_TRUE(err.empty());
+ }
+}
+
+/**
+ * @brief Verify if checksum generator returns valid records for backup files
+ * @test Expected result:
+ * - CYNARA_API_SUCCESS returned from checksum generator
+ * - valid record in output stream
+ * - empty error stream
+ */
+TEST_F(ChsgenCommandlineTest, suffixErasing) {
+ using ::testing::StartsWith;
+
+ std::string err;
+ std::string out;
+
+ for (const std::string &file : { "_", "_additional", "buckets" }) {
+ clearOutput();
+ prepare_argv({ execName,
+ std::string(CYNARA_TESTS_DIR) + "/db6/" + file + backupFilenameSuffix });
+ SCOPED_TRACE(file);
+
+ Cynara::ChecksumGenerator chsgen(this->argc(), this->argv());
+ const auto ret = chsgen.run();
+ getOutput(out, err);
+
+ ASSERT_EQ(CYNARA_API_SUCCESS, ret);
+ ASSERT_THAT(out, StartsWith(file + fieldSeparator + "$1$"));
+ ASSERT_TRUE(err.empty());
+ }
+}
--
2.7.4
From 0cbbe1c7b7e7ffce65d5edc3dcca0c6055109cf0 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Wed, 11 Feb 2015 16:00:12 +0100
Subject: [PATCH 07/16] Refactorize migration tool
This refactoring run deals with:
* unintuitive naming,
* late input validation,
* passing only parts of input during option parsing,
* unconsistent comments.
Additionally, this patch:
* adds possiblity to install database in a custom directory,
* removes possibility of removing whole Cynara's state directory during
deinstallation - now only database is removed by migration tool.
Change-Id: I59e429d93812861ca9c32f201ed0056f753cbc25
---
migration/cynara-db-migration | 55 ++++++++++++++++++++++++++++---------------
1 file changed, 36 insertions(+), 19 deletions(-)
diff --git a/migration/cynara-db-migration b/migration/cynara-db-migration
index 5ab6409..46c6df0 100644
--- a/migration/cynara-db-migration
+++ b/migration/cynara-db-migration
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
STATE_PATH='/var/cynara'
DB_DIR='db'
INDEX_NAME='buckets'
-DEFAULT_NAME='_'
+DEFAULT_BUCKET_NAME='_'
DENY_POLICY=';0x0;'
##### Variables, with default values (optional)
@@ -40,22 +40,25 @@ NEW_VERSION=
##### Functions
parse_opts() {
- while getopts ":f:t:u:g:l:" opt; do
+ while getopts ":f:t:p:u:g:l:" opt; do
case $opt in
f )
- OLD_VERSION=${OPTARG}
+ OLD_VERSION="${OPTARG}"
;;
t )
- NEW_VERSION=${OPTARG}
+ NEW_VERSION="${OPTARG}"
+ ;;
+ p )
+ STATE_PATH="${OPTARG}"
;;
u )
- CYNARA_USER=${OPTARG}
+ CYNARA_USER="${OPTARG}"
;;
g )
- CYNARA_GROUP=${OPTARG}
+ CYNARA_GROUP="${OPTARG}"
;;
l )
- SMACK_LABEL=${OPTARG}
+ SMACK_LABEL="${OPTARG}"
;;
\? )
echo "Invalid option: -$OPTARG" >&2
@@ -69,17 +72,13 @@ parse_opts() {
done
}
-create_db() {
- if [ -z ${NEW_VERSION} ]; then
- failure
- fi
-
- # Create Cynara's database directory:
+minimal_db() {
+ # Create Cynara's database directory
mkdir -p ${STATE_PATH}/${DB_DIR}
# Create contents of minimal database: first index file, then default bucket
echo ${DENY_POLICY} > ${STATE_PATH}/${DB_DIR}/${INDEX_NAME}
- touch ${STATE_PATH}/${DB_DIR}/${DEFAULT_NAME}
+ touch ${STATE_PATH}/${DB_DIR}/${DEFAULT_BUCKET_NAME}
# Set proper permissions for newly created database
chown -R ${CYNARA_USER}:${CYNARA_GROUP} ${STATE_PATH}/${DB_DIR}
@@ -89,6 +88,14 @@ create_db() {
chsmack -a ${SMACK_LABEL} ${STATE_PATH}/${DB_DIR}/*
}
+install_db() {
+ if [ -z ${NEW_VERSION} ] ; then
+ failure
+ fi
+
+ minimal_db
+}
+
migrate_db() {
if [ -z ${OLD_VERSION} -o -z ${NEW_VERSION} ]; then
failure
@@ -96,7 +103,8 @@ migrate_db() {
# Create minimal database if there was none:
if [ ! -d "${STATE_PATH}/${DB_DIR}" ]; then
- create_db
+ install_db
+ exit_success
fi
}
@@ -105,7 +113,7 @@ remove_db() {
failure
fi
- rm -rf ${STATE_PATH}
+ rm -rf "${STATE_PATH}/${DB_DIR}"
}
usage() {
@@ -115,13 +123,14 @@ Usage: $0 COMMAND OPTIONS
This script installs, migrates to another version or removes Cynara's policies database
Commands:
- upgrade (up) migrate old data to new version of database structure
+ upgrade (up) migrate data to different version of database
install (in) create minimal database
uninstall (rm) remove database entirely
Options:
-f from Set old version of database (mandatory for upgrade and uninstall)
-t to Set new version of database (mandatory for upgrade and install)
+ -p path Set path for storing database (default: /var/cynara)
-u user Set database owner (default: cynara)
-g group Set database group (default: cynara)
-l label Set SMACK label for database (default: System)
@@ -131,9 +140,17 @@ EOF
failure() {
usage
+ exit_failure
+}
+
+exit_failure() {
exit 1
}
+exit_success() {
+ exit 0
+}
+
##### Main
if [ 0 -eq $# ]; then
@@ -149,7 +166,7 @@ case $1 in
"in" | "install" )
shift $OPTIND
parse_opts "$@"
- create_db
+ install_db
;;
"rm" | "uninstall" )
shift $OPTIND
--
2.7.4
From 3cdfeec14c8db2a11721aa7b71c2d689289c390a Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Mon, 9 Feb 2015 15:37:57 +0100
Subject: [PATCH 08/16] Add comparator for Semantic Versioning
Change-Id: I73b273465995b6246d20179395bdff1b4d1941f2
---
migration/cynara-db-migration | 46 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/migration/cynara-db-migration b/migration/cynara-db-migration
index 46c6df0..645d831 100644
--- a/migration/cynara-db-migration
+++ b/migration/cynara-db-migration
@@ -27,6 +27,11 @@ INDEX_NAME='buckets'
DEFAULT_BUCKET_NAME='_'
DENY_POLICY=';0x0;'
+# Return values for comparison
+LESS=-1
+EQUAL=0
+GREATER=1
+
##### Variables, with default values (optional)
CYNARA_USER='cynara'
@@ -39,6 +44,47 @@ NEW_VERSION=
##### Functions
+version_compare() {
+ local MAJOR1=
+ local MAJOR2=
+ local MINOR1=
+ local MINOR2=
+ local PATCH1=
+ local PATCH2=
+
+ # Parse
+ i=1
+ while [ 2 -ge $i ] ; do
+ eval "ARG=\$$i"
+ eval "MAJOR$i=${ARG%%.*}"
+ eval "TMP=${ARG#*.}"
+ eval "MINOR$i=${TMP%%.*}"
+ eval "PATCH$i=${ARG##*.}"
+ i=$(($i+1))
+ done
+
+ # Compare
+ if [ $MAJOR1 -lt $MAJOR2 ] ; then
+ echo "$LESS"
+ elif [ $MAJOR1 -eq $MAJOR2 ] ; then
+ if [ $MINOR1 -lt $MINOR2 ] ; then
+ echo "$LESS"
+ elif [ $MINOR1 -eq $MINOR2 ] ; then
+ if [ $PATCH1 -lt $PATCH2 ] ; then
+ echo "$LESS"
+ elif [ $PATCH1 -eq $PATCH2 ] ; then
+ echo "$EQUAL"
+ else
+ echo "$GREATER"
+ fi
+ else
+ echo "$GREATER"
+ fi
+ else
+ echo "$GREATER"
+ fi
+}
+
parse_opts() {
while getopts ":f:t:p:u:g:l:" opt; do
case $opt in
--
2.7.4
From 0bb80318f3edc278902bc5ff54c497ac1882be57 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Fri, 16 Jan 2015 11:16:56 +0100
Subject: [PATCH 09/16] Add support for checksums to migration tool
This patch also adds downgrade option to the migration tool.
Change-Id: If6a443172d52a78e8bfbf732e7eca38cb37f886f
---
migration/cynara-db-migration | 70 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/migration/cynara-db-migration b/migration/cynara-db-migration
index 645d831..d31897c 100644
--- a/migration/cynara-db-migration
+++ b/migration/cynara-db-migration
@@ -25,6 +25,8 @@ STATE_PATH='/var/cynara'
DB_DIR='db'
INDEX_NAME='buckets'
DEFAULT_BUCKET_NAME='_'
+CHECKSUM_NAME='checksum'
+GUARD_NAME='guard'
DENY_POLICY=';0x0;'
# Return values for comparison
@@ -32,6 +34,9 @@ LESS=-1
EQUAL=0
GREATER=1
+# Cynara version which introduced checksums
+CHS_INTRO_VERSION='0.6.0'
+
##### Variables, with default values (optional)
CYNARA_USER='cynara'
@@ -118,6 +123,41 @@ parse_opts() {
done
}
+generate_checksums() {
+ # Output file
+ CHECKSUMS="${STATE_PATH}/${DB_DIR}/${CHECKSUM_NAME}"
+ GUARD="${STATE_PATH}/${DB_DIR}/${GUARD_NAME}"
+ WILDCARD="*"
+
+ # Check if checksums should be generated from backup
+ if [ -e $GUARD ] ; then
+ WILDCARD="${WILDCARD}~"
+
+ # Database will be read from backup at next load
+ CHECKSUMS="${CHECKSUMS}~"
+ fi
+
+ # Mimic opening in truncate mode
+ echo -n "" > "${CHECKSUMS}"
+
+ # Actual checksums generation
+ for FILE in $(find ${STATE_PATH}/${DB_DIR}/${WILDCARD} -type f ! -name "${CHECKSUM_NAME}*" \
+ ! -name "${GUARD_NAME}"); do
+ CHECKSUM="$(/usr/sbin/cynara-db-chsgen ${FILE})"
+ if [ 0 -eq $? ] ; then
+ echo "${CHECKSUM}" >> ${CHECKSUMS}
+ else
+ exit_failure
+ fi
+ done
+
+ # Set proper permissions for newly created checksum file
+ chown -R ${CYNARA_USER}:${CYNARA_GROUP} ${CHECKSUMS}
+
+ # Set proper SMACK label for newly created checksum file
+ chsmack -a ${SMACK_LABEL} ${CHECKSUMS}
+}
+
minimal_db() {
# Create Cynara's database directory
mkdir -p ${STATE_PATH}/${DB_DIR}
@@ -134,12 +174,27 @@ minimal_db() {
chsmack -a ${SMACK_LABEL} ${STATE_PATH}/${DB_DIR}/*
}
+upgrade_db() {
+ # Add or update checksum file if necessary
+ if [ 0 -ge $(version_compare ${CHS_INTRO_VERSION} ${NEW_VERSION}) ] ; then
+ generate_checksums
+ fi
+}
+
+downgrade_db() {
+ # Remove checksum file if necessary
+ if [ 0 -lt $(version_compare ${CHS_INTRO_VERSION} ${NEW_VERSION}) ] ; then
+ rm "${STATE_PATH}/${DB_DIR}/${CHECKSUM_NAME}" > /dev/null 2>&1
+ fi
+}
+
install_db() {
if [ -z ${NEW_VERSION} ] ; then
failure
fi
minimal_db
+ upgrade_db
}
migrate_db() {
@@ -152,6 +207,21 @@ migrate_db() {
install_db
exit_success
fi
+
+ case $(version_compare ${OLD_VERSION} ${NEW_VERSION}) in
+ -1 )
+ upgrade_db
+ ;;
+ 0 )
+ :
+ # Same version given twice; take no action
+ ;;
+ 1 )
+ downgrade_db
+ ;;
+ * )
+ failure
+ esac
}
remove_db() {
--
2.7.4
From df2737b7eb40da782e0e1394284866331d54fe6a Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Tue, 24 Feb 2015 15:58:42 +0100
Subject: [PATCH 10/16] Add tests for migration tool
Change-Id: I2bdd88cd07646896b75ea36e7776b7fa1a449bd8
---
packaging/cynara.spec | 1 +
test/CMakeLists.txt | 4 +
test/db/db10_postchs_bcp/_~ | 0
test/db/db10_postchs_bcp/buckets~ | 1 +
test/db/db10_postchs_bcp/checksum~ | 2 +
test/db/db10_postchs_bcp/guard | 0
test/db/db7_prechs/_ | 0
test/db/db7_prechs/buckets | 1 +
test/db/db8_postchs/_ | 0
test/db/db8_postchs/buckets | 1 +
test/db/db8_postchs/checksum | 2 +
test/db/db9_prechs_bcp/_~ | 0
test/db/db9_prechs_bcp/buckets~ | 1 +
test/db/db9_prechs_bcp/guard | 0
test/tools/cynara-db-migration-tests | 218 +++++++++++++++++++++++++++++++++++
15 files changed, 231 insertions(+)
create mode 100644 test/db/db10_postchs_bcp/_~
create mode 100644 test/db/db10_postchs_bcp/buckets~
create mode 100644 test/db/db10_postchs_bcp/checksum~
create mode 100644 test/db/db10_postchs_bcp/guard
create mode 100644 test/db/db7_prechs/_
create mode 100644 test/db/db7_prechs/buckets
create mode 100644 test/db/db8_postchs/_
create mode 100644 test/db/db8_postchs/buckets
create mode 100644 test/db/db8_postchs/checksum
create mode 100644 test/db/db9_prechs_bcp/_~
create mode 100644 test/db/db9_prechs_bcp/buckets~
create mode 100644 test/db/db9_prechs_bcp/guard
create mode 100644 test/tools/cynara-db-migration-tests
diff --git a/packaging/cynara.spec b/packaging/cynara.spec
index 48d939a..3289855 100644
--- a/packaging/cynara.spec
+++ b/packaging/cynara.spec
@@ -337,6 +337,7 @@ fi
%files -n cynara-tests
%manifest cynara-tests.manifest
%attr(755,root,root) /usr/bin/cynara-tests
+%attr(755,root,root) /usr/bin/cynara-db-migration-tests
%attr(755,root,root) %{tests_dir}/db*/*
%dir %attr(755,root,root) %{tests_dir}/empty_db
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 450993f..d937d3c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -107,6 +107,8 @@ SET(CYNARA_TESTS_SOURCES
types/policykey.cpp
)
+SET(CYNARA_MIGRATION_TOOL_TESTS tools/cynara-db-migration-tests)
+
INCLUDE_DIRECTORIES(
${PKGS_INCLUDE_DIRS}
${CYNARA_SRC}/common
@@ -128,3 +130,5 @@ TARGET_LINK_LIBRARIES(${TARGET_CYNARA_TESTS}
crypt
)
INSTALL(TARGETS ${TARGET_CYNARA_TESTS} DESTINATION ${BIN_INSTALL_DIR})
+
+INSTALL(FILES ${CYNARA_MIGRATION_TOOL_TESTS} DESTINATION ${BIN_INSTALL_DIR})
diff --git a/test/db/db10_postchs_bcp/_~ b/test/db/db10_postchs_bcp/_~
new file mode 100644
index 0000000..e69de29
diff --git a/test/db/db10_postchs_bcp/buckets~ b/test/db/db10_postchs_bcp/buckets~
new file mode 100644
index 0000000..29ab987
--- /dev/null
+++ b/test/db/db10_postchs_bcp/buckets~
@@ -0,0 +1 @@
+;0x0;
diff --git a/test/db/db10_postchs_bcp/checksum~ b/test/db/db10_postchs_bcp/checksum~
new file mode 100644
index 0000000..63b55e0
--- /dev/null
+++ b/test/db/db10_postchs_bcp/checksum~
@@ -0,0 +1,2 @@
+_;$1$$qRPK7m23GJusamGpoGLby/
+buckets;$1$$6ZlVs5lw2nZgVmiw0BdY21
diff --git a/test/db/db10_postchs_bcp/guard b/test/db/db10_postchs_bcp/guard
new file mode 100644
index 0000000..e69de29
diff --git a/test/db/db7_prechs/_ b/test/db/db7_prechs/_
new file mode 100644
index 0000000..e69de29
diff --git a/test/db/db7_prechs/buckets b/test/db/db7_prechs/buckets
new file mode 100644
index 0000000..29ab987
--- /dev/null
+++ b/test/db/db7_prechs/buckets
@@ -0,0 +1 @@
+;0x0;
diff --git a/test/db/db8_postchs/_ b/test/db/db8_postchs/_
new file mode 100644
index 0000000..e69de29
diff --git a/test/db/db8_postchs/buckets b/test/db/db8_postchs/buckets
new file mode 100644
index 0000000..29ab987
--- /dev/null
+++ b/test/db/db8_postchs/buckets
@@ -0,0 +1 @@
+;0x0;
diff --git a/test/db/db8_postchs/checksum b/test/db/db8_postchs/checksum
new file mode 100644
index 0000000..63b55e0
--- /dev/null
+++ b/test/db/db8_postchs/checksum
@@ -0,0 +1,2 @@
+_;$1$$qRPK7m23GJusamGpoGLby/
+buckets;$1$$6ZlVs5lw2nZgVmiw0BdY21
diff --git a/test/db/db9_prechs_bcp/_~ b/test/db/db9_prechs_bcp/_~
new file mode 100644
index 0000000..e69de29
diff --git a/test/db/db9_prechs_bcp/buckets~ b/test/db/db9_prechs_bcp/buckets~
new file mode 100644
index 0000000..29ab987
--- /dev/null
+++ b/test/db/db9_prechs_bcp/buckets~
@@ -0,0 +1 @@
+;0x0;
diff --git a/test/db/db9_prechs_bcp/guard b/test/db/db9_prechs_bcp/guard
new file mode 100644
index 0000000..e69de29
diff --git a/test/tools/cynara-db-migration-tests b/test/tools/cynara-db-migration-tests
new file mode 100644
index 0000000..c6ea3d8
--- /dev/null
+++ b/test/tools/cynara-db-migration-tests
@@ -0,0 +1,218 @@
+#!/bin/sh
+#
+# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,`
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# @file test/tools/cynara-db-migration-tests
+# @author Pawel Wieczorek
+# @brief Tests of migration tool for Cynara's database
+#
+
+##### Constants (these must not be modified by shell)
+
+# Paths
+TESTS_DIR='/tmp/cynara-db-migration-tests'
+PATTERNS_DIR='/usr/share/cynara/tests'
+MIGRATE='/usr/sbin/cynara-db-migration'
+
+# Names
+DB_DIR='db'
+LOG_FILE='output.log'
+FAIL_FILE='fail.log'
+
+# Various Cynara versions
+CHS_INTRO_VERSION='0.6.0'
+PRECHS_HIGH_VERSION='0.4.2'
+PRECHS_LOW_VERSION='0.2.4'
+POSTCHS_HIGH_VERSION='4.2.0'
+POSTCHS_LOW_VERSION='2.4.0'
+
+# Messages
+MIGRATE_FAIL_MSG="$MIGRATE failed."
+COMPARE_FAIL_MSG="Mismatch in file"
+DB_STILL_EXISTS_MSG="Database directory still exists."
+
+# Status indicators
+SUCCESS=0
+FAILURE=1
+
+##### Variables, with default values (optional)
+
+TEST_CASE=0
+
+##### Functions
+
+fail_msg() {
+ local ID="$1"
+ local NAME="$2"
+ echo "Test $ID ($NAME) failed:"
+ cat "${TESTS_DIR}/${ID}/${FAIL_FILE}"
+}
+
+success_msg() {
+ local ID="$1"
+ local NAME="$2"
+ echo "Test $ID ($NAME) passed."
+}
+
+execute() {
+ ${MIGRATE} $1
+ echo $?
+}
+
+run() {
+ # Iterate test case ID
+ TEST_CASE=$(($TEST_CASE+1))
+
+ # Prepare environment
+ local ID=$TEST_CASE
+ local INITIAL="$1"
+ local PATTERN="$2"
+ local NAME="$3"
+ local STATE_PATH="${TESTS_DIR}/${ID}"
+
+ mkdir -p "$STATE_PATH"
+ if [ 'empty' != "$INITIAL" ] ; then
+ cp -a "${PATTERNS_DIR}/${INITIAL}" "${STATE_PATH}/${DB_DIR}"
+ fi
+
+ # Prepare error handling
+ local RUN_SUCCESS=$SUCCESS
+ local FAIL_REASON="${STATE_PATH}/${FAIL_FILE}"
+ echo -n "" > "$FAIL_REASON"
+
+ # Run command
+ local ARG="$4 -p $STATE_PATH"
+ local RET=$(execute "$ARG")
+
+ # Check results
+ if [ $SUCCESS -ne $RET ] ; then
+ # Migration tool failure
+ echo "$MIGRATE_FAIL_MSG" > "$FAIL_REASON"
+ else
+ # Clear logfile
+ local LOG="${STATE_PATH}/${LOG_FILE}"
+ echo -n "" > "$LOG"
+
+ if [ 'empty' = "$PATTERN" ] ; then
+ # No pattern - check if database directory was removed
+ if [ -d "${STATE_PATH}/${DB_DIR}" ] ; then
+ RUN_SUCCESS=$FAILURE
+ echo "" >> "$FAIL_REASON"
+ echo "$DB_STILL_EXISTS_MSG" >> "$FAIL_REASON"
+ fi
+ else
+ # Pattern given - compare it to generated database
+ for FILE in ${PATTERNS_DIR}/${PATTERN}/* ; do
+ diff ${FILE} ${STATE_PATH}/${DB_DIR}/${FILE##*\/} > "$LOG" 2>&1
+ if [ $SUCCESS -ne $? ] ; then
+ RUN_SUCCESS=$FAILURE
+ # Append comparison result to fail log
+ echo "" >> "$FAIL_REASON"
+ echo "${COMPARE_FAIL_MSG}: ${FILE##*\/}" >> "$FAIL_REASON"
+ cat "$LOG" >> "$FAIL_REASON"
+ fi
+ done
+ fi
+ fi
+
+ # Return results
+ if [ $SUCCESS -eq $RUN_SUCCESS ] ; then
+ success_msg "$ID" "$NAME"
+ else
+ fail_msg "$ID" "$NAME"
+ fi
+
+ # Clean up environment
+ rm -r "$STATE_PATH"
+}
+
+##### Main
+
+# How to add new test cases:
+#
+# run INITIAL_DB PATTERN_DB TEST_CASE_NAME MIGRATION_ARGS
+#
+# checking if database was removed: pass 'empty' as PATTERN_DB
+
+### Set up tests environment
+mkdir -p "$TESTS_DIR"
+
+# Test case 01: install minimal pre-checksum database
+run empty db7_prechs "inst_min_prechs" "install -t $PRECHS_LOW_VERSION"
+
+# Test case 02: install minimal post-checksum database
+run empty db8_postchs "inst_min_postchs" "install -t $POSTCHS_LOW_VERSION"
+
+# Test case 03: upgrade from pre-checksum to pre-checksum
+run db7_prechs db7_prechs "up_prechs_prechs" \
+ "upgrade -f $PRECHS_LOW_VERSION -t $PRECHS_HIGH_VERSION"
+
+# Test case 04: upgrade from pre-checksum to post-checksum
+run db7_prechs db8_postchs "up_prechs_postchs" \
+ "upgrade -f $PRECHS_LOW_VERSION -t $POSTCHS_HIGH_VERSION"
+
+# Test case 05: upgrade from post-checksum to post-checksum
+run db8_postchs db8_postchs "up_postchs_postchs" \
+ "upgrade -f $POSTCHS_LOW_VERSION -t $POSTCHS_HIGH_VERSION"
+
+# Test case 06: downgrade from pre-checksum to pre-checksum
+run db7_prechs db7_prechs "down_prechs_prechs" \
+ "upgrade -f $PRECHS_HIGH_VERSION -t $PRECHS_LOW_VERSION"
+
+# Test case 07: downgrade from post-checksum to pre-checksum
+run db8_postchs db7_prechs "down_postchs_prechs" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $PRECHS_LOW_VERSION"
+
+# Test case 08: downgrade from post-checksum to post-checksum
+run db8_postchs db8_postchs "down_postchs_postchs" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $POSTCHS_LOW_VERSION"
+
+# Test case 09: migrate to the same database version
+run db8_postchs db8_postchs "migr_same_ver" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $POSTCHS_HIGH_VERSION"
+
+# Test case 10: uninstall database
+run db7_prechs empty "uninst_db" "uninstall -f $PRECHS_LOW_VERSION"
+
+# Test case 11: upgrade from pre-checksum to pre-checksum (backups)
+run db9_prechs_bcp db9_prechs_bcp "up_prechs_prechs_bcp" \
+ "upgrade -f $PRECHS_LOW_VERSION -t $PRECHS_HIGH_VERSION"
+
+# Test case 12: upgrade from pre-checksum to post-checksum (backups)
+run db9_prechs_bcp db10_postchs_bcp "up_prechs_postchs_bcp" \
+ "upgrade -f $PRECHS_LOW_VERSION -t $POSTCHS_HIGH_VERSION"
+
+# Test case 13: upgrade from post-checksum to post-checksum (backups)
+run db10_postchs_bcp db10_postchs_bcp "up_postchs_postchs_bcp" \
+ "upgrade -f $POSTCHS_LOW_VERSION -t $POSTCHS_HIGH_VERSION"
+
+# Test case 14: downgrade from backup pre-checksum to pre-checksum (backups)
+run db9_prechs_bcp db9_prechs_bcp "down_prechs_prechs_bcp" \
+ "upgrade -f $PRECHS_HIGH_VERSION -t $PRECHS_LOW_VERSION"
+
+# Test case 15: downgrade from backup post-checksum to pre-checksum (backups)
+run db10_postchs_bcp db9_prechs_bcp "down_postchs_prechs_bcp" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $PRECHS_LOW_VERSION"
+
+# Test case 16: downgrade from backup post-checksum to post-checksum (backups)
+run db10_postchs_bcp db10_postchs_bcp "down_postchs_postchs_bcp" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $POSTCHS_LOW_VERSION"
+
+# Test case 17: migrate to the same database version (backups)
+run db10_postchs_bcp db10_postchs_bcp "migr_same_ver_bcp" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $POSTCHS_HIGH_VERSION"
+
+### Clean up tests environment
+rm -r "$TESTS_DIR"
--
2.7.4
From 2f2d8f10c0b96524c6380b18a89845016632a53b Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Fri, 5 Dec 2014 15:26:24 +0100
Subject: [PATCH 11/16] Extend ignored files list in integrity mechanism
Integrity mechanism will not remove file containing checksums even
though it is not listed in database index.
Change-Id: I1e587ecdad5abff47d78362394cc0ecdb1ecd4c4
---
src/storage/Integrity.cpp | 14 +++++++++++---
src/storage/Integrity.h | 3 +++
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/storage/Integrity.cpp b/src/storage/Integrity.cpp
index 82e8f5a..5dfa624 100644
--- a/src/storage/Integrity.cpp
+++ b/src/storage/Integrity.cpp
@@ -109,9 +109,8 @@ void Integrity::deleteNonIndexedFiles(BucketPresenceTester tester) {
while (errno = 0, (direntPtr = readdir(dirPtr)) != nullptr) {
std::string filename = direntPtr->d_name;
- //ignore all special files (working dir, parent dir, index)
- if ("." == filename || ".." == filename ||
- PathConfig::StoragePath::indexFilename == filename) {
+ //ignore all special files (working dir, parent dir, index, checksums)
+ if (isSpecialDirectory(filename) || isSpecialDatabaseEntry(filename)) {
continue;
}
@@ -236,4 +235,13 @@ void Integrity::deleteHardLink(const std::string &filename) {
}
}
+bool Integrity::isSpecialDirectory(const std::string &filename) {
+ return "." == filename || ".." == filename;
+}
+
+bool Integrity::isSpecialDatabaseEntry(const std::string &filename) {
+ return PathConfig::StoragePath::indexFilename == filename ||
+ PathConfig::StoragePath::checksumFilename == filename;
+}
+
} /* namespace Cynara */
diff --git a/src/storage/Integrity.h b/src/storage/Integrity.h
index d06eada..2917fb3 100644
--- a/src/storage/Integrity.h
+++ b/src/storage/Integrity.h
@@ -58,6 +58,9 @@ protected:
static void createHardLink(const std::string &oldName, const std::string &newName);
static void deleteHardLink(const std::string &filename);
+ static bool isSpecialDirectory(const std::string &filename);
+ static bool isSpecialDatabaseEntry(const std::string &filename);
+
private:
const std::string m_dbPath;
static const std::string m_indexFilename;
--
2.7.4
From 501306b6a09f74a644e620ebcdef42a3cbc3c10b Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Fri, 27 Feb 2015 10:50:52 +0100
Subject: [PATCH 12/16] Remove unwanted pointers (InMemoryStorageBackend)
Using pointers to helper classes (Integrity and, in future,
ChecksumValidator) is unnecessary and undesired. However, this forces
removal of InMemoryStorageBackend default constructor, as it cannot
initialize its helpers with valid arguments.
This patch also adjusts tests to the new constructor set and removes no
longer used typedef.
Change-Id: If0a41a75c16be6d55bdf3841ddb5190c388968af
---
src/storage/InMemoryStorageBackend.cpp | 16 +++++------
src/storage/InMemoryStorageBackend.h | 6 ++---
src/storage/Integrity.h | 3 ---
test/storage/inmemorystoragebackend/buckets.cpp | 14 +++++-----
.../inmemeorystoragebackendfixture.h | 3 ++-
.../inmemorystoragebackend.cpp | 31 +++++++++++-----------
test/storage/inmemorystoragebackend/search.cpp | 4 +--
7 files changed, 38 insertions(+), 39 deletions(-)
diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp
index 45b7874..a5e08b1 100644
--- a/src/storage/InMemoryStorageBackend.cpp
+++ b/src/storage/InMemoryStorageBackend.cpp
@@ -57,12 +57,12 @@ const std::string InMemoryStorageBackend::m_backupFilenameSuffix(
const std::string InMemoryStorageBackend::m_bucketFilenamePrefix(
PathConfig::StoragePath::bucketFilenamePrefix);
-InMemoryStorageBackend::InMemoryStorageBackend(const std::string &path) : m_dbPath(path) {
- m_integrity.reset(new Integrity(path));
+InMemoryStorageBackend::InMemoryStorageBackend(const std::string &path) : m_dbPath(path),
+ m_integrity(path) {
}
void InMemoryStorageBackend::load(void) {
- bool isBackupValid = m_integrity->backupGuardExists();
+ bool isBackupValid = m_integrity.backupGuardExists();
std::string bucketSuffix = "";
std::string indexFilename = m_dbPath + m_indexFilename;
@@ -104,9 +104,9 @@ void InMemoryStorageBackend::save(void) {
storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
this, std::placeholders::_1));
- m_integrity->syncDatabase(buckets(), true);
- m_integrity->createBackupGuard();
- m_integrity->revalidatePrimaryDatabase(buckets());
+ m_integrity.syncDatabase(buckets(), true);
+ m_integrity.createBackupGuard();
+ m_integrity.revalidatePrimaryDatabase(buckets());
//guard is removed during revalidation
}
@@ -265,10 +265,10 @@ std::shared_ptr InMemoryStorageBackend::bucketDumpStreamOpene
void InMemoryStorageBackend::postLoadCleanup(bool isBackupValid) {
if (isBackupValid) {
- m_integrity->revalidatePrimaryDatabase(buckets());
+ m_integrity.revalidatePrimaryDatabase(buckets());
}
//in case there were unnecessary files in db directory
- m_integrity->deleteNonIndexedFiles(std::bind(&InMemoryStorageBackend::hasBucket, this,
+ m_integrity.deleteNonIndexedFiles(std::bind(&InMemoryStorageBackend::hasBucket, this,
std::placeholders::_1));
}
diff --git a/src/storage/InMemoryStorageBackend.h b/src/storage/InMemoryStorageBackend.h
index 723c61d..c9e63c2 100644
--- a/src/storage/InMemoryStorageBackend.h
+++ b/src/storage/InMemoryStorageBackend.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@ namespace Cynara {
class InMemoryStorageBackend : public StorageBackend {
public:
+ InMemoryStorageBackend() = delete;
InMemoryStorageBackend(const std::string &path);
virtual ~InMemoryStorageBackend() {};
@@ -64,7 +65,6 @@ public:
const PolicyKey &filter);
protected:
- InMemoryStorageBackend() {}
void openFileStream(std::shared_ptr stream, const std::string &filename);
std::shared_ptr bucketStreamOpener(const PolicyBucketId &bucketId,
const std::string &fileNameSuffix);
@@ -78,7 +78,7 @@ protected:
private:
std::string m_dbPath;
Buckets m_buckets;
- IntegrityUniquePtr m_integrity;
+ Integrity m_integrity;
static const std::string m_indexFilename;
static const std::string m_backupFilenameSuffix;
static const std::string m_bucketFilenamePrefix;
diff --git a/src/storage/Integrity.h b/src/storage/Integrity.h
index 2917fb3..569ca85 100644
--- a/src/storage/Integrity.h
+++ b/src/storage/Integrity.h
@@ -31,9 +31,6 @@
namespace Cynara {
-class Integrity;
-typedef std::unique_ptr IntegrityUniquePtr;
-
class Integrity
{
public:
diff --git a/test/storage/inmemorystoragebackend/buckets.cpp b/test/storage/inmemorystoragebackend/buckets.cpp
index f53b51c..d201d69 100644
--- a/test/storage/inmemorystoragebackend/buckets.cpp
+++ b/test/storage/inmemorystoragebackend/buckets.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ TEST_F(InMemeoryStorageBackendFixture, createBucket) {
using ::testing::ReturnRef;
using ::testing::IsEmpty;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -53,7 +53,7 @@ TEST_F(InMemeoryStorageBackendFixture, createBucket) {
TEST_F(InMemeoryStorageBackendFixture, updateBucket) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -69,7 +69,7 @@ TEST_F(InMemeoryStorageBackendFixture, updateBucket) {
TEST_F(InMemeoryStorageBackendFixture, updateNonexistentBucket) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -81,7 +81,7 @@ TEST_F(InMemeoryStorageBackendFixture, deleteBucket) {
using ::testing::ReturnRef;
using ::testing::IsEmpty;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -97,7 +97,7 @@ TEST_F(InMemeoryStorageBackendFixture, hasBucket) {
using ::testing::ReturnRef;
using ::testing::IsEmpty;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -111,7 +111,7 @@ TEST_F(InMemeoryStorageBackendFixture, hasBucket) {
TEST_F(InMemeoryStorageBackendFixture, deleteNonexistentBucket) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
diff --git a/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h b/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h
index b671a0d..fbc523b 100644
--- a/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h
+++ b/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -147,6 +147,7 @@ protected:
Cynara::Buckets m_buckets;
static const std::string m_indexFileName;
static const std::string m_backupFileNameSuffix;
+ static const std::string m_fakeDbPath;
//erase helper structures
Cynara::PolicyCollection m_fullPolicyCollection;
diff --git a/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp b/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp
index 8e19743..1c88335 100644
--- a/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp
+++ b/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,13 +40,14 @@
using namespace Cynara;
-const std::string InMemeoryStorageBackendFixture::m_indexFileName = "buckets";
-const std::string InMemeoryStorageBackendFixture::m_backupFileNameSuffix = "~";
+const std::string InMemeoryStorageBackendFixture::m_indexFileName("buckets");
+const std::string InMemeoryStorageBackendFixture::m_backupFileNameSuffix("~");
+const std::string InMemeoryStorageBackendFixture::m_fakeDbPath("/fake/database/path");
TEST_F(InMemeoryStorageBackendFixture, defaultPolicyIsDeny) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillOnce(ReturnRef(m_buckets));
@@ -65,7 +66,7 @@ TEST_F(InMemeoryStorageBackendFixture, deleteLinking) {
using ::testing::IsEmpty;
using ::testing::UnorderedElementsAre;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.Times(4)
.WillRepeatedly(ReturnRef(m_buckets));
@@ -120,7 +121,7 @@ TEST_F(InMemeoryStorageBackendFixture, insertPolicy) {
using ::testing::UnorderedElementsAre;
using PredefinedPolicyType::ALLOW;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillOnce(ReturnRef(m_buckets));
@@ -136,7 +137,7 @@ TEST_F(InMemeoryStorageBackendFixture, insertPolicy) {
TEST_F(InMemeoryStorageBackendFixture, insertPolicyToNonexistentBucket) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillOnce(ReturnRef(m_buckets));
@@ -151,7 +152,7 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicy) {
using ::testing::ContainerEq;
using PredefinedPolicyType::ALLOW;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillOnce(ReturnRef(m_buckets));
@@ -184,7 +185,7 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicyFromNonexistentBucket) {
using ::testing::IsEmpty;
using ::testing::UnorderedElementsAre;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillOnce(ReturnRef(m_buckets));
@@ -311,7 +312,7 @@ TEST_F(InMemeoryStorageBackendFixture, load_from_backup) {
TEST_F(InMemeoryStorageBackendFixture, erasePoliciesEmptyBase) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -345,7 +346,7 @@ TEST_F(InMemeoryStorageBackendFixture, erasePoliciesSingleBucket) {
for (const auto &filter : filters()) {
SCOPED_TRACE(filter.name());
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
createBucket(bucketId);
@@ -380,7 +381,7 @@ TEST_F(InMemeoryStorageBackendFixture, erasePoliciesRecursiveNotLinkedBuckets) {
for (const auto &filter : filters()) {
SCOPED_TRACE(filter.name());
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
createBucket(bucketId);
@@ -423,7 +424,7 @@ TEST_F(InMemeoryStorageBackendFixture, erasePoliciesRecursiveLinkedBuckets) {
for (const auto &filter : filters()) {
SCOPED_TRACE(filter.name());
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
createBucket(bucketId);
@@ -473,7 +474,7 @@ TEST_F(InMemeoryStorageBackendFixture, erasePoliciesRecursiveLinkedBucketsNoBack
for (const auto &filter : filters()) {
SCOPED_TRACE(filter.name());
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
createBucket(bucketId);
@@ -522,7 +523,7 @@ TEST_F(InMemeoryStorageBackendFixture, erasePoliciesNonRecursiveLinkedBuckets) {
for (const auto &filter : filters()) {
SCOPED_TRACE(filter.name());
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
createBucket(bucketId);
diff --git a/test/storage/inmemorystoragebackend/search.cpp b/test/storage/inmemorystoragebackend/search.cpp
index cf6a419..46247a2 100644
--- a/test/storage/inmemorystoragebackend/search.cpp
+++ b/test/storage/inmemorystoragebackend/search.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ TEST_F(InMemeoryStorageBackendFixture, searchDefault) {
createBucket(defaultPolicyBucketId, policies);
// Just override buckets() accessor
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
--
2.7.4
From ba47308b144e4321ebce79ecf837a1104b0d1d74 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Mon, 22 Dec 2014 16:18:41 +0100
Subject: [PATCH 13/16] Modify RecordCorruptedException class hierarchy
So far there was only one type of record Cynara could read from its
database. If any corruption was detected, BucketRecordCorruptedException
was thrown.
Now database will contain information about not only buckets and
policies, but also some metadata for them (in this case - checksums).
Need for exception superclass for handling corrupted records emerged.
Patch modifies exception class hierarchy and adds new exception type:
ChecksumRecordCorruptedException.
Change-Id: I3af6bd20b57e17ec31d766f138595920c7a413bd
---
.../exceptions/BucketRecordCorruptedException.h | 64 ++++------------
.../exceptions/ChecksumRecordCorruptedException.h | 57 ++++++++++++++
src/common/exceptions/RecordCorruptedException.h | 86 ++++++++++++++++++++++
3 files changed, 158 insertions(+), 49 deletions(-)
create mode 100644 src/common/exceptions/ChecksumRecordCorruptedException.h
create mode 100644 src/common/exceptions/RecordCorruptedException.h
diff --git a/src/common/exceptions/BucketRecordCorruptedException.h b/src/common/exceptions/BucketRecordCorruptedException.h
index a5ffb7d..e7ea604 100644
--- a/src/common/exceptions/BucketRecordCorruptedException.h
+++ b/src/common/exceptions/BucketRecordCorruptedException.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,82 +16,48 @@
/**
* @file src/common/exceptions/BucketRecordCorruptedException.h
* @author Aleksander Zdyb
+ * @author Pawel Wieczorek
* @version 1.0
* @brief Implementation of BucketRecordCorruptedException
*/
+
#ifndef SRC_COMMON_EXCEPTIONS_BUCKETRECORDCORRUPTEDEXCEPTION_H_
#define SRC_COMMON_EXCEPTIONS_BUCKETRECORDCORRUPTEDEXCEPTION_H_
#include
-#include
+#include
namespace Cynara {
-class BucketRecordCorruptedException : public DatabaseException {
+class BucketRecordCorruptedException : public RecordCorruptedException {
public:
- BucketRecordCorruptedException(void) = delete;
+ BucketRecordCorruptedException() = delete;
virtual ~BucketRecordCorruptedException() {};
- BucketRecordCorruptedException(const std::string &line)
- : m_lineNumber(0), m_line(line) {}
+ BucketRecordCorruptedException(const std::string &line) : RecordCorruptedException(line) {
+ setMessage(subtype());
+ }
BucketRecordCorruptedException withLineNumber(const size_t &lineNumber) const {
BucketRecordCorruptedException copy(*this);
copy.m_lineNumber = lineNumber;
- copy.m_message.clear();
+ copy.setMessage(copy.subtype());
return copy;
}
BucketRecordCorruptedException withFilename(const std::string &filename) const {
BucketRecordCorruptedException copy(*this);
copy.m_filename = filename;
- copy.m_message.clear();
+ copy.setMessage(copy.subtype());
return copy;
}
- virtual const std::string &message(void) const {
- if (m_message.empty()) {
- m_message = "Bucket record corrupted at"
- + formatedFilename()
- + formatedLineNumber()
- + ": <" + slicedLine() + ">";
- }
- return m_message;
- }
-
- const std::string &filename(void) const {
- return m_filename;
- }
-
- const std::string &line(void) const {
- return m_line;
- }
-
- size_t lineNumber(void) const {
- return m_lineNumber;
- }
-
-protected:
- inline std::string slicedLine(void) const {
- return m_line.substr(0, 50) + (m_line.size() > 50 ? "..." : "");
- }
-
- inline std::string formatedFilename(void) const {
- return m_filename.empty() ? " line" : " " + m_filename;
- }
-
- inline std::string formatedLineNumber(void) const {
- return m_lineNumber <= 0 ? ""
- : (m_filename.empty() ? " " : ":")
- + std::to_string(static_cast(m_lineNumber));
- }
-
private:
- size_t m_lineNumber;
- std::string m_line;
- std::string m_filename;
- mutable std::string m_message;
+ const std::string &subtype(void) {
+ static const std::string subtype("Bucket");
+ return subtype;
+ }
};
} /* namespace Cynara */
diff --git a/src/common/exceptions/ChecksumRecordCorruptedException.h b/src/common/exceptions/ChecksumRecordCorruptedException.h
new file mode 100644
index 0000000..84b81bc
--- /dev/null
+++ b/src/common/exceptions/ChecksumRecordCorruptedException.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file src/common/exceptions/ChecksumRecordCorruptedException.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Implementation of ChecksumRecordCorruptedException
+ */
+
+#ifndef SRC_COMMON_EXCEPTIONS_CHECKSUMRECORDCORRUPTEDEXCEPTION_H_
+#define SRC_COMMON_EXCEPTIONS_CHECKSUMRECORDCORRUPTEDEXCEPTION_H_
+
+#include
+
+#include
+
+namespace Cynara {
+
+class ChecksumRecordCorruptedException : public RecordCorruptedException {
+public:
+ ChecksumRecordCorruptedException() = delete;
+ virtual ~ChecksumRecordCorruptedException() {};
+
+ ChecksumRecordCorruptedException(const std::string &line) : RecordCorruptedException(line) {
+ setMessage(subtype());
+ }
+
+ ChecksumRecordCorruptedException withLineNumber(const size_t &lineNumber) const {
+ ChecksumRecordCorruptedException copy(*this);
+ copy.m_lineNumber = lineNumber;
+ copy.setMessage(copy.subtype());
+ return copy;
+ }
+
+private:
+ const std::string &subtype(void) {
+ static const std::string subtype("Checksum");
+ return subtype;
+ }
+};
+
+} /* namespace Cynara */
+
+#endif /* SRC_COMMON_EXCEPTIONS_CHECKSUMRECORDCORRUPTEDEXCEPTION_H_ */
diff --git a/src/common/exceptions/RecordCorruptedException.h b/src/common/exceptions/RecordCorruptedException.h
new file mode 100644
index 0000000..6177aab
--- /dev/null
+++ b/src/common/exceptions/RecordCorruptedException.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file src/common/exceptions/RecordCorruptedException.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Implementation of RecordCorruptedException
+ */
+
+#ifndef SRC_COMMON_EXCEPTIONS_RECORDCORRUPTEDEXCEPTION_H_
+#define SRC_COMMON_EXCEPTIONS_RECORDCORRUPTEDEXCEPTION_H_
+
+#include
+
+#include
+
+namespace Cynara {
+
+class RecordCorruptedException : public DatabaseException {
+public:
+ RecordCorruptedException(void) = delete;
+ virtual ~RecordCorruptedException() {};
+
+ RecordCorruptedException(const std::string &line)
+ : m_lineNumber(0), m_line(line), m_filename(std::string()) {
+ setMessage(std::string());
+ }
+
+ const std::string &message(void) const {
+ return m_message;
+ }
+
+ const std::string &filename(void) const {
+ return m_filename;
+ }
+
+ const std::string &line(void) const {
+ return m_line;
+ }
+
+ size_t lineNumber(void) const {
+ return m_lineNumber;
+ }
+
+protected:
+ std::string slicedLine(void) const {
+ return m_line.substr(0, 50) + (m_line.size() > 50 ? "..." : "");
+ }
+
+ std::string formattedMetadata(void) const {
+ return (m_filename.empty() ? "line" : m_filename)
+ + (m_lineNumber <= 0 ? "" : formattedLineNumber());
+ }
+
+ std::string formattedLineNumber(void) const {
+ return (m_filename.empty() ? " " : ":")
+ + std::to_string(static_cast(m_lineNumber));
+ }
+
+ void setMessage(const std::string &subtype) {
+ m_message = (subtype.empty() ? "Record" : subtype + " record") + " corrupted at "
+ + formattedMetadata() + ": <" + slicedLine() + ">";
+ }
+
+ size_t m_lineNumber;
+ std::string m_line;
+ std::string m_filename;
+ std::string m_message;
+};
+
+} /* namespace Cynara */
+
+#endif /* SRC_COMMON_EXCEPTIONS_RECORDCORRUPTEDEXCEPTION_H_ */
--
2.7.4
From 8a9adaa9c38a3269942181abadb5f700b7661ccb Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Thu, 26 Feb 2015 14:39:39 +0100
Subject: [PATCH 14/16] Fix basename() usage in ChecksumGenerator
Contents of a string passed to basename() as an argument may be modified
(it depends on implementation). In order not to perform unexpected
changes, duplicate of given string is passed to basename().
Change-Id: Ib783629160f9528a6054dd0f78b9ebd5e6870fb6
---
src/chsgen/ChecksumGenerator.cpp | 32 +++++++++++++++++++++++---------
src/chsgen/ChecksumGenerator.h | 4 ++--
2 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/src/chsgen/ChecksumGenerator.cpp b/src/chsgen/ChecksumGenerator.cpp
index 6255403..fcc76dc 100644
--- a/src/chsgen/ChecksumGenerator.cpp
+++ b/src/chsgen/ChecksumGenerator.cpp
@@ -23,6 +23,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -43,8 +45,10 @@ const char ChecksumGenerator::m_fieldSeparator(StorageConfig::fieldSeparator);
const char ChecksumGenerator::m_recordSeparator(StorageConfig::recordSeparator);
const std::string ChecksumGenerator::m_backupFilenameSuffix(StorageConfig::backupFilenameSuffix);
-ChecksumGenerator::ChecksumGenerator(int argc, char * const *argv) : m_copyStream(std::string()) {
- m_filename = (1 < argc ? argv[1] : std::string());
+ChecksumGenerator::ChecksumGenerator(int argc, char * const *argv) {
+ if (argc > 1) {
+ m_pathname = argv[1];
+ }
}
int ChecksumGenerator::run(void) {
@@ -65,11 +69,14 @@ int ChecksumGenerator::run(void) {
} catch (const std::length_error &ex) {
std::cerr << ex.what() << std::endl;
return CYNARA_API_UNKNOWN_ERROR;
+ } catch (const std::bad_alloc &ex) {
+ std::cerr << ex.what() << std::endl;
+ return CYNARA_API_OUT_OF_MEMORY;
}
}
const std::string ChecksumGenerator::generate(const std::string &data) {
- auto checksum = crypt(data.c_str(), "$1$");
+ const char *checksum = crypt(data.c_str(), "$1$");
if (nullptr != checksum) {
return std::string(checksum);
@@ -85,10 +92,10 @@ const std::string ChecksumGenerator::generate(const std::string &data) {
};
void ChecksumGenerator::openFileStream(void) {
- m_inputStream.open(m_filename);
+ m_inputStream.open(m_pathname);
if (!m_inputStream.is_open()) {
- throw FileNotFoundException(m_filename);
+ throw FileNotFoundException(m_pathname);
}
}
@@ -100,14 +107,21 @@ void ChecksumGenerator::copyFileStream(void) {
}
void ChecksumGenerator::printRecord(void) const {
- std::string filename(basename(m_filename.c_str()));
- getBasicFilename(filename);
+ std::unique_ptr pathnameDuplicate(strdup(m_pathname.c_str()), free);
+ if (pathnameDuplicate == nullptr) {
+ LOGE("Insufficient memory available to allocate duplicate filename: <%s>",
+ m_pathname.c_str());
+ throw std::bad_alloc();
+ }
+
+ std::string basename(::basename(pathnameDuplicate.get()));
+ removeBackupSuffix(basename);
- std::cout << filename << m_fieldSeparator << generate(m_copyStream.str())
+ std::cout << basename << m_fieldSeparator << generate(m_copyStream.str())
<< m_recordSeparator;
}
-void ChecksumGenerator::getBasicFilename(std::string &filename) const {
+void ChecksumGenerator::removeBackupSuffix(std::string &filename) const {
auto backupSuffixPos = filename.rfind(m_backupFilenameSuffix);
if (std::string::npos != backupSuffixPos &&
diff --git a/src/chsgen/ChecksumGenerator.h b/src/chsgen/ChecksumGenerator.h
index a3e96e0..30e34fb 100644
--- a/src/chsgen/ChecksumGenerator.h
+++ b/src/chsgen/ChecksumGenerator.h
@@ -42,11 +42,11 @@ private:
void openFileStream(void);
void copyFileStream(void);
void printRecord(void) const;
- void getBasicFilename(std::string &filename) const;
+ void removeBackupSuffix(std::string &filename) const;
std::ifstream m_inputStream;
std::stringstream m_copyStream;
- std::string m_filename;
+ std::string m_pathname;
static const char m_fieldSeparator;
static const char m_recordSeparator;
static const std::string m_backupFilenameSuffix;
--
2.7.4
From 7832866a7fbf8b6425e180d1dbdfe7b80ab8f96d Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Tue, 23 Dec 2014 14:53:59 +0100
Subject: [PATCH 15/16] Introduce ChecksumValidator
ChecksumValidator computes checksums for every file listed in checksum
index equivalent using crypt(3). As a result, base64-like (custom
alphabet) encoded strings are produced and compared with last known
corresponding digest. Its 4-character prefix indicates used algorithm.
Class will be later used as an integrity mechanism extension.
Change-Id: Ibaba636bae30c747e8eac5561e9b130d4398518e
---
src/storage/CMakeLists.txt | 2 +
src/storage/ChecksumValidator.cpp | 142 ++++++++++++++++++++++++++++++++++++++
src/storage/ChecksumValidator.h | 65 +++++++++++++++++
test/CMakeLists.txt | 1 +
4 files changed, 210 insertions(+)
create mode 100644 src/storage/ChecksumValidator.cpp
create mode 100644 src/storage/ChecksumValidator.h
diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt
index 7bccc8c..996b37a 100644
--- a/src/storage/CMakeLists.txt
+++ b/src/storage/CMakeLists.txt
@@ -24,6 +24,7 @@ SET(CYNARA_LIB_CYNARA_STORAGE_PATH ${CYNARA_PATH}/storage)
SET(LIB_CYNARA_STORAGE_SOURCES
${CYNARA_LIB_CYNARA_STORAGE_PATH}/BucketDeserializer.cpp
+ ${CYNARA_LIB_CYNARA_STORAGE_PATH}/ChecksumValidator.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/InMemoryStorageBackend.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/Integrity.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/Storage.cpp
@@ -51,6 +52,7 @@ SET_TARGET_PROPERTIES(
TARGET_LINK_LIBRARIES(${TARGET_LIB_CYNARA_STORAGE}
${CYNARA_DEP_LIBRARIES}
${TARGET_CYNARA_COMMON}
+ crypt
)
INSTALL(TARGETS ${TARGET_LIB_CYNARA_STORAGE} DESTINATION ${LIB_INSTALL_DIR})
diff --git a/src/storage/ChecksumValidator.cpp b/src/storage/ChecksumValidator.cpp
new file mode 100644
index 0000000..1354ad1
--- /dev/null
+++ b/src/storage/ChecksumValidator.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file src/storage/ChecksumValidator.cpp
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief This file contains ChecksumValidator implementation.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "ChecksumValidator.h"
+
+namespace Cynara {
+
+const std::string ChecksumValidator::m_checksumFilename(PathConfig::StoragePath::checksumFilename);
+const std::string ChecksumValidator::m_backupFilenameSuffix(
+ PathConfig::StoragePath::backupFilenameSuffix);
+
+void ChecksumValidator::load(std::istream &stream) {
+ m_sums.clear();
+
+ std::string line;
+ std::size_t lineNum = 1;
+ while (std::getline(stream, line, PathConfig::StoragePath::recordSeparator)) {
+ try {
+ std::size_t beginToken = 0;
+ std::string filename = parseFilename(line, beginToken);
+ std::string checksum = parseChecksum(line, beginToken);
+
+ m_sums.insert({ filename, checksum });
+ ++lineNum;
+ } catch (const ChecksumRecordCorruptedException &ex) {
+ throw ex.withLineNumber(lineNum);
+ }
+ }
+};
+
+const std::string ChecksumValidator::generate(const std::string &data) {
+ const char *checksum = crypt(data.c_str(), "$1$");
+
+ if (nullptr != checksum) {
+ return checksum;
+ }
+
+ int err = errno;
+ if (err == ENOSYS) {
+ LOGE("'crypt' function was not implemented; error [%d] : <%s>", err, strerror(err));
+ } else {
+ LOGE("'crypt' function error [%d] : <%s>", err, strerror(err));
+ }
+ throw UnexpectedErrorException(err, strerror(err));
+};
+
+void ChecksumValidator::compare(std::istream &stream, const std::string &pathname,
+ bool isBackupValid) {
+ if (isChecksumIndex(pathname)) {
+ return;
+ }
+
+ std::unique_ptr pathnameDuplicate(strdup(pathname.c_str()), free);
+ if (pathnameDuplicate == nullptr) {
+ LOGE("Insufficient memory available to allocate duplicate filename: <%s>",
+ pathname.c_str());
+ throw std::bad_alloc();
+ }
+
+ std::string filename(::basename(pathnameDuplicate.get()));
+ std::stringstream copyStream;
+
+ if (isBackupValid) {
+ auto backupSuffixPos = filename.rfind(m_backupFilenameSuffix);
+
+ if ((std::string::npos != backupSuffixPos) &&
+ (filename.size() == (backupSuffixPos + m_backupFilenameSuffix.size()))) {
+ filename.erase(backupSuffixPos);
+ }
+ }
+
+ std::copy(std::istreambuf_iterator(stream),
+ std::istreambuf_iterator(),
+ std::ostreambuf_iterator(copyStream));
+ stream.seekg(0);
+
+ if (m_sums[filename] != generate(copyStream.str())) {
+ throw ChecksumRecordCorruptedException(m_sums[filename]);
+ }
+};
+
+const std::string ChecksumValidator::parseFilename(const std::string &line,
+ std::size_t &beginToken) {
+ std::size_t filenameEndToken = line.find(PathConfig::StoragePath::fieldSeparator, beginToken);
+ if (filenameEndToken != beginToken && filenameEndToken != std::string::npos) {
+ auto filename = line.substr(beginToken, filenameEndToken - beginToken);
+ beginToken = filenameEndToken + 1;
+ return filename;
+ }
+ throw ChecksumRecordCorruptedException(line);
+}
+
+const std::string ChecksumValidator::parseChecksum(const std::string &line,
+ std::size_t &beginToken) {
+ if (beginToken >= line.size()) {
+ throw ChecksumRecordCorruptedException(line);
+ }
+
+ auto checksum = line.substr(beginToken);
+ beginToken = line.size();
+ return checksum;
+}
+
+bool ChecksumValidator::isChecksumIndex(const std::string &filename) const {
+ auto checksum = m_dbPath + m_checksumFilename;
+ return (filename == checksum || filename == checksum + m_backupFilenameSuffix);
+}
+
+} // namespace Cynara
diff --git a/src/storage/ChecksumValidator.h b/src/storage/ChecksumValidator.h
new file mode 100644
index 0000000..bfd577b
--- /dev/null
+++ b/src/storage/ChecksumValidator.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file src/storage/ChecksumValidator.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief This file contains ChecksumValidator header.
+ */
+
+#ifndef SRC_STORAGE_CHECKSUMVALIDATOR_H_
+#define SRC_STORAGE_CHECKSUMVALIDATOR_H_
+
+#include
+#include
+#include
+#include
+
+namespace Cynara {
+
+class ChecksumValidator;
+typedef std::unique_ptr ChecksumValidatorUniquePtr;
+
+class ChecksumValidator {
+public:
+ ChecksumValidator(const std::string &path) : m_dbPath(path) {}
+
+ void load(std::istream &stream);
+ void compare(std::istream &stream, const std::string &pathname, bool isBackupValid);
+
+ void clear(void) {
+ m_sums.clear();
+ }
+
+ static const std::string generate(const std::string &data);
+
+protected:
+ typedef std::unordered_map Checksums;
+
+ bool isChecksumIndex(const std::string &pathname) const;
+
+ static const std::string parseFilename(const std::string &line, std::size_t &beginToken);
+ static const std::string parseChecksum(const std::string &line, std::size_t &beginToken);
+
+ Checksums m_sums;
+ const std::string m_dbPath;
+ static const std::string m_checksumFilename;
+ static const std::string m_backupFilenameSuffix;
+};
+
+} // namespace Cynara
+
+#endif // SRC_STORAGE_CHECKSUMVALIDATOR_H_
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index d937d3c..f9b42a8 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -63,6 +63,7 @@ SET(CYNARA_SOURCES_FOR_TESTS
${CYNARA_SRC}/helpers/creds-commons/creds-commons.cpp
${CYNARA_SRC}/service/main/CmdlineParser.cpp
${CYNARA_SRC}/storage/BucketDeserializer.cpp
+ ${CYNARA_SRC}/storage/ChecksumValidator.cpp
${CYNARA_SRC}/storage/InMemoryStorageBackend.cpp
${CYNARA_SRC}/storage/Integrity.cpp
${CYNARA_SRC}/storage/Storage.cpp
--
2.7.4
From 9f0e503b603acb3bcb7dfedd6fd27216070e6be7 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Tue, 27 Jan 2015 11:47:19 +0100
Subject: [PATCH 16/16] Add tests for ChecksumValidator
Add tests checking if ChecksumValidator properly:
* generates checksums,
* loads them or rejects corrupted records,
* supports backup files.
Change-Id: I2e4222283cc0676490134819561824df6661034f
---
test/CMakeLists.txt | 1 +
test/storage/checksum/checksumvalidator.cpp | 154 +++++++++++++++++++++++
test/storage/checksum/checksumvalidatorfixture.h | 54 ++++++++
test/storage/checksum/fakechecksumvalidator.h | 37 ++++++
4 files changed, 246 insertions(+)
create mode 100644 test/storage/checksum/checksumvalidator.cpp
create mode 100644 test/storage/checksum/checksumvalidatorfixture.h
create mode 100644 test/storage/checksum/fakechecksumvalidator.h
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index f9b42a8..5050634 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -92,6 +92,7 @@ SET(CYNARA_TESTS_SOURCES
cyad/policy_parser.cpp
helpers.cpp
service/main/cmdlineparser.cpp
+ storage/checksum/checksumvalidator.cpp
storage/performance/bucket.cpp
storage/storage/policies.cpp
storage/storage/check.cpp
diff --git a/test/storage/checksum/checksumvalidator.cpp b/test/storage/checksum/checksumvalidator.cpp
new file mode 100644
index 0000000..19918f3
--- /dev/null
+++ b/test/storage/checksum/checksumvalidator.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file test/storage/checksum/checksumvalidator.cpp
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Tests of ChecksumValidator
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "checksumvalidatorfixture.h"
+#include "fakechecksumvalidator.h"
+
+using namespace Cynara;
+
+const std::string ChecksumValidatorFixture::m_dbPath("/fake/path/");
+const std::string ChecksumValidatorFixture::m_filename("fakeFilename");
+const std::string ChecksumValidatorFixture::m_checksum("$1$$fakeChecksum");
+const std::string ChecksumValidatorFixture::m_backupFilenameSuffix(
+ PathConfig::StoragePath::backupFilenameSuffix);
+const char ChecksumValidatorFixture::m_fieldSeparator(PathConfig::StoragePath::fieldSeparator);
+const char ChecksumValidatorFixture::m_recordSeparator(PathConfig::StoragePath::recordSeparator);
+const size_t ChecksumValidatorFixture::m_firstLine(1);
+
+/**
+ * @brief Verify if generate() can use systems' crypt(3) implementation
+ * @test Expected result: no exceptions are thrown and non-empty string is returned
+ */
+TEST_F(ChecksumValidatorFixture, generateChecksum) {
+ for (const auto &data : { std::string("test-data"), std::string() }) {
+ SCOPED_TRACE(data);
+
+ std::string returnedChecksum;
+ ASSERT_NO_THROW(returnedChecksum = ChecksumValidator::generate(data));
+ ASSERT_NE(std::string(), returnedChecksum);
+ }
+}
+
+/**
+ * @brief Verify if load() can successfully parse sample checksum record
+ * @test Expected result:
+ * - no exceptions are thrown from load()
+ * - proper checksums are stored for corresponding files
+ */
+TEST_F(ChecksumValidatorFixture, parseCorrectRecords) {
+ std::istringstream checksums(m_filename + m_fieldSeparator + m_checksum);
+
+ FakeChecksumValidator validator(m_dbPath);
+ ASSERT_NO_THROW(validator.load(checksums));
+ ASSERT_EQ(m_checksum, validator.sums().at(m_filename));
+}
+
+/**
+ * @brief Verify if load() rejects storing corrupted checksum records
+ * @test Expected result:
+ * - load() throws ChecksumRecordCorruptedException
+ * - no data is stored (there was no correct data to insert)
+ */
+TEST_F(ChecksumValidatorFixture, parseCorruptedRecords) {
+ const auto badLines = { m_filename + m_fieldSeparator,
+ m_filename + m_checksum,
+ m_fieldSeparator + m_checksum };
+
+ FakeChecksumValidator validator(m_dbPath);
+
+ for (const auto &badLine : badLines) {
+ SCOPED_TRACE(badLine);
+ std::istringstream checksums(badLine);
+
+ ASSERT_THROW(validator.load(checksums), ChecksumRecordCorruptedException);
+ ASSERT_TRUE(validator.sums().empty());
+ }
+}
+
+/**
+ * @brief Verify if compare() can successfully check sample database file
+ * @test Expected result: no exceptions are thrown and file contents are still readable
+ */
+TEST_F(ChecksumValidatorFixture, compareBasicAndBackup) {
+ FakeChecksumValidator validator(m_dbPath);
+ std::string checksumsContents;
+ simpleChecksumsContents(checksumsContents);
+
+ std::istringstream checksums(checksumsContents);
+ validator.load(checksums);
+
+ std::unordered_map files = { { "_", std::string() },
+ { "buckets", ";0x0;\n" } };
+
+ for (const auto &file : files) {
+ const auto filename = m_dbPath + file.first;
+ const auto contents = file.second;
+ std::istringstream fakeFile(contents);
+
+ SCOPED_TRACE(filename);
+
+ ASSERT_NO_THROW(validator.compare(fakeFile, filename, false));
+ ASSERT_NO_THROW(validator.compare(fakeFile, filename + m_backupFilenameSuffix, true));
+
+ ASSERT_EQ(contents, fakeFile.str());
+ }
+}
+
+/**
+ * @brief Verify if compare() throws an exception when checksum mismatch is detected
+ * @test Expected result: ChecksumRecordCorruptedException is thrown
+ */
+TEST_F(ChecksumValidatorFixture, checksumMismatch) {
+ FakeChecksumValidator validator(m_dbPath);
+ std::string checksumsContents;
+ simpleChecksumsContents(checksumsContents);
+
+ std::istringstream checksums(checksumsContents);
+ validator.load(checksums);
+
+ // Please note that default policy is set to ALLOW instead of DENY
+ std::unordered_map files = { { "_", "client;user;privilege;0x0;" },
+ { "buckets", ";0xFFFF;\n" } };
+
+ for (const auto &file : files) {
+ const auto filename = m_dbPath + file.first;
+ const auto contents = file.second;
+ std::istringstream fakeFile(contents);
+ SCOPED_TRACE(filename);
+
+ ASSERT_THROW(validator.compare(fakeFile, filename, false),
+ ChecksumRecordCorruptedException);
+ }
+}
diff --git a/test/storage/checksum/checksumvalidatorfixture.h b/test/storage/checksum/checksumvalidatorfixture.h
new file mode 100644
index 0000000..6fb28f6
--- /dev/null
+++ b/test/storage/checksum/checksumvalidatorfixture.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file test/storage/checksum/checksumvalidatorfixture.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Fixture for ChecksumValidator tests
+ */
+
+#ifndef CHECKSUMVALIDATORFIXTURE_H_
+#define CHECKSUMVALIDATORFIXTURE_H_
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+class ChecksumValidatorFixture : public ::testing::Test {
+protected:
+ void simpleChecksumsContents(std::string &contents) {
+ std::stringstream buffer;
+ buffer << "_" << m_fieldSeparator << "$1$$qRPK7m23GJusamGpoGLby/" << m_recordSeparator
+ << "buckets" << m_fieldSeparator << "$1$$6ZlVs5lw2nZgVmiw0BdY21"
+ << m_recordSeparator;
+
+ contents = buffer.str();
+ }
+
+ static const std::string m_dbPath;
+ static const std::string m_filename;
+ static const std::string m_checksum;
+ static const std::string m_backupFilenameSuffix;
+ static const char m_fieldSeparator;
+ static const char m_recordSeparator;
+ static const size_t m_firstLine;
+};
+
+#endif /* CHECKSUMVALIDATORFIXTURE_H_ */
diff --git a/test/storage/checksum/fakechecksumvalidator.h b/test/storage/checksum/fakechecksumvalidator.h
new file mode 100644
index 0000000..af3ed82
--- /dev/null
+++ b/test/storage/checksum/fakechecksumvalidator.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file test/storage/checksum/fakechecksumvalidator.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Mock of ChecksumValidator
+ */
+
+#ifndef FAKECHECKSUMVALIDATOR_H_
+#define FAKECHECKSUMVALIDATOR_H_
+
+#include
+
+class FakeChecksumValidator : public Cynara::ChecksumValidator {
+public:
+ using Cynara::ChecksumValidator::ChecksumValidator;
+
+ const Checksums &sums(void) {
+ return m_sums;
+ }
+};
+
+#endif /* FAKECHECKSUMVALIDATOR_H_ */
--
2.7.4