From dbf54b95632dcadcdc5c745fc4241953c93af15f Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Tue, 21 Feb 2017 22:27:46 +0000 Subject: [PATCH] Add test cases for BlockStore2 and fix existing BlockStore2 implementations --- src/blockstore/CMakeLists.txt | 1 + .../encrypted/EncryptedBlockStore2.h | 47 +++- .../inmemory/InMemoryBlockStore2.cpp | 65 +++++ .../inmemory/InMemoryBlockStore2.h | 30 ++ .../ondisk/OnDiskBlockStore2.cpp | 5 + .../ondisk/OnDiskBlockStore2.h | 81 ++++-- .../versioncounting/IntegrityViolationError.h | 1 + .../VersionCountingBlockStore2.h | 88 +++--- src/blockstore/interface/BlockStore2.h | 2 + src/cpp-utils/data/Data.h | 11 + .../EncryptedBlockStoreTest_Generic.cpp | 24 ++ .../inmemory/InMemoryBlockStoreTest.cpp | 13 + .../ondisk/OnDiskBlockStoreTest_Generic.cpp | 17 ++ .../VersionCountingBlockStoreTest_Generic.cpp | 24 +- test/blockstore/testutils/BlockStore2Test.h | 263 ++++++++++++++++++ 15 files changed, 612 insertions(+), 60 deletions(-) create mode 100644 src/blockstore/implementations/inmemory/InMemoryBlockStore2.cpp create mode 100644 src/blockstore/implementations/inmemory/InMemoryBlockStore2.h create mode 100644 test/blockstore/testutils/BlockStore2Test.h diff --git a/src/blockstore/CMakeLists.txt b/src/blockstore/CMakeLists.txt index c66a23ae..8d1a595e 100644 --- a/src/blockstore/CMakeLists.txt +++ b/src/blockstore/CMakeLists.txt @@ -9,6 +9,7 @@ set(SOURCES implementations/testfake/FakeBlock.cpp implementations/inmemory/InMemoryBlock.cpp implementations/inmemory/InMemoryBlockStore.cpp + implementations/inmemory/InMemoryBlockStore2.cpp implementations/parallelaccess/ParallelAccessBlockStore.cpp implementations/parallelaccess/BlockRef.cpp implementations/parallelaccess/ParallelAccessBlockStoreAdapter.cpp diff --git a/src/blockstore/implementations/encrypted/EncryptedBlockStore2.h b/src/blockstore/implementations/encrypted/EncryptedBlockStore2.h index d1d54ae5..ea7805ad 100644 --- a/src/blockstore/implementations/encrypted/EncryptedBlockStore2.h +++ b/src/blockstore/implementations/encrypted/EncryptedBlockStore2.h @@ -21,7 +21,7 @@ public: } boost::future tryCreate(const Key &key, const cpputils::Data &data) override { - cpputils::Data encrypted = _encrypt(data); + cpputils::Data encrypted = _encrypt(key, data); return _baseBlockStore->tryCreate(key, encrypted); } @@ -31,34 +31,43 @@ public: boost::future> load(const Key &key) const override { auto loaded = _baseBlockStore->load(key); - return loaded.then([this] (boost::future> data_) { + return loaded.then([this, key] (boost::future> data_) { auto data = data_.get(); if (boost::none == data) { return boost::optional(boost::none); } - return _tryDecrypt(data); + return _tryDecrypt(key, *data); }); } boost::future store(const Key &key, const cpputils::Data &data) override { - cpputils::Data encrypted = _encrypt(data); + cpputils::Data encrypted = _encrypt(key, data); return _baseBlockStore->store(key, encrypted); } private: - cpputils::Data _encrypt(const Key &key, const cpputils::Data &data) { + // This header is prepended to blocks to allow future versions to have compatibility. + static constexpr uint16_t FORMAT_VERSION_HEADER = 0; + + cpputils::Data _encrypt(const Key &key, const cpputils::Data &data) const { cpputils::Data plaintextWithHeader = _prependKeyHeaderToData(key, data); - return Cipher::encrypt((byte*)plaintextWithHeader.data(), plaintextWithHeader.size(), _encKey); + cpputils::Data encrypted = Cipher::encrypt((byte*)plaintextWithHeader.data(), plaintextWithHeader.size(), _encKey); + return _prependFormatHeaderToData(encrypted); } - boost::optional _tryDecrypt(const Key &key, const cpputils::Data &data) { - boost::optional decrypted = Cipher::decrypt((byte*)data.data(), data.size(), _encKey); - if (boost::none != decrypted && !_keyHeaderIsCorrect(key, *decrypted)) { + boost::optional _tryDecrypt(const Key &key, const cpputils::Data &data) const { + auto ciphertext = _checkAndRemoveFormatHeader(data); + boost::optional decrypted = Cipher::decrypt((byte*)ciphertext.data(), ciphertext.size(), _encKey); + if (boost::none == decrypted) { // TODO Warning return boost::none; } - return decrypted; + if (!_keyHeaderIsCorrect(key, *decrypted)) { + // TODO Warning + return boost::none; + } + return _removeKeyHeader(*decrypted); } static cpputils::Data _prependKeyHeaderToData(const Key &key, const cpputils::Data &data) { @@ -72,6 +81,24 @@ private: return 0 == std::memcmp(key.data(), data.data(), Key::BINARY_LENGTH); } + static cpputils::Data _prependFormatHeaderToData(const cpputils::Data &data) { + cpputils::Data dataWithHeader(sizeof(FORMAT_VERSION_HEADER) + data.size()); + std::memcpy(dataWithHeader.dataOffset(0), &FORMAT_VERSION_HEADER, sizeof(FORMAT_VERSION_HEADER)); + std::memcpy(dataWithHeader.dataOffset(sizeof(FORMAT_VERSION_HEADER)), data.data(), data.size()); + return dataWithHeader; + } + + static cpputils::Data _removeKeyHeader(const cpputils::Data &data) { + return data.copyAndRemovePrefix(Key::BINARY_LENGTH); + } + + static cpputils::Data _checkAndRemoveFormatHeader(const cpputils::Data &data) { + if (*reinterpret_cast(data.data()) != FORMAT_VERSION_HEADER) { + throw std::runtime_error("The encrypted block has the wrong format. Was it created with a newer version of CryFS?"); + } + return data.copyAndRemovePrefix(sizeof(FORMAT_VERSION_HEADER)); + } + cpputils::unique_ref _baseBlockStore; typename Cipher::EncryptionKey _encKey; diff --git a/src/blockstore/implementations/inmemory/InMemoryBlockStore2.cpp b/src/blockstore/implementations/inmemory/InMemoryBlockStore2.cpp new file mode 100644 index 00000000..8442c1a3 --- /dev/null +++ b/src/blockstore/implementations/inmemory/InMemoryBlockStore2.cpp @@ -0,0 +1,65 @@ +#include "InMemoryBlockStore2.h" +#include +#include +#include + +using std::make_unique; +using std::string; +using std::mutex; +using std::lock_guard; +using std::piecewise_construct; +using std::make_tuple; +using std::make_pair; +using cpputils::Data; +using cpputils::unique_ref; +using cpputils::make_unique_ref; +using boost::optional; +using boost::none; +using boost::future; +using boost::make_ready_future; + +namespace blockstore { +namespace inmemory { + +InMemoryBlockStore2::InMemoryBlockStore2() + : _blocks() {} + +future InMemoryBlockStore2::tryCreate(const Key &key, const Data &data) { + auto result = _blocks.insert(make_pair(key, data.copy())); + return make_ready_future(result.second); // Return if insertion was successful (i.e. key didn't exist yet) +} + +future InMemoryBlockStore2::remove(const Key &key) { + auto found = _blocks.find(key); + if (found == _blocks.end()) { + // Key not found + return make_ready_future(false); + } + + _blocks.erase(found); + return make_ready_future(true); +} + +future> InMemoryBlockStore2::load(const Key &key) const { + auto found = _blocks.find(key); + if (found == _blocks.end()) { + return make_ready_future(optional(none)); + } + return make_ready_future(optional(found->second.copy())); +} + +future InMemoryBlockStore2::store(const Key &key, const Data &data) { + auto found = _blocks.find(key); + if (found == _blocks.end()) { + return tryCreate(key, data).then([] (future success) { + if (!success.get()) { + throw std::runtime_error("Could neither save nor create the block in InMemoryBlockStore::store()"); + } + }); + } + found->second = data.copy(); + return make_ready_future(); +} + +} +} diff --git a/src/blockstore/implementations/inmemory/InMemoryBlockStore2.h b/src/blockstore/implementations/inmemory/InMemoryBlockStore2.h new file mode 100644 index 00000000..4fc63181 --- /dev/null +++ b/src/blockstore/implementations/inmemory/InMemoryBlockStore2.h @@ -0,0 +1,30 @@ +#pragma once +#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_INMEMORY_INMEMORYBLOCKSTORE2_H_ +#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_INMEMORY_INMEMORYBLOCKSTORE2_H_ + +#include "../../interface/BlockStore2.h" +#include +#include + +namespace blockstore { +namespace inmemory { + +class InMemoryBlockStore2 final: public BlockStore2 { +public: + InMemoryBlockStore2(); + + boost::future tryCreate(const Key &key, const cpputils::Data &data) override; + boost::future remove(const Key &key) override; + boost::future> load(const Key &key) const override; + boost::future store(const Key &key, const cpputils::Data &data) override; + +private: + std::unordered_map _blocks; + + DISALLOW_COPY_AND_ASSIGN(InMemoryBlockStore2); +}; + +} +} + +#endif diff --git a/src/blockstore/implementations/ondisk/OnDiskBlockStore2.cpp b/src/blockstore/implementations/ondisk/OnDiskBlockStore2.cpp index 782177e4..3bedad0b 100644 --- a/src/blockstore/implementations/ondisk/OnDiskBlockStore2.cpp +++ b/src/blockstore/implementations/ondisk/OnDiskBlockStore2.cpp @@ -1,7 +1,12 @@ #include "OnDiskBlockStore2.h" +using std::string; + namespace blockstore { namespace ondisk { +const string OnDiskBlockStore2::FORMAT_VERSION_HEADER_PREFIX = "cryfs;block;"; +const string OnDiskBlockStore2::FORMAT_VERSION_HEADER = OnDiskBlockStore2::FORMAT_VERSION_HEADER_PREFIX + "0"; + } } diff --git a/src/blockstore/implementations/ondisk/OnDiskBlockStore2.h b/src/blockstore/implementations/ondisk/OnDiskBlockStore2.h index 28787a77..f901073f 100644 --- a/src/blockstore/implementations/ondisk/OnDiskBlockStore2.h +++ b/src/blockstore/implementations/ondisk/OnDiskBlockStore2.h @@ -7,48 +7,95 @@ #include #include #include "OnDiskBlockStore.h" +#include namespace blockstore { namespace ondisk { -//TODO Implement without basing on OnDiskBlockStore - class OnDiskBlockStore2 final: public BlockStore2 { public: - explicit OnDiskBlockStore2(cpputils::unique_ref base) - : _base(std::move(base)) {} + explicit OnDiskBlockStore2(const boost::filesystem::path& path) + : _rootDir(path) {} boost::future tryCreate(const Key &key, const cpputils::Data &data) override { - auto created = _base->tryCreate(key, data.copy()); - if (boost::none == created) { + auto filepath = _getFilepath(key); + if (boost::filesystem::exists(filepath)) { return boost::make_ready_future(false); - } else { - return boost::make_ready_future(true); } + + store(key, data).wait(); + return boost::make_ready_future(true); } boost::future remove(const Key &key) override { - _base->remove(key); + auto filepath = _getFilepath(key); + if (!boost::filesystem::is_regular_file(filepath)) { // TODO Is this branch necessary? + return boost::make_ready_future(false); + } + bool retval = boost::filesystem::remove(filepath); + if (!retval) { + cpputils::logging::LOG(cpputils::logging::ERROR, "Couldn't find block {} to remove", key.ToString()); + return boost::make_ready_future(false); + } + if (boost::filesystem::is_empty(filepath.parent_path())) { + boost::filesystem::remove(filepath.parent_path()); + } return boost::make_ready_future(true); } boost::future> load(const Key &key) const override { - auto block = _base->load(key); - if (boost::none == block) { - return boost::make_ready_future>(boost::none); + auto fileContent = cpputils::Data::LoadFromFile(_getFilepath(key)); + if (fileContent == boost::none) { + return boost::make_ready_future(boost::optional(boost::none)); } - cpputils::Data data((*block)->size()); - std::memcpy(data.data(), (*block)->data(), data.size()); - return boost::make_ready_future>(std::move(data)); + return boost::make_ready_future(boost::optional(_checkAndRemoveHeader(std::move(*fileContent)))); } boost::future store(const Key &key, const cpputils::Data &data) override { - _base->overwrite(key, data.copy()); + cpputils::Data fileContent(formatVersionHeaderSize() + data.size()); + std::memcpy(fileContent.data(), FORMAT_VERSION_HEADER.c_str(), formatVersionHeaderSize()); + std::memcpy(fileContent.dataOffset(formatVersionHeaderSize()), data.data(), data.size()); + auto filepath = _getFilepath(key); + boost::filesystem::create_directory(filepath.parent_path()); // TODO Instead create all of them once at fs creation time? + fileContent.StoreToFile(filepath); return boost::make_ready_future(); } private: - cpputils::unique_ref _base; + boost::filesystem::path _rootDir; + + static const std::string FORMAT_VERSION_HEADER_PREFIX; + static const std::string FORMAT_VERSION_HEADER; + + boost::filesystem::path _getFilepath(const Key &key) const { + std::string keyStr = key.ToString(); + return _rootDir / keyStr.substr(0,3) / keyStr.substr(3); + } + + static cpputils::Data _checkAndRemoveHeader(const cpputils::Data &data) { + if (!_isAcceptedCryfsHeader(data)) { + if (_isOtherCryfsHeader(data)) { + throw std::runtime_error("This block is not supported yet. Maybe it was created with a newer version of CryFS?"); + } else { + throw std::runtime_error("This is not a valid block."); + } + } + cpputils::Data result(data.size() - formatVersionHeaderSize()); + std::memcpy(result.data(), data.dataOffset(formatVersionHeaderSize()), result.size()); + return result; + } + + static bool _isAcceptedCryfsHeader(const cpputils::Data &data) { + return 0 == std::memcmp(data.data(), FORMAT_VERSION_HEADER.c_str(), formatVersionHeaderSize()); + } + + static bool _isOtherCryfsHeader(const cpputils::Data &data) { + return 0 == std::memcmp(data.data(), FORMAT_VERSION_HEADER_PREFIX.c_str(), FORMAT_VERSION_HEADER_PREFIX.size()); + } + + static unsigned int formatVersionHeaderSize() { + return FORMAT_VERSION_HEADER.size() + 1; // +1 because of the null byte + } DISALLOW_COPY_AND_ASSIGN(OnDiskBlockStore2); }; diff --git a/src/blockstore/implementations/versioncounting/IntegrityViolationError.h b/src/blockstore/implementations/versioncounting/IntegrityViolationError.h index 41d0061d..a7d8085e 100644 --- a/src/blockstore/implementations/versioncounting/IntegrityViolationError.h +++ b/src/blockstore/implementations/versioncounting/IntegrityViolationError.h @@ -23,6 +23,7 @@ namespace blockstore { : _reason("Integrity violation: " + reason) { } friend class VersionCountingBlockStore; + friend class VersionCountingBlockStore2; std::string _reason; }; diff --git a/src/blockstore/implementations/versioncounting/VersionCountingBlockStore2.h b/src/blockstore/implementations/versioncounting/VersionCountingBlockStore2.h index 90a72d87..f73d96f0 100644 --- a/src/blockstore/implementations/versioncounting/VersionCountingBlockStore2.h +++ b/src/blockstore/implementations/versioncounting/VersionCountingBlockStore2.h @@ -5,6 +5,7 @@ #include "../../interface/BlockStore2.h" #include #include "KnownBlockVersions.h" +#include "IntegrityViolationError.h" namespace blockstore { namespace versioncounting { @@ -19,42 +20,57 @@ public: boost::future tryCreate(const Key &key, const cpputils::Data &data) override { _checkNoPastIntegrityViolations(); - uint64_t version = blockStore->knownBlockVersions()->incrementVersion(key); - cpputils::Data dataWithHeader = _prependHeaderToData(blockStore->knownBlockVersions()->myClientId(), version, data); - return baseBlockStore_->tryCreate(key, dataWithHeader); + uint64_t version = _knownBlockVersions.incrementVersion(key); + cpputils::Data dataWithHeader = _prependHeaderToData(_knownBlockVersions.myClientId(), version, data); + return _baseBlockStore->tryCreate(key, dataWithHeader); } boost::future remove(const Key &key) override { _checkNoPastIntegrityViolations(); _knownBlockVersions.markBlockAsDeleted(key); - return baseBlockStore->remove(key); + return _baseBlockStore->remove(key); } boost::future> load(const Key &key) const override { _checkNoPastIntegrityViolations(); - auto loaded = baseBlockStore_->load(key); - loaded.then([this, key] (boost::future> loaded_) { + return _baseBlockStore->load(key).then([this, key] (boost::future> loaded_) { auto loaded = loaded_.get(); if (boost::none == loaded) { if (_missingBlockIsIntegrityViolation && _knownBlockVersions.blockShouldExist(key)) { integrityViolationDetected("A block that should exist wasn't found. Did an attacker delete it?"); } - return boost::none; + return boost::optional(boost::none); } - if (!_checkHeader(key, *loaded)) { - return boost::none; - } - return *loaded; + _checkHeader(key, *loaded); + return boost::optional(_removeHeader(*loaded)); }); } boost::future store(const Key &key, const cpputils::Data &data) override { _checkNoPastIntegrityViolations(); - TODO Need to load first so it can see if the version number changed by another - THIS BUG IS ALSO IN THE NEXT BRANCH (i.e. without these changes here) - //... + //TODO There's a bug in the next branch in override(). They have to load and read the old version number too. + return load(key).then([this, key, data = data.copy()] (boost::future> loaded_) { + auto loaded = loaded_.get(); + if (boost::none == loaded) { + return tryCreate(key, data).then([] (boost::future success) { + if (!success.get()) { + throw std::runtime_error("Could neither store nor create the block in VersionCountingBlockStore::store"); + } + }); + } + // Loading the block already read the newest version number into _knownBlockVersions, now we only have to increment it + // TODO Check that (with a caching blockstore below) this doesn't impact performance + uint64_t version = _knownBlockVersions.incrementVersion(key); + cpputils::Data dataWithHeader = _prependHeaderToData(_knownBlockVersions.myClientId(), version, data); + return _baseBlockStore->store(key, dataWithHeader); + }); } +private: + // This header is prepended to blocks to allow future versions to have compatibility. + static constexpr uint16_t FORMAT_VERSION_HEADER = 0; + +public: static constexpr uint64_t VERSION_ZERO = 0; static constexpr unsigned int CLIENTID_HEADER_OFFSET = sizeof(FORMAT_VERSION_HEADER); static constexpr unsigned int VERSION_HEADER_OFFSET = sizeof(FORMAT_VERSION_HEADER) + sizeof(uint32_t); @@ -62,10 +78,7 @@ public: private: - // This header is prepended to blocks to allow future versions to have compatibility. - static constexpr uint16_t FORMAT_VERSION_HEADER = 0; - - cpputils::Data VersionCountingBlock::_prependHeaderToData(uint32_t myClientId, uint64_t version, const cpputils::Data &data) { + cpputils::Data _prependHeaderToData(uint32_t myClientId, uint64_t version, const cpputils::Data &data) { static_assert(HEADER_LENGTH == sizeof(FORMAT_VERSION_HEADER) + sizeof(myClientId) + sizeof(version), "Wrong header length"); cpputils::Data result(data.size() + HEADER_LENGTH); std::memcpy(result.dataOffset(0), &FORMAT_VERSION_HEADER, sizeof(FORMAT_VERSION_HEADER)); @@ -75,32 +88,45 @@ private: return result; } - void _checkHeader(const Key &key, const cpputils::Data &data) { + void _checkHeader(const Key &key, const cpputils::Data &data) const { _checkFormatHeader(data); _checkVersionHeader(key, data); } - void _checkFormatHeader(const cpputils::Data &data) { + void _checkFormatHeader(const cpputils::Data &data) const { if (*reinterpret_cast(data.data()) != FORMAT_VERSION_HEADER) { throw std::runtime_error("The versioned block has the wrong format. Was it created with a newer version of CryFS?"); } } - void _checkVersionHeader(const Key &key, const cpputils::Data &data) { - uint32_t clientId; - std::memcpy(&clientId, _dataWithHeader.dataOffset(CLIENTID_HEADER_OFFSET), sizeof(clientId)); + void _checkVersionHeader(const Key &key, const cpputils::Data &data) const { + uint32_t clientId = _readClientId(data); + uint64_t version = _readVersion(data); - uint64_t version; - std::memcpy(&version, _dataWithHeader.dataOffset(VERSION_HEADER_OFFSET), sizeof(version)); - - if(!_knownBlockVersions.checkAndUpdateVersion(lastClientId, key, version)) { + if(!_knownBlockVersions.checkAndUpdateVersion(clientId, key, version)) { integrityViolationDetected("The block version number is too low. Did an attacker try to roll back the block or to re-introduce a deleted block?"); } } - void _checkNoPastIntegrityViolations() { + static uint32_t _readClientId(const cpputils::Data &data) { + uint32_t clientId; + std::memcpy(&clientId, data.dataOffset(CLIENTID_HEADER_OFFSET), sizeof(clientId)); + return clientId; + } + + static uint64_t _readVersion(const cpputils::Data &data) { + uint64_t version; + std::memcpy(&version, data.dataOffset(VERSION_HEADER_OFFSET), sizeof(version)); + return version; + } + + cpputils::Data _removeHeader(const cpputils::Data &data) const { + return data.copyAndRemovePrefix(HEADER_LENGTH); + } + + void _checkNoPastIntegrityViolations() const { if (_integrityViolationDetected) { - throw std::runtime_error(string() + + throw std::runtime_error(std::string() + "There was an integrity violation detected. Preventing any further access to the file system. " + "If you want to reset the integrity data (i.e. accept changes made by a potential attacker), " + "please unmount the file system and delete the following file before re-mounting it: " + @@ -108,13 +134,13 @@ private: } } - void integrityViolationDetected(const string &reason) const { + void integrityViolationDetected(const std::string &reason) const { _integrityViolationDetected = true; throw IntegrityViolationError(reason); } cpputils::unique_ref _baseBlockStore; - KnownBlockVersions _knownBlockVersions; + mutable KnownBlockVersions _knownBlockVersions; const bool _missingBlockIsIntegrityViolation; mutable bool _integrityViolationDetected; diff --git a/src/blockstore/interface/BlockStore2.h b/src/blockstore/interface/BlockStore2.h index 7f7a0699..26fb3e0e 100644 --- a/src/blockstore/interface/BlockStore2.h +++ b/src/blockstore/interface/BlockStore2.h @@ -10,6 +10,8 @@ #include #include +// TODO warn_unused_result for all boost::future interfaces + namespace blockstore { class BlockStore2 { diff --git a/src/cpp-utils/data/Data.h b/src/cpp-utils/data/Data.h index 4b805859..62e9c448 100644 --- a/src/cpp-utils/data/Data.h +++ b/src/cpp-utils/data/Data.h @@ -8,6 +8,7 @@ #include "../macros.h" #include #include +#include "../assert/assert.h" namespace cpputils { @@ -21,6 +22,9 @@ public: Data copy() const; + //TODO Test copyAndRemovePrefix + Data copyAndRemovePrefix(size_t prefixSize) const; + void *data(); const void *data() const; @@ -94,6 +98,13 @@ inline Data Data::copy() const { return copy; } +inline Data Data::copyAndRemovePrefix(size_t prefixSize) const { + ASSERT(prefixSize <= _size, "Can't remove more than there is"); + Data copy(_size - prefixSize); + std::memcpy(copy.data(), dataOffset(prefixSize), copy.size()); + return copy; +} + inline void *Data::data() { return const_cast(const_cast(this)->data()); } diff --git a/test/blockstore/implementations/encrypted/EncryptedBlockStoreTest_Generic.cpp b/test/blockstore/implementations/encrypted/EncryptedBlockStoreTest_Generic.cpp index e4c4362b..d27364ef 100644 --- a/test/blockstore/implementations/encrypted/EncryptedBlockStoreTest_Generic.cpp +++ b/test/blockstore/implementations/encrypted/EncryptedBlockStoreTest_Generic.cpp @@ -1,8 +1,11 @@ #include #include #include "blockstore/implementations/encrypted/EncryptedBlockStore.h" +#include "blockstore/implementations/encrypted/EncryptedBlockStore2.h" #include "blockstore/implementations/testfake/FakeBlockStore.h" +#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" #include "../../testutils/BlockStoreTest.h" +#include "../../testutils/BlockStore2Test.h" //TODO Move FakeAuthenticatedCipher out of test folder to normal folder. Dependencies should not point into tests of other modules. #include "../../../cpp-utils/crypto/symmetric/testutils/FakeAuthenticatedCipher.h" #include @@ -10,8 +13,11 @@ using ::testing::Test; using blockstore::BlockStore; +using blockstore::BlockStore2; using blockstore::encrypted::EncryptedBlockStore; +using blockstore::encrypted::EncryptedBlockStore2; using blockstore::testfake::FakeBlockStore; +using blockstore::inmemory::InMemoryBlockStore2; using cpputils::AES256_GCM; using cpputils::AES256_CFB; using cpputils::FakeAuthenticatedCipher; @@ -38,3 +44,21 @@ private: INSTANTIATE_TYPED_TEST_CASE_P(Encrypted_FakeCipher, BlockStoreTest, EncryptedBlockStoreTestFixture); INSTANTIATE_TYPED_TEST_CASE_P(Encrypted_AES256_GCM, BlockStoreTest, EncryptedBlockStoreTestFixture); INSTANTIATE_TYPED_TEST_CASE_P(Encrypted_AES256_CFB, BlockStoreTest, EncryptedBlockStoreTestFixture); + +template +class EncryptedBlockStore2TestFixture: public BlockStore2TestFixture { +public: + unique_ref createBlockStore() override { + return make_unique_ref>(make_unique_ref(), createKeyFixture()); + } + +private: + static typename Cipher::EncryptionKey createKeyFixture(int seed = 0) { + Data data = DataFixture::generate(Cipher::EncryptionKey::BINARY_LENGTH, seed); + return Cipher::EncryptionKey::FromBinary(data.data()); + } +}; + +INSTANTIATE_TYPED_TEST_CASE_P(Encrypted_FakeCipher, BlockStore2Test, EncryptedBlockStore2TestFixture); +INSTANTIATE_TYPED_TEST_CASE_P(Encrypted_AES256_GCM, BlockStore2Test, EncryptedBlockStore2TestFixture); +INSTANTIATE_TYPED_TEST_CASE_P(Encrypted_AES256_CFB, BlockStore2Test, EncryptedBlockStore2TestFixture); diff --git a/test/blockstore/implementations/inmemory/InMemoryBlockStoreTest.cpp b/test/blockstore/implementations/inmemory/InMemoryBlockStoreTest.cpp index ddac72d8..b2d033cf 100644 --- a/test/blockstore/implementations/inmemory/InMemoryBlockStoreTest.cpp +++ b/test/blockstore/implementations/inmemory/InMemoryBlockStoreTest.cpp @@ -1,14 +1,18 @@ #include "blockstore/implementations/inmemory/InMemoryBlock.h" #include "blockstore/implementations/inmemory/InMemoryBlockStore.h" +#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" #include "../../testutils/BlockStoreTest.h" +#include "../../testutils/BlockStore2Test.h" #include "../../testutils/BlockStoreWithRandomKeysTest.h" #include #include using blockstore::BlockStore; +using blockstore::BlockStore2; using blockstore::BlockStoreWithRandomKeys; using blockstore::inmemory::InMemoryBlockStore; +using blockstore::inmemory::InMemoryBlockStore2; using cpputils::unique_ref; using cpputils::make_unique_ref; @@ -29,3 +33,12 @@ public: }; INSTANTIATE_TYPED_TEST_CASE_P(InMemory, BlockStoreWithRandomKeysTest, InMemoryBlockStoreWithRandomKeysTestFixture); + +class InMemoryBlockStore2TestFixture: public BlockStore2TestFixture { +public: + unique_ref createBlockStore() override { + return make_unique_ref(); + } +}; + +INSTANTIATE_TYPED_TEST_CASE_P(InMemory, BlockStore2Test, InMemoryBlockStore2TestFixture); diff --git a/test/blockstore/implementations/ondisk/OnDiskBlockStoreTest_Generic.cpp b/test/blockstore/implementations/ondisk/OnDiskBlockStoreTest_Generic.cpp index f7936eba..a6f93be1 100644 --- a/test/blockstore/implementations/ondisk/OnDiskBlockStoreTest_Generic.cpp +++ b/test/blockstore/implementations/ondisk/OnDiskBlockStoreTest_Generic.cpp @@ -1,6 +1,8 @@ #include "blockstore/implementations/ondisk/OnDiskBlock.h" #include "blockstore/implementations/ondisk/OnDiskBlockStore.h" +#include "blockstore/implementations/ondisk/OnDiskBlockStore2.h" #include "../../testutils/BlockStoreTest.h" +#include "../../testutils/BlockStore2Test.h" #include "../../testutils/BlockStoreWithRandomKeysTest.h" #include @@ -10,6 +12,8 @@ using blockstore::BlockStore; using blockstore::BlockStoreWithRandomKeys; using blockstore::ondisk::OnDiskBlockStore; +using blockstore::BlockStore2; +using blockstore::ondisk::OnDiskBlockStore2; using cpputils::TempDir; using cpputils::unique_ref; @@ -40,3 +44,16 @@ private: }; INSTANTIATE_TYPED_TEST_CASE_P(OnDisk, BlockStoreWithRandomKeysTest, OnDiskBlockStoreWithRandomKeysTestFixture); + +class OnDiskBlockStore2TestFixture: public BlockStore2TestFixture { +public: + OnDiskBlockStore2TestFixture(): tempdir() {} + + unique_ref createBlockStore() override { + return make_unique_ref(tempdir.path()); + } +private: + TempDir tempdir; +}; + +INSTANTIATE_TYPED_TEST_CASE_P(OnDisk, BlockStore2Test, OnDiskBlockStore2TestFixture); diff --git a/test/blockstore/implementations/versioncounting/VersionCountingBlockStoreTest_Generic.cpp b/test/blockstore/implementations/versioncounting/VersionCountingBlockStoreTest_Generic.cpp index 19275fb1..aed9fb94 100644 --- a/test/blockstore/implementations/versioncounting/VersionCountingBlockStoreTest_Generic.cpp +++ b/test/blockstore/implementations/versioncounting/VersionCountingBlockStoreTest_Generic.cpp @@ -1,15 +1,21 @@ #include "blockstore/implementations/versioncounting/VersionCountingBlockStore.h" +#include "blockstore/implementations/versioncounting/VersionCountingBlockStore2.h" #include "blockstore/implementations/testfake/FakeBlockStore.h" +#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" #include "../../testutils/BlockStoreTest.h" +#include "../../testutils/BlockStore2Test.h" #include #include using ::testing::Test; using blockstore::BlockStore; +using blockstore::BlockStore2; using blockstore::versioncounting::VersionCountingBlockStore; +using blockstore::versioncounting::VersionCountingBlockStore2; using blockstore::versioncounting::KnownBlockVersions; using blockstore::testfake::FakeBlockStore; +using blockstore::inmemory::InMemoryBlockStore2; using cpputils::Data; using cpputils::DataFixture; @@ -17,16 +23,30 @@ using cpputils::make_unique_ref; using cpputils::unique_ref; using cpputils::TempFile; -template +template class VersionCountingBlockStoreTestFixture: public BlockStoreTestFixture { public: VersionCountingBlockStoreTestFixture() :stateFile(false) {} TempFile stateFile; unique_ref createBlockStore() override { - return make_unique_ref(make_unique_ref(), stateFile.path(), 0x12345678, SINGLECLIENT); + return make_unique_ref(make_unique_ref(), stateFile.path(), 0x12345678, MissingBlockIsIntegrityViolation); } }; INSTANTIATE_TYPED_TEST_CASE_P(VersionCounting_multiclient, BlockStoreTest, VersionCountingBlockStoreTestFixture); INSTANTIATE_TYPED_TEST_CASE_P(VersionCounting_singleclient, BlockStoreTest, VersionCountingBlockStoreTestFixture); + +template +class VersionCountingBlockStore2TestFixture: public BlockStore2TestFixture { +public: + VersionCountingBlockStore2TestFixture() :stateFile(false) {} + + TempFile stateFile; + unique_ref createBlockStore() override { + return make_unique_ref(make_unique_ref(), stateFile.path(), 0x12345678, MissingBlockIsIntegrityViolation); + } +}; + +INSTANTIATE_TYPED_TEST_CASE_P(VersionCounting_multiclient, BlockStore2Test, VersionCountingBlockStore2TestFixture); +INSTANTIATE_TYPED_TEST_CASE_P(VersionCounting_singleclient, BlockStore2Test, VersionCountingBlockStore2TestFixture); diff --git a/test/blockstore/testutils/BlockStore2Test.h b/test/blockstore/testutils/BlockStore2Test.h new file mode 100644 index 00000000..acd97636 --- /dev/null +++ b/test/blockstore/testutils/BlockStore2Test.h @@ -0,0 +1,263 @@ +#pragma once +#ifndef MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_TESTUTILS_BLOCKSTORE2TEST_H_ +#define MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_TESTUTILS_BLOCKSTORE2TEST_H_ + +#include +#include +#include +#include + +#include "blockstore/interface/BlockStore2.h" + +namespace boost { +inline void PrintTo(const optional &, ::std::ostream *os) { + *os << "optional"; +} +} + +class BlockStore2TestFixture { +public: + virtual ~BlockStore2TestFixture() {} + virtual cpputils::unique_ref createBlockStore() = 0; +}; + +template +class BlockStore2Test: public ::testing::Test { +public: + BlockStore2Test() :fixture(), blockStore(this->fixture.createBlockStore()) {} + + BOOST_STATIC_ASSERT_MSG( + (std::is_base_of::value), + "Given test fixture for instantiating the (type parameterized) BlockStoreTest must inherit from BlockStoreTestFixture" + ); + + ConcreteBlockStoreTestFixture fixture; + cpputils::unique_ref blockStore; +}; + +TYPED_TEST_CASE_P(BlockStore2Test); + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenCallingTryCreateOnExistingBlock_thenFails) { + blockstore::Key key = this->blockStore->create(cpputils::Data(1024)).get(); + EXPECT_FALSE(this->blockStore->tryCreate(key, cpputils::Data(1024)).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenCallingTryCreateOnNonExistingBlock_thenSucceeds) { + blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + EXPECT_TRUE(this->blockStore->tryCreate(key, cpputils::Data(1024)).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenCallingTryCreateOnNonExistingBlock_thenSucceeds) { + this->blockStore->create(cpputils::Data(512)); + blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + EXPECT_TRUE(this->blockStore->tryCreate(key, cpputils::Data(1024)).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenLoadExistingBlock_thenSucceeds) { + blockstore::Key key = this->blockStore->create(cpputils::Data(1024)).get(); + EXPECT_NE(boost::none, this->blockStore->load(key).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenLoadNonexistingBlock_thenFails) { + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + EXPECT_EQ(boost::none, this->blockStore->load(key).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenLoadNonexistingBlock_thenFails) { + this->blockStore->create(cpputils::Data(512)); + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + EXPECT_EQ(boost::none, this->blockStore->load(key).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringExistingBlock_thenSucceeds) { + blockstore::Key key = this->blockStore->create(cpputils::Data(1024)).get(); + this->blockStore->store(key, cpputils::Data(1024)).wait(); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenStoringNonexistingBlock_thenSucceeds) { + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + this->blockStore->store(key, cpputils::Data(1024)).wait(); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringNonexistingBlock_thenSucceeds) { + this->blockStore->create(cpputils::Data(512)); + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + this->blockStore->store(key, cpputils::Data(1024)).wait(); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenCreatingTwoBlocks_thenTheyGetDifferentKeys) { + blockstore::Key key1 = this->blockStore->create(cpputils::Data(1024)).get(); + blockstore::Key key2 = this->blockStore->create(cpputils::Data(1024)).get(); + EXPECT_NE(key1, key2); +} + +TYPED_TEST_P(BlockStore2Test, givenOtherwiseEmptyBlockStore_whenRemovingBlock_thenBlockIsNotLoadableAnymore) { + blockstore::Key key = this->blockStore->create(cpputils::Data(1024)).get(); + EXPECT_NE(boost::none, this->blockStore->load(key).get()); + this->blockStore->remove(key).get(); + EXPECT_EQ(boost::none, this->blockStore->load(key).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenRemovingBlock_thenBlockIsNotLoadableAnymore) { + blockstore::Key key = this->blockStore->create(cpputils::Data(1024)).get(); + this->blockStore->create(cpputils::Data(512)); + EXPECT_NE(boost::none, this->blockStore->load(key).get()); + this->blockStore->remove(key).get(); + EXPECT_EQ(boost::none, this->blockStore->load(key).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenOtherwiseEmptyBlockStore_whenRemovingExistingBlock_thenSucceeds) { + blockstore::Key key = this->blockStore->create(cpputils::Data(1024)).get(); + EXPECT_EQ(true, this->blockStore->remove(key).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenRemovingExistingBlock_thenSucceeds) { + blockstore::Key key = this->blockStore->create(cpputils::Data(1024)).get(); + this->blockStore->create(cpputils::Data(512)); + EXPECT_EQ(true, this->blockStore->remove(key).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenRemovingNonexistingBlock_thenFails) { + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + auto result = this->blockStore->remove(key).get(); + EXPECT_EQ(false, result); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads) { + auto key = this->blockStore->create(cpputils::Data(0)).get(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(0u, loaded.size()); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads) { + this->blockStore->create(cpputils::Data(512)); + auto key = this->blockStore->create(cpputils::Data(0)).get(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(0u, loaded.size()); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads) { + cpputils::Data data = cpputils::DataFixture::generate(1024); + auto key = this->blockStore->create(data.copy()).get(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(loaded, data); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads) { + this->blockStore->create(cpputils::Data(512)); + cpputils::Data data = cpputils::DataFixture::generate(1024); + auto key = this->blockStore->create(data.copy()).get(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(loaded, data); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenStoringAndLoadingNonExistingEmptyBlock_thenCorrectBlockLoads) { + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + this->blockStore->store(key, cpputils::Data(0)).wait(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(0u, loaded.size()); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringAndLoadingNonExistingEmptyBlock_thenCorrectBlockLoads) { + this->blockStore->create(cpputils::Data(512)); + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + this->blockStore->store(key, cpputils::Data(0)).wait(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(0u, loaded.size()); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenStoringAndLoadingNonExistingNonEmptyBlock_thenCorrectBlockLoads) { + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + cpputils::Data data = cpputils::DataFixture::generate(1024); + this->blockStore->store(key, data.copy()).wait(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(data, loaded); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringAndLoadingNonExistingNonEmptyBlock_thenCorrectBlockLoads) { + this->blockStore->create(cpputils::Data(512)); + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + cpputils::Data data = cpputils::DataFixture::generate(1024); + this->blockStore->store(key, data.copy()).wait(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(data, loaded); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenStoringAndLoadingExistingEmptyBlock_thenCorrectBlockLoads) { + auto key = this->blockStore->create(cpputils::Data(512)).get(); + this->blockStore->store(key, cpputils::Data(0)).wait(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(0u, loaded.size()); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringAndLoadingExistingEmptyBlock_thenCorrectBlockLoads) { + this->blockStore->create(cpputils::Data(512)).get(); + auto key = this->blockStore->create(cpputils::Data(512)).get(); + this->blockStore->store(key, cpputils::Data(0)).wait(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(0u, loaded.size()); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenStoringAndLoadingExistingNonEmptyBlock_thenCorrectBlockLoads) { + auto key = this->blockStore->create(cpputils::Data(512)).get(); + cpputils::Data data = cpputils::DataFixture::generate(1024); + this->blockStore->store(key, data.copy()).wait(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(data, loaded); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringAndLoadingExistingNonEmptyBlock_thenCorrectBlockLoads) { + this->blockStore->create(cpputils::Data(512)).get(); + auto key = this->blockStore->create(cpputils::Data(512)).get(); + cpputils::Data data = cpputils::DataFixture::generate(1024); + this->blockStore->store(key, data.copy()).wait(); + auto loaded = this->blockStore->load(key).get().value(); + EXPECT_EQ(data, loaded); +} + +TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenLoadingNonExistingBlock_thenFails) { + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + EXPECT_EQ(boost::none, this->blockStore->load(key).get()); +} + +TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenLoadingNonExistingBlock_thenFails) { + this->blockStore->create(cpputils::Data(512)).get(); + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + EXPECT_EQ(boost::none, this->blockStore->load(key).get()); +} + + +REGISTER_TYPED_TEST_CASE_P(BlockStore2Test, + givenNonEmptyBlockStore_whenCallingTryCreateOnExistingBlock_thenFails, + givenEmptyBlockStore_whenCallingTryCreateOnNonExistingBlock_thenSucceeds, + givenNonEmptyBlockStore_whenCallingTryCreateOnNonExistingBlock_thenSucceeds, + givenNonEmptyBlockStore_whenLoadExistingBlock_thenSucceeds, + givenEmptyBlockStore_whenLoadNonexistingBlock_thenFails, + givenNonEmptyBlockStore_whenLoadNonexistingBlock_thenFails, + givenNonEmptyBlockStore_whenStoringExistingBlock_thenSucceeds, + givenEmptyBlockStore_whenStoringNonexistingBlock_thenSucceeds, + givenNonEmptyBlockStore_whenStoringNonexistingBlock_thenSucceeds, + givenEmptyBlockStore_whenCreatingTwoBlocks_thenTheyGetDifferentKeys, + givenOtherwiseEmptyBlockStore_whenRemovingBlock_thenBlockIsNotLoadableAnymore, + givenNonEmptyBlockStore_whenRemovingBlock_thenBlockIsNotLoadableAnymore, + givenOtherwiseEmptyBlockStore_whenRemovingExistingBlock_thenSucceeds, + givenNonEmptyBlockStore_whenRemovingExistingBlock_thenSucceeds, + givenEmptyBlockStore_whenRemovingNonexistingBlock_thenFails, + givenEmptyBlockStore_whenCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads, + givenNonEmptyBlockStore_whenCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads, + givenEmptyBlockStore_whenCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads, + givenNonEmptyBlockStore_whenCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads, + givenEmptyBlockStore_whenStoringAndLoadingNonExistingEmptyBlock_thenCorrectBlockLoads, + givenNonEmptyBlockStore_whenStoringAndLoadingNonExistingEmptyBlock_thenCorrectBlockLoads, + givenEmptyBlockStore_whenStoringAndLoadingNonExistingNonEmptyBlock_thenCorrectBlockLoads, + givenNonEmptyBlockStore_whenStoringAndLoadingNonExistingNonEmptyBlock_thenCorrectBlockLoads, + givenEmptyBlockStore_whenStoringAndLoadingExistingEmptyBlock_thenCorrectBlockLoads, + givenNonEmptyBlockStore_whenStoringAndLoadingExistingEmptyBlock_thenCorrectBlockLoads, + givenEmptyBlockStore_whenStoringAndLoadingExistingNonEmptyBlock_thenCorrectBlockLoads, + givenNonEmptyBlockStore_whenStoringAndLoadingExistingNonEmptyBlock_thenCorrectBlockLoads, + givenEmptyBlockStore_whenLoadingNonExistingBlock_thenFails, + givenNonEmptyBlockStore_whenLoadingNonExistingBlock_thenFails +); + + +#endif