Rename blobstore to blockstore

This commit is contained in:
Sebastian Messmer 2014-12-09 17:19:59 +01:00
parent c306d8be66
commit 93a624b228
39 changed files with 0 additions and 1738 deletions

View File

@ -1,3 +0,0 @@
add_subdirectory(interface)
add_subdirectory(utils)
add_subdirectory(implementations)

View File

@ -1,2 +0,0 @@
add_subdirectory(ondisk)
add_subdirectory(inmemory)

View File

@ -1,3 +0,0 @@
add_library(blobstore_inmemory InMemoryBlob.cpp InMemoryBlobStore.cpp)
target_link_libraries(blobstore_inmemory blobstore_interface blobstore_utils)

View File

@ -1,46 +0,0 @@
#include "InMemoryBlob.h"
#include "InMemoryBlobStore.h"
#include <cstring>
using std::unique_ptr;
using std::make_unique;
using std::make_shared;
using std::istream;
using std::ostream;
using std::ifstream;
using std::ofstream;
using std::ios;
namespace blobstore {
namespace inmemory {
InMemoryBlob::InMemoryBlob(size_t size)
: _data(make_shared<Data>(size)) {
_data->FillWithZeroes();
}
InMemoryBlob::InMemoryBlob(const InMemoryBlob &rhs)
: _data(rhs._data) {
}
InMemoryBlob::~InMemoryBlob() {
}
void *InMemoryBlob::data() {
return _data->data();
}
const void *InMemoryBlob::data() const {
return _data->data();
}
size_t InMemoryBlob::size() const {
return _data->size();
}
void InMemoryBlob::flush() {
}
} /* namespace inmemory */
} /* namespace blobstore */

View File

@ -1,32 +0,0 @@
#pragma once
#ifndef BLOBSTORE_IMPLEMENTATIONS_INMEMORY_INMEMORYBLOB_H_
#define BLOBSTORE_IMPLEMENTATIONS_INMEMORY_INMEMORYBLOB_H_
#include "blobstore/interface/Blob.h"
#include "blobstore/utils/Data.h"
namespace blobstore {
namespace inmemory {
class InMemoryBlobStore;
class InMemoryBlob: public Blob {
public:
InMemoryBlob(size_t size);
InMemoryBlob(const InMemoryBlob &rhs);
virtual ~InMemoryBlob();
void *data() override;
const void *data() const override;
void flush() override;
size_t size() const override;
private:
std::shared_ptr<Data> _data;
};
} /* namespace inmemory */
} /* namespace blobstore */
#endif

View File

@ -1,38 +0,0 @@
#include "InMemoryBlobStore.h"
#include "InMemoryBlob.h"
#include "blobstore/utils/RandomKeyGenerator.h"
using std::unique_ptr;
using std::make_unique;
using std::string;
using std::mutex;
using std::lock_guard;
namespace blobstore {
namespace inmemory {
InMemoryBlobStore::InMemoryBlobStore()
: _blobs() {}
unique_ptr<BlobWithKey> InMemoryBlobStore::create(const std::string &key, size_t size) {
auto insert_result = _blobs.emplace(key, size);
if (!insert_result.second) {
return nullptr;
}
//Return a copy of the stored InMemoryBlob
return make_unique<BlobWithKey>(key, make_unique<InMemoryBlob>(insert_result.first->second));
}
unique_ptr<Blob> InMemoryBlobStore::load(const string &key) {
//Return a copy of the stored InMemoryBlob
try {
return make_unique<InMemoryBlob>(_blobs.at(key));
} catch (const std::out_of_range &e) {
return nullptr;
}
}
} /* namespace ondisk */
} /* namespace blobstore */

View File

@ -1,32 +0,0 @@
#pragma once
#ifndef BLOBSTORE_IMPLEMENTATIONS_INMEMORY_INMEMORYBLOBSTORE_H_
#define BLOBSTORE_IMPLEMENTATIONS_INMEMORY_INMEMORYBLOBSTORE_H_
#include "blobstore/interface/helpers/BlobStoreWithRandomKeys.h"
#include "fspp/utils/macros.h"
#include <mutex>
#include <map>
namespace blobstore {
namespace inmemory {
class InMemoryBlob;
class InMemoryBlobStore: public BlobStoreWithRandomKeys {
public:
InMemoryBlobStore();
std::unique_ptr<BlobWithKey> create(const std::string &key, size_t size) override;
std::unique_ptr<Blob> load(const std::string &key) override;
private:
std::map<std::string, InMemoryBlob> _blobs;
DISALLOW_COPY_AND_ASSIGN(InMemoryBlobStore);
};
} /* namespace inmemory */
} /* namespace blobstore */
#endif

View File

@ -1,3 +0,0 @@
add_library(blobstore_ondisk OnDiskBlob.cpp OnDiskBlobStore.cpp FileAlreadyExistsException.cpp)
target_link_libraries(blobstore_ondisk blobstore_interface blobstore_utils boost_filesystem boost_system)

View File

@ -1,19 +0,0 @@
#include "FileAlreadyExistsException.h"
namespace bf = boost::filesystem;
using std::runtime_error;
using std::string;
namespace blobstore {
namespace ondisk {
FileAlreadyExistsException::FileAlreadyExistsException(const bf::path &filepath)
: runtime_error(string("The file ")+filepath.c_str()+" already exists") {
}
FileAlreadyExistsException::~FileAlreadyExistsException() {
}
} /* namespace ondisk */
} /* namespace blobstore */

View File

@ -1,21 +0,0 @@
#pragma once
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONDISK_FILEALREADYEXISTSEXCEPTION_H_
#define BLOBSTORE_IMPLEMENTATIONS_ONDISK_FILEALREADYEXISTSEXCEPTION_H_
#include <boost/filesystem/path.hpp>
#include <stdexcept>
namespace blobstore {
namespace ondisk {
class FileAlreadyExistsException: public std::runtime_error {
public:
FileAlreadyExistsException(const boost::filesystem::path &filepath);
virtual ~FileAlreadyExistsException();
};
} /* namespace ondisk */
} /* namespace blobstore */
#endif

View File

@ -1,87 +0,0 @@
#include "OnDiskBlob.h"
#include "OnDiskBlobStore.h"
#include "blobstore/implementations/ondisk/FileAlreadyExistsException.h"
#include "blobstore/utils/FileDoesntExistException.h"
#include <cstring>
#include <fstream>
#include <boost/filesystem.hpp>
using std::unique_ptr;
using std::make_unique;
using std::istream;
using std::ostream;
using std::ifstream;
using std::ofstream;
using std::ios;
namespace bf = boost::filesystem;
namespace blobstore {
namespace ondisk {
OnDiskBlob::OnDiskBlob(const bf::path &filepath, size_t size)
: _filepath(filepath), _data(size) {
}
OnDiskBlob::OnDiskBlob(const bf::path &filepath, Data &&data)
: _filepath(filepath), _data(std::move(data)) {
}
OnDiskBlob::~OnDiskBlob() {
_storeToDisk();
}
void *OnDiskBlob::data() {
return _data.data();
}
const void *OnDiskBlob::data() const {
return _data.data();
}
size_t OnDiskBlob::size() const {
return _data.size();
}
unique_ptr<OnDiskBlob> OnDiskBlob::LoadFromDisk(const bf::path &filepath) {
try {
//If it isn't a file, Data::LoadFromFile() would usually also crash. We still need this extra check
//upfront, because Data::LoadFromFile() doesn't crash if we give it the path of a directory
//instead the path of a file.
if(!bf::is_regular_file(filepath)) {
return nullptr;
}
Data data = Data::LoadFromFile(filepath);
return unique_ptr<OnDiskBlob>(new OnDiskBlob(filepath, std::move(data)));
} catch (const FileDoesntExistException &e) {
return nullptr;
}
}
unique_ptr<OnDiskBlob> OnDiskBlob::CreateOnDisk(const bf::path &filepath, size_t size) {
if (bf::exists(filepath)) {
return nullptr;
}
auto blob = unique_ptr<OnDiskBlob>(new OnDiskBlob(filepath, size));
blob->_fillDataWithZeroes();
blob->_storeToDisk();
return blob;
}
void OnDiskBlob::_fillDataWithZeroes() {
_data.FillWithZeroes();
}
void OnDiskBlob::_storeToDisk() const {
_data.StoreToFile(_filepath);
}
void OnDiskBlob::flush() {
_storeToDisk();
}
} /* namespace ondisk */
} /* namespace blobstore */

View File

@ -1,47 +0,0 @@
#pragma once
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONDISK_ONDISKBLOB_H_
#define BLOBSTORE_IMPLEMENTATIONS_ONDISK_ONDISKBLOB_H_
#include "blobstore/interface/Blob.h"
#include "blobstore/utils/Data.h"
#include <boost/filesystem/path.hpp>
#include <iostream>
#include "fspp/utils/macros.h"
namespace blobstore {
namespace ondisk {
class OnDiskBlobStore;
class OnDiskBlob: public Blob {
public:
virtual ~OnDiskBlob();
static std::unique_ptr<OnDiskBlob> LoadFromDisk(const boost::filesystem::path &filepath);
static std::unique_ptr<OnDiskBlob> CreateOnDisk(const boost::filesystem::path &filepath, size_t size);
void *data() override;
const void *data() const override;
void flush() override;
size_t size() const override;
private:
const boost::filesystem::path _filepath;
Data _data;
OnDiskBlob(const boost::filesystem::path &filepath, size_t size);
OnDiskBlob(const boost::filesystem::path &filepath, Data &&data);
void _fillDataWithZeroes();
void _storeToDisk() const;
DISALLOW_COPY_AND_ASSIGN(OnDiskBlob);
};
} /* namespace ondisk */
} /* namespace blobstore */
#endif

View File

@ -1,36 +0,0 @@
#include "OnDiskBlobStore.h"
#include "OnDiskBlob.h"
#include "blobstore/utils/RandomKeyGenerator.h"
using std::unique_ptr;
using std::make_unique;
using std::string;
using std::mutex;
using std::lock_guard;
namespace bf = boost::filesystem;
namespace blobstore {
namespace ondisk {
OnDiskBlobStore::OnDiskBlobStore(const boost::filesystem::path &rootdir)
: _rootdir(rootdir) {}
unique_ptr<BlobWithKey> OnDiskBlobStore::create(const std::string &key, size_t size) {
auto file_path = _rootdir / key;
auto blob = OnDiskBlob::CreateOnDisk(file_path, size);
if (!blob) {
return nullptr;
}
return make_unique<BlobWithKey>(key, std::move(blob));
}
unique_ptr<Blob> OnDiskBlobStore::load(const string &key) {
auto file_path = _rootdir / key;
return OnDiskBlob::LoadFromDisk(file_path);
}
} /* namespace ondisk */
} /* namespace blobstore */

View File

@ -1,32 +0,0 @@
#pragma once
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONDISK_ONDISKBLOBSTORE_H_
#define BLOBSTORE_IMPLEMENTATIONS_ONDISK_ONDISKBLOBSTORE_H_
#include "blobstore/interface/helpers/BlobStoreWithRandomKeys.h"
#include <boost/filesystem.hpp>
#include "fspp/utils/macros.h"
#include <mutex>
namespace blobstore {
namespace ondisk {
class OnDiskBlobStore: public BlobStoreWithRandomKeys {
public:
OnDiskBlobStore(const boost::filesystem::path &rootdir);
std::unique_ptr<BlobWithKey> create(const std::string &key, size_t size) override;
std::unique_ptr<Blob> load(const std::string &key) override;
private:
const boost::filesystem::path _rootdir;
DISALLOW_COPY_AND_ASSIGN(OnDiskBlobStore);
};
} /* namespace ondisk */
} /* namespace blobstore */
#endif

View File

@ -1,24 +0,0 @@
#pragma once
#ifndef BLOBSTORE_INTERFACE_BLOB_H_
#define BLOBSTORE_INTERFACE_BLOB_H_
#include <cstring>
namespace blobstore {
class Blob {
public:
virtual ~Blob() {}
virtual void *data() = 0;
virtual const void *data() const = 0;
virtual void flush() = 0;
virtual size_t size() const = 0;
};
}
#endif

View File

@ -1,29 +0,0 @@
#pragma once
#ifndef FSPP_BLOBSTORE_BLOBSTORE_H_
#define FSPP_BLOBSTORE_BLOBSTORE_H_
#include <string>
#include <memory>
#include "Blob.h"
#include "blobstore/utils/BlobWithKey.h"
namespace blobstore {
//TODO Don't use string, but own class for keys? (better performance for all keys have same length)
class BlobStore {
public:
virtual ~BlobStore() {}
virtual BlobWithKey create(size_t size) = 0;
//TODO Use boost::optional (if key doesn't exist)
// Return nullptr if blob with this key doesn't exists
virtual std::unique_ptr<Blob> load(const std::string &key) = 0;
//TODO Needed for performance? Or is deleting loaded blobs enough?
//virtual void remove(const std::string &key) = 0;
};
}
#endif

View File

@ -1 +0,0 @@
add_library(blobstore_interface helpers/BlobStoreWithRandomKeys.cpp)

View File

@ -1,20 +0,0 @@
#include "BlobStoreWithRandomKeys.h"
#include "blobstore/utils/RandomKeyGenerator.h"
using namespace blobstore;
using std::string;
BlobWithKey BlobStoreWithRandomKeys::create(size_t size) {
std::unique_ptr<BlobWithKey> result;
do {
result = create(_generateRandomKey(), size);
} while (!result);
return std::move(*result);
}
string BlobStoreWithRandomKeys::_generateRandomKey() {
return RandomKeyGenerator::singleton().create();
}

View File

@ -1,27 +0,0 @@
#pragma once
#ifndef FSPP_BLOBSTORE_BLOBSTOREWITHRANDOMKEYS_H_
#define FSPP_BLOBSTORE_BLOBSTOREWITHRANDOMKEYS_H_
#include "blobstore/interface/Blob.h"
#include "blobstore/interface/BlobStore.h"
namespace blobstore {
// This is an implementation helpers for BlobStores that use random blob keys.
// You should never give this static type to the client. The client should always
// work with the BlobStore interface instead.
class BlobStoreWithRandomKeys: public BlobStore {
public:
//TODO Use boost::optional (if key already exists)
// Return nullptr if key already exists
virtual std::unique_ptr<BlobWithKey> create(const std::string &key, size_t size) = 0;
BlobWithKey create(size_t size) final;
private:
std::string _generateRandomKey();
};
}
#endif

View File

@ -1,21 +0,0 @@
#pragma once
#ifndef BLOBSTORE_INTERFACE_BLOBWITHKEY_H_
#define BLOBSTORE_INTERFACE_BLOBWITHKEY_H_
#include "blobstore/interface/Blob.h"
#include <memory>
#include "fspp/utils/macros.h"
namespace blobstore {
struct BlobWithKey {
BlobWithKey(const std::string &key_, std::unique_ptr<Blob> blob_): key(key_), blob(std::move(blob_)) {}
std::string key;
std::unique_ptr<Blob> blob;
};
}
#endif

View File

@ -1,3 +0,0 @@
add_library(blobstore_utils Data.cpp RandomKeyGenerator.cpp FileDoesntExistException.cpp)
target_link_libraries(blobstore_utils cryptopp)

View File

@ -1,91 +0,0 @@
#include "Data.h"
#include "FileDoesntExistException.h"
#include <stdexcept>
#include <fstream>
using std::istream;
using std::ofstream;
using std::ifstream;
using std::ios;
using std::unique_ptr;
using std::make_unique;
namespace bf = boost::filesystem;
namespace blobstore {
Data::Data(size_t size)
: _size(size), _data(std::malloc(size)) {
if (nullptr == _data) {
throw std::bad_alloc();
}
}
Data::Data(Data &&rhs)
: _size(rhs._size), _data(rhs._data) {
// Make rhs invalid, so the memory doesn't get freed in its destructor.
rhs._data = nullptr;
}
Data::~Data() {
std::free(_data);
_data = nullptr;
}
void *Data::data() {
return const_cast<void*>(const_cast<const Data*>(this)->data());
}
const void *Data::data() const {
return _data;
}
size_t Data::size() const {
return _size;
}
void Data::FillWithZeroes() {
std::memset(_data, 0, _size);
}
void Data::StoreToFile(const bf::path &filepath) const {
ofstream file(filepath.c_str(), ios::binary | ios::trunc);
file.write((const char*)_data, _size);
}
Data Data::LoadFromFile(const bf::path &filepath) {
ifstream file(filepath.c_str(), ios::binary);
_assertFileExists(file, filepath);
size_t size = _getStreamSize(file);
Data result(size);
result._readFromStream(file);
return result;
}
void Data::_assertFileExists(const ifstream &file, const bf::path &filepath) {
if (!file.good()) {
throw FileDoesntExistException(filepath);
}
}
size_t Data::_getStreamSize(istream &stream) {
auto current_pos = stream.tellg();
//Retrieve length
stream.seekg(0, stream.end);
auto endpos = stream.tellg();
//Restore old position
stream.seekg(current_pos, stream.beg);
return endpos - current_pos;
}
void Data::_readFromStream(istream &stream) {
stream.read((char*)_data, _size);
}
} /* namespace blobstore */

View File

@ -1,43 +0,0 @@
#pragma once
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONDISK_DATA_H_
#define BLOBSTORE_IMPLEMENTATIONS_ONDISK_DATA_H_
#include <cstdlib>
//TODO Move this to a more generic utils
#include "fspp/utils/macros.h"
#include <boost/filesystem/path.hpp>
#include <memory>
namespace blobstore {
class Data {
public:
Data(size_t size);
Data(Data &&rhs); // move constructor
virtual ~Data();
void *data();
const void *data() const;
size_t size() const;
void FillWithZeroes();
void StoreToFile(const boost::filesystem::path &filepath) const;
static Data LoadFromFile(const boost::filesystem::path &filepath);
private:
size_t _size;
void *_data;
static void _assertFileExists(const std::ifstream &file, const boost::filesystem::path &filepath);
static size_t _getStreamSize(std::istream &stream);
void _readFromStream(std::istream &stream);
DISALLOW_COPY_AND_ASSIGN(Data);
};
} /* namespace blobstore */
#endif

View File

@ -1,17 +0,0 @@
#include "FileDoesntExistException.h"
namespace bf = boost::filesystem;
using std::runtime_error;
using std::string;
namespace blobstore {
FileDoesntExistException::FileDoesntExistException(const bf::path &filepath)
: runtime_error(string("The file ")+filepath.c_str()+" doesn't exist") {
}
FileDoesntExistException::~FileDoesntExistException() {
}
} /* namespace blobstore */

View File

@ -1,19 +0,0 @@
#pragma once
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONDISK_FILEDOESNTEXISTEXCEPTION_H_
#define BLOBSTORE_IMPLEMENTATIONS_ONDISK_FILEDOESNTEXISTEXCEPTION_H_
#include <boost/filesystem/path.hpp>
#include <stdexcept>
namespace blobstore {
class FileDoesntExistException: public std::runtime_error {
public:
FileDoesntExistException(const boost::filesystem::path &filepath);
virtual ~FileDoesntExistException();
};
} /* namespace blobstore */
#endif

View File

@ -1,53 +0,0 @@
#include "RandomKeyGenerator.h"
using std::string;
#include <crypto++/hex.h>
#include <crypto++/osrng.h>
using CryptoPP::AutoSeededRandomPool;
using CryptoPP::ArraySource;
using CryptoPP::StringSink;
using CryptoPP::HexEncoder;
using std::make_unique;
namespace blobstore {
constexpr unsigned int RandomKeyGenerator::KEYLENGTH_ENTROPY;
constexpr unsigned int RandomKeyGenerator::KEYLENGTH;
namespace {
string encodeKeyToHex(const byte *data);
}
RandomKeyGenerator::RandomKeyGenerator()
: _randomPool(make_unique<AutoSeededRandomPool>()) {
}
RandomKeyGenerator::~RandomKeyGenerator() {
}
RandomKeyGenerator &RandomKeyGenerator::singleton() {
static RandomKeyGenerator singleton;
return singleton;
}
string RandomKeyGenerator::create() {
byte key[KEYLENGTH_ENTROPY];
_randomPool->GenerateBlock(key, KEYLENGTH_ENTROPY);
return encodeKeyToHex(key);
}
namespace {
string encodeKeyToHex(const byte *data) {
string result;
ArraySource(data, RandomKeyGenerator::KEYLENGTH_ENTROPY, true,
new HexEncoder(new StringSink(result))
);
assert(result.size() == RandomKeyGenerator::KEYLENGTH);
return result;
}
}
} /* namespace blobstore */

View File

@ -1,37 +0,0 @@
#pragma once
#ifndef BLOBSTORE_IMPLEMENTATIONS_ONDISK_RANDOMKEYGENERATOR_H_
#define BLOBSTORE_IMPLEMENTATIONS_ONDISK_RANDOMKEYGENERATOR_H_
#include "fspp/utils/macros.h"
#include <memory>
namespace CryptoPP {
class AutoSeededRandomPool;
}
namespace blobstore {
// Creates random keys for use as block access handles.
// A key here is NOT a key for encryption, but a key as used in key->value mappings ("access handle for a block").
class RandomKeyGenerator {
public:
virtual ~RandomKeyGenerator();
static constexpr unsigned int KEYLENGTH_ENTROPY = 16; // random bytes in the key
static constexpr unsigned int KEYLENGTH = KEYLENGTH_ENTROPY * 2;
static RandomKeyGenerator &singleton();
std::string create();
private:
RandomKeyGenerator();
std::unique_ptr<CryptoPP::AutoSeededRandomPool> _randomPool;
DISALLOW_COPY_AND_ASSIGN(RandomKeyGenerator);
};
} /* namespace blobstore */
#endif

View File

@ -1,32 +0,0 @@
#include "gtest/gtest.h"
#include "blobstore/implementations/inmemory/InMemoryBlobStore.h"
#include "blobstore/implementations/inmemory/InMemoryBlob.h"
#include "test/blobstore/testutils/BlobStoreTest.h"
#include "test/blobstore/testutils/BlobStoreWithRandomKeysTest.h"
using blobstore::BlobStore;
using blobstore::BlobStoreWithRandomKeys;
using blobstore::inmemory::InMemoryBlobStore;
using std::unique_ptr;
using std::make_unique;
class InMemoryBlobStoreTestFixture: public BlobStoreTestFixture {
public:
unique_ptr<BlobStore> createBlobStore() override {
return make_unique<InMemoryBlobStore>();
}
};
INSTANTIATE_TYPED_TEST_CASE_P(InMemory, BlobStoreTest, InMemoryBlobStoreTestFixture);
class InMemoryBlobStoreWithRandomKeysTestFixture: public BlobStoreWithRandomKeysTestFixture {
public:
unique_ptr<BlobStoreWithRandomKeys> createBlobStore() override {
return make_unique<InMemoryBlobStore>();
}
};
INSTANTIATE_TYPED_TEST_CASE_P(InMemory, BlobStoreWithRandomKeysTest, InMemoryBlobStoreWithRandomKeysTestFixture);

View File

@ -1,36 +0,0 @@
#include "gtest/gtest.h"
#include "blobstore/implementations/ondisk/OnDiskBlobStore.h"
#include "blobstore/implementations/ondisk/OnDiskBlob.h"
#include "test/blobstore/testutils/BlobStoreTest.h"
#include "test/blobstore/testutils/BlobStoreWithRandomKeysTest.h"
using blobstore::BlobStore;
using blobstore::BlobStoreWithRandomKeys;
using blobstore::ondisk::OnDiskBlobStore;
using std::unique_ptr;
using std::make_unique;
class OnDiskBlobStoreTestFixture: public BlobStoreTestFixture {
public:
unique_ptr<BlobStore> createBlobStore() override {
return make_unique<OnDiskBlobStore>(tempdir.path());
}
private:
TempDir tempdir;
};
INSTANTIATE_TYPED_TEST_CASE_P(OnDisk, BlobStoreTest, OnDiskBlobStoreTestFixture);
class OnDiskBlobStoreWithRandomKeysTestFixture: public BlobStoreWithRandomKeysTestFixture {
public:
unique_ptr<BlobStoreWithRandomKeys> createBlobStore() override {
return make_unique<OnDiskBlobStore>(tempdir.path());
}
private:
TempDir tempdir;
};
INSTANTIATE_TYPED_TEST_CASE_P(OnDisk, BlobStoreWithRandomKeysTest, OnDiskBlobStoreWithRandomKeysTestFixture);

View File

@ -1,78 +0,0 @@
#include "gtest/gtest.h"
#include "test/testutils/TempFile.h"
#include "blobstore/implementations/ondisk/OnDiskBlob.h"
#include "blobstore/implementations/ondisk/FileAlreadyExistsException.h"
using ::testing::Test;
using ::testing::WithParamInterface;
using ::testing::Values;
using std::unique_ptr;
using namespace blobstore;
using namespace blobstore::ondisk;
namespace bf = boost::filesystem;
class OnDiskBlobCreateTest: public Test {
public:
OnDiskBlobCreateTest()
// Don't create the temp file yet (therefore pass false to the TempFile constructor)
: file(false) {
}
TempFile file;
};
TEST_F(OnDiskBlobCreateTest, CreatingBlobCreatesFile) {
EXPECT_FALSE(bf::exists(file.path()));
auto blob = OnDiskBlob::CreateOnDisk(file.path(), 0);
EXPECT_TRUE(bf::exists(file.path()));
EXPECT_TRUE(bf::is_regular_file(file.path()));
}
TEST_F(OnDiskBlobCreateTest, CreatingExistingBlobReturnsNull) {
auto blob1 = OnDiskBlob::CreateOnDisk(file.path(), 0);
auto blob2 = OnDiskBlob::CreateOnDisk(file.path(), 0);
EXPECT_TRUE((bool)blob1);
EXPECT_FALSE((bool)blob2);
}
class OnDiskBlobCreateSizeTest: public OnDiskBlobCreateTest, public WithParamInterface<size_t> {
public:
unique_ptr<OnDiskBlob> blob;
Data ZEROES;
OnDiskBlobCreateSizeTest():
blob(OnDiskBlob::CreateOnDisk(file.path(), GetParam())),
ZEROES(blob->size())
{
ZEROES.FillWithZeroes();
}
};
INSTANTIATE_TEST_CASE_P(OnDiskBlobCreateSizeTest, OnDiskBlobCreateSizeTest, Values(0, 1, 5, 1024, 10*1024*1024));
TEST_P(OnDiskBlobCreateSizeTest, OnDiskSizeIsCorrect) {
Data fileContent = Data::LoadFromFile(file.path());
EXPECT_EQ(GetParam(), fileContent.size());
}
TEST_P(OnDiskBlobCreateSizeTest, OnDiskBlobIsZeroedOut) {
Data fileContent = Data::LoadFromFile(file.path());
EXPECT_EQ(0, std::memcmp(ZEROES.data(), fileContent.data(), fileContent.size()));
}
// This test is also tested by OnDiskBlobStoreTest, but there the blob is created using the BlobStore interface.
// Here, we create it using OnDiskBlob::CreateOnDisk()
TEST_P(OnDiskBlobCreateSizeTest, InMemorySizeIsCorrect) {
EXPECT_EQ(GetParam(), blob->size());
}
// This test is also tested by OnDiskBlobStoreTest, but there the blob is created using the BlobStore interface.
// Here, we create it using OnDiskBlob::CreateOnDisk()
TEST_P(OnDiskBlobCreateSizeTest, InMemoryBlobIsZeroedOut) {
EXPECT_EQ(0, std::memcmp(ZEROES.data(), blob->data(), blob->size()));
}

View File

@ -1,111 +0,0 @@
#include <test/testutils/DataBlockFixture.h>
#include "gtest/gtest.h"
#include "test/testutils/TempFile.h"
#include "blobstore/implementations/ondisk/OnDiskBlob.h"
#include "blobstore/implementations/ondisk/FileAlreadyExistsException.h"
using ::testing::Test;
using ::testing::WithParamInterface;
using ::testing::Values;
using std::unique_ptr;
using namespace blobstore;
using namespace blobstore::ondisk;
namespace bf = boost::filesystem;
class OnDiskBlobFlushTest: public Test, public WithParamInterface<size_t> {
public:
OnDiskBlobFlushTest()
// Don't create the temp file yet (therefore pass false to the TempFile constructor)
: file(false), randomData(GetParam()) {
}
TempFile file;
DataBlockFixture randomData;
unique_ptr<OnDiskBlob> CreateBlobAndLoadItFromDisk() {
{
auto blob = OnDiskBlob::CreateOnDisk(file.path(), randomData.size());
}
return OnDiskBlob::LoadFromDisk(file.path());
}
unique_ptr<OnDiskBlob> CreateBlob() {
return OnDiskBlob::CreateOnDisk(file.path(), randomData.size());
}
void WriteDataToBlob(const unique_ptr<OnDiskBlob> &blob) {
std::memcpy(blob->data(), randomData.data(), randomData.size());
}
void EXPECT_BLOB_DATA_CORRECT(const unique_ptr<OnDiskBlob> &blob) {
EXPECT_EQ(randomData.size(), blob->size());
EXPECT_EQ(0, std::memcmp(randomData.data(), blob->data(), randomData.size()));
}
void EXPECT_STORED_FILE_DATA_CORRECT() {
Data actual = Data::LoadFromFile(file.path());
EXPECT_EQ(randomData.size(), actual.size());
EXPECT_EQ(0, std::memcmp(randomData.data(), actual.data(), randomData.size()));
}
};
INSTANTIATE_TEST_CASE_P(OnDiskBlobFlushTest, OnDiskBlobFlushTest, Values((size_t)0, (size_t)1, (size_t)1024, (size_t)4096, (size_t)10*1024*1024));
// This test is also tested by OnDiskBlobStoreTest, but there the blob is created using the BlobStore interface.
// Here, we create it using OnDiskBlob::CreateOnDisk()
TEST_P(OnDiskBlobFlushTest, AfterCreate_FlushingDoesntChangeBlob) {
auto blob = CreateBlob();
WriteDataToBlob(blob);
blob->flush();
EXPECT_BLOB_DATA_CORRECT(blob);
}
// This test is also tested by OnDiskBlobStoreTest, but there the blob is created using the BlobStore interface.
// Here, we create it using OnDiskBlob::CreateOnDisk() / OnDiskBlob::LoadFromDisk()
TEST_P(OnDiskBlobFlushTest, AfterLoad_FlushingDoesntChangeBlob) {
auto blob = CreateBlobAndLoadItFromDisk();
WriteDataToBlob(blob);
blob->flush();
EXPECT_BLOB_DATA_CORRECT(blob);
}
TEST_P(OnDiskBlobFlushTest, AfterCreate_FlushingWritesCorrectData) {
auto blob = CreateBlob();
WriteDataToBlob(blob);
blob->flush();
EXPECT_STORED_FILE_DATA_CORRECT();
}
TEST_P(OnDiskBlobFlushTest, AfterLoad_FlushingWritesCorrectData) {
auto blob = CreateBlobAndLoadItFromDisk();
WriteDataToBlob(blob);
blob->flush();
EXPECT_STORED_FILE_DATA_CORRECT();
}
// This test is also tested by OnDiskBlobStoreTest, but there it can only checks blob content by loading it again.
// Here, we check the content on disk.
TEST_P(OnDiskBlobFlushTest, AfterCreate_FlushesWhenDestructed) {
{
auto blob = CreateBlob();
WriteDataToBlob(blob);
}
EXPECT_STORED_FILE_DATA_CORRECT();
}
// This test is also tested by OnDiskBlobStoreTest, but there it can only checks blob content by loading it again.
// Here, we check the content on disk.
TEST_P(OnDiskBlobFlushTest, AfterLoad_FlushesWhenDestructed) {
{
auto blob = CreateBlobAndLoadItFromDisk();
WriteDataToBlob(blob);
}
EXPECT_STORED_FILE_DATA_CORRECT();
}

View File

@ -1,73 +0,0 @@
#include <test/testutils/DataBlockFixture.h>
#include "gtest/gtest.h"
#include "test/testutils/TempFile.h"
#include "blobstore/implementations/ondisk/OnDiskBlob.h"
#include "blobstore/utils/FileDoesntExistException.h"
#include "blobstore/utils/Data.h"
#include <fstream>
using ::testing::Test;
using ::testing::WithParamInterface;
using ::testing::Values;
using std::ofstream;
using std::unique_ptr;
using std::ios;
using namespace blobstore;
using namespace blobstore::ondisk;
namespace bf = boost::filesystem;
class OnDiskBlobLoadTest: public Test, public WithParamInterface<size_t> {
public:
TempFile file;
void SetFileSize(size_t size) {
Data data(size);
data.StoreToFile(file.path());
}
void StoreData(const DataBlockFixture &data) {
//TODO Implement data.StoreToFile(filepath) instead
Data dataobj(data.size());
std::memcpy(dataobj.data(), data.data(), data.size());
dataobj.StoreToFile(file.path());
}
unique_ptr<OnDiskBlob> LoadBlob() {
return OnDiskBlob::LoadFromDisk(file.path());
}
void EXPECT_BLOB_DATA_EQ(const DataBlockFixture &expected, const OnDiskBlob &actual) {
EXPECT_EQ(expected.size(), actual.size());
EXPECT_EQ(0, std::memcmp(expected.data(), actual.data(), expected.size()));
}
};
INSTANTIATE_TEST_CASE_P(OnDiskBlobLoadTest, OnDiskBlobLoadTest, Values(0, 1, 5, 1024, 10*1024*1024));
TEST_P(OnDiskBlobLoadTest, FileSizeIsCorrect) {
SetFileSize(GetParam());
auto blob = LoadBlob();
EXPECT_EQ(GetParam(), blob->size());
}
TEST_P(OnDiskBlobLoadTest, LoadedDataIsCorrect) {
DataBlockFixture randomData(GetParam());
StoreData(randomData);
auto blob = LoadBlob();
EXPECT_BLOB_DATA_EQ(randomData, *blob);
}
TEST_F(OnDiskBlobLoadTest, LoadNotExistingBlob) {
TempFile file2(false); // Pass false, so the file isn't created.
EXPECT_FALSE(
(bool)OnDiskBlob::LoadFromDisk(file2.path())
);
}

View File

@ -1,4 +0,0 @@
/*
* Tests that the header can be included without needing additional header includes as dependencies.
*/
#include "blobstore/interface/BlobStore.h"

View File

@ -1,4 +0,0 @@
/*
* Tests that the header can be included without needing additional header includes as dependencies.
*/
#include "blobstore/interface/Blob.h"

View File

@ -1,117 +0,0 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "blobstore/interface/helpers/BlobStoreWithRandomKeys.h"
#include "blobstore/utils/RandomKeyGenerator.h"
using ::testing::Test;
using ::testing::_;
using ::testing::Return;
using ::testing::Invoke;
using std::string;
using std::unique_ptr;
using std::make_unique;
using namespace blobstore;
class BlobStoreWithRandomKeysMock: public BlobStoreWithRandomKeys {
public:
unique_ptr<BlobWithKey> create(const std::string &key, size_t size) {
return unique_ptr<BlobWithKey>(do_create(key, size));
}
MOCK_METHOD2(do_create, BlobWithKey*(const std::string &, size_t));
unique_ptr<Blob> load(const string &key) {
return unique_ptr<Blob>(do_load(key));
}
MOCK_METHOD1(do_load, Blob*(const string &));
MOCK_METHOD1(exists, bool(const string &));
};
class BlobMock: public Blob {
public:
MOCK_METHOD0(data, void*());
MOCK_CONST_METHOD0(data, const void*());
MOCK_METHOD0(flush, void());
MOCK_CONST_METHOD0(size, size_t());
};
class BlobStoreWithRandomKeysTest: public Test {
public:
BlobStoreWithRandomKeysMock blobStoreMock;
BlobStore &blobStore = blobStoreMock;
};
TEST_F(BlobStoreWithRandomKeysTest, SizeIsPassedThrough0) {
EXPECT_CALL(blobStoreMock, do_create(_, 0)).WillOnce(Return(new BlobWithKey("", make_unique<BlobMock>())));
blobStore.create(0);
}
TEST_F(BlobStoreWithRandomKeysTest, SizeIsPassedThrough1) {
EXPECT_CALL(blobStoreMock, do_create(_, 1)).WillOnce(Return(new BlobWithKey("", make_unique<BlobMock>())));
blobStore.create(1);
}
TEST_F(BlobStoreWithRandomKeysTest, SizeIsPassedThrough1024) {
EXPECT_CALL(blobStoreMock, do_create(_, 1024)).WillOnce(Return(new BlobWithKey("", make_unique<BlobMock>())));
blobStore.create(1024);
}
TEST_F(BlobStoreWithRandomKeysTest, KeyHasCorrectSize) {
EXPECT_CALL(blobStoreMock, do_create(_, _)).WillOnce(Invoke([](const string &key, size_t) {
EXPECT_EQ(RandomKeyGenerator::KEYLENGTH, key.size());
return new BlobWithKey("", make_unique<BlobMock>());
}));
blobStore.create(1024);
}
TEST_F(BlobStoreWithRandomKeysTest, TwoBlobsGetDifferentKeys) {
string first_key;
EXPECT_CALL(blobStoreMock, do_create(_, _))
.WillOnce(Invoke([&first_key](const string &key, size_t) {
first_key = key;
return new BlobWithKey("", make_unique<BlobMock>());
}))
.WillOnce(Invoke([&first_key](const string &key, size_t) {
EXPECT_NE(first_key, key);
return new BlobWithKey("", make_unique<BlobMock>());
}));
blobStore.create(1024);
blobStore.create(1024);
}
TEST_F(BlobStoreWithRandomKeysTest, WillTryADifferentKeyIfKeyAlreadyExists) {
string first_key;
EXPECT_CALL(blobStoreMock, do_create(_, _))
.WillOnce(Invoke([&first_key](const string &key, size_t) {
first_key = key;
return nullptr;
}))
.WillOnce(Invoke([&first_key](const string &key, size_t) {
EXPECT_NE(first_key, key);
return new BlobWithKey("", make_unique<BlobMock>());
}));
blobStore.create(1024);
}
TEST_F(BlobStoreWithRandomKeysTest, WillTryADifferentKeyIfKeyAlreadyExistsTwoTimes) {
string first_key;
EXPECT_CALL(blobStoreMock, do_create(_, _))
.WillOnce(Invoke([&first_key](const string &key, size_t) {
first_key = key;
return nullptr;
}))
.WillOnce(Invoke([&first_key](const string &key, size_t) {
first_key = key;
return nullptr;
}))
.WillOnce(Invoke([&first_key](const string &key, size_t) {
EXPECT_NE(first_key, key);
return new BlobWithKey("", make_unique<BlobMock>());
}));
blobStore.create(1024);
}

View File

@ -1,226 +0,0 @@
#pragma once
#ifndef TEST_BLOBSTORE_IMPLEMENTATIONS_TESTUTILS_BLOBSTORETEST_H_
#define TEST_BLOBSTORE_IMPLEMENTATIONS_TESTUTILS_BLOBSTORETEST_H_
#include <test/testutils/DataBlockFixture.h>
#include "test/testutils/TempDir.h"
#include "blobstore/interface/BlobStore.h"
#include "blobstore/utils/RandomKeyGenerator.h"
class BlobStoreTestFixture {
public:
virtual std::unique_ptr<blobstore::BlobStore> createBlobStore() = 0;
};
template<class ConcreteBlobStoreTestFixture>
class BlobStoreTest: public ::testing::Test {
public:
BOOST_STATIC_ASSERT_MSG(
(std::is_base_of<BlobStoreTestFixture, ConcreteBlobStoreTestFixture>::value),
"Given test fixture for instantiating the (type parameterized) BlobStoreTest must inherit from BlobStoreTestFixture"
);
const std::vector<size_t> SIZES = {0, 1, 1024, 4096, 10*1024*1024};
ConcreteBlobStoreTestFixture fixture;
};
template<class ConcreateBlobStoreTestFixture>
class BlobStoreSizeParameterizedTest {
public:
BlobStoreSizeParameterizedTest(ConcreateBlobStoreTestFixture &fixture, size_t size_): blobStore(fixture.createBlobStore()), size(size_) {}
void TestCreatedBlobHasCorrectSize() {
auto blob = blobStore->create(size);
EXPECT_EQ(size, blob.blob->size());
}
void TestLoadingUnchangedBlobHasCorrectSize() {
auto blob = blobStore->create(size);
auto loaded_blob = blobStore->load(blob.key);
EXPECT_EQ(size, loaded_blob->size());
}
void TestCreatedBlobIsZeroedOut() {
auto blob = blobStore->create(size);
EXPECT_EQ(0, std::memcmp(ZEROES(size).data(), blob.blob->data(), size));
}
void TestLoadingUnchangedBlobIsZeroedOut() {
auto blob = blobStore->create(size);
auto loaded_blob = blobStore->load(blob.key);
EXPECT_EQ(0, std::memcmp(ZEROES(size).data(), loaded_blob->data(), size));
}
void TestLoadedBlobIsCorrect() {
DataBlockFixture randomData(size);
auto loaded_blob = StoreDataToBlobAndLoadIt(randomData);
EXPECT_EQ(size, loaded_blob->size());
EXPECT_EQ(0, std::memcmp(randomData.data(), loaded_blob->data(), size));
}
void TestLoadedBlobIsCorrectWhenLoadedDirectlyAfterFlushing() {
DataBlockFixture randomData(size);
auto loaded_blob = StoreDataToBlobAndLoadItDirectlyAfterFlushing(randomData);
EXPECT_EQ(size, loaded_blob->size());
EXPECT_EQ(0, std::memcmp(randomData.data(), loaded_blob->data(), size));
}
void TestAfterCreate_FlushingDoesntChangeBlob() {
DataBlockFixture randomData(size);
auto blob = CreateBlob();
WriteDataToBlob(blob.get(), randomData);
blob->flush();
EXPECT_BLOB_DATA_CORRECT(*blob, randomData);
}
void TestAfterLoad_FlushingDoesntChangeBlob() {
DataBlockFixture randomData(size);
auto blob = CreateBlobAndLoadIt();
WriteDataToBlob(blob.get(), randomData);
blob->flush();
EXPECT_BLOB_DATA_CORRECT(*blob, randomData);
}
void TestAfterCreate_FlushesWhenDestructed() {
DataBlockFixture randomData(size);
std::string key;
{
auto blob = blobStore->create(size);
key = blob.key;
WriteDataToBlob(blob.blob.get(), randomData);
}
auto loaded_blob = blobStore->load(key);
EXPECT_BLOB_DATA_CORRECT(*loaded_blob, randomData);
}
void TestAfterLoad_FlushesWhenDestructed() {
DataBlockFixture randomData(size);
std::string key;
{
key = blobStore->create(size).key;
auto blob = blobStore->load(key);
WriteDataToBlob(blob.get(), randomData);
}
auto loaded_blob = blobStore->load(key);
EXPECT_BLOB_DATA_CORRECT(*loaded_blob, randomData);
}
void TestLoadNonExistingBlobWithDefinitelyValidKey() {
EXPECT_FALSE(
(bool)blobStore->load(blobstore::RandomKeyGenerator::singleton().create())
);
}
void TestLoadNonExistingBlobWithMaybeInvalidKey() {
EXPECT_FALSE(
(bool)blobStore->load("not-existing-key")
);
}
void TestLoadNonExistingBlobWithEmptyKey() {
EXPECT_FALSE(
(bool)blobStore->load("")
);
}
private:
std::unique_ptr<blobstore::BlobStore> blobStore;
size_t size;
blobstore::Data ZEROES(size_t size) {
blobstore::Data ZEROES(size);
ZEROES.FillWithZeroes();
return ZEROES;
}
std::unique_ptr<blobstore::Blob> StoreDataToBlobAndLoadIt(const DataBlockFixture &data) {
std::string key = StoreDataToBlobAndGetKey(data);
return blobStore->load(key);
}
std::string StoreDataToBlobAndGetKey(const DataBlockFixture &data) {
auto blob = blobStore->create(data.size());
std::memcpy(blob.blob->data(), data.data(), data.size());
return blob.key;
}
std::unique_ptr<blobstore::Blob> StoreDataToBlobAndLoadItDirectlyAfterFlushing(const DataBlockFixture &data) {
auto blob = blobStore->create(data.size());
std::memcpy(blob.blob->data(), data.data(), data.size());
blob.blob->flush();
return blobStore->load(blob.key);
}
std::unique_ptr<blobstore::Blob> CreateBlobAndLoadIt() {
std::string key = blobStore->create(size).key;
return blobStore->load(key);
}
std::unique_ptr<blobstore::Blob> CreateBlob() {
return blobStore->create(size).blob;
}
void WriteDataToBlob(blobstore::Blob *blob, const DataBlockFixture &randomData) {
std::memcpy(blob->data(), randomData.data(), randomData.size());
}
void EXPECT_BLOB_DATA_CORRECT(const blobstore::Blob &blob, const DataBlockFixture &randomData) {
EXPECT_EQ(randomData.size(), blob.size());
EXPECT_EQ(0, std::memcmp(randomData.data(), blob.data(), randomData.size()));
}
};
TYPED_TEST_CASE_P(BlobStoreTest);
#define TYPED_TEST_P_FOR_ALL_SIZES(TestName) \
TYPED_TEST_P(BlobStoreTest, TestName) { \
for (auto size: this->SIZES) { \
BlobStoreSizeParameterizedTest<TypeParam>(this->fixture, size) \
.Test##TestName(); \
} \
} \
TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlobHasCorrectSize);
TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlobHasCorrectSize);
TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlobIsZeroedOut);
TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlobIsZeroedOut);
TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlobIsCorrect);
TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlobIsCorrectWhenLoadedDirectlyAfterFlushing);
TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushingDoesntChangeBlob);
TYPED_TEST_P_FOR_ALL_SIZES(AfterLoad_FlushingDoesntChangeBlob);
TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushesWhenDestructed);
TYPED_TEST_P_FOR_ALL_SIZES(AfterLoad_FlushesWhenDestructed);
TYPED_TEST_P_FOR_ALL_SIZES(LoadNonExistingBlobWithDefinitelyValidKey);
TYPED_TEST_P_FOR_ALL_SIZES(LoadNonExistingBlobWithMaybeInvalidKey);
TYPED_TEST_P_FOR_ALL_SIZES(LoadNonExistingBlobWithEmptyKey);
TYPED_TEST_P(BlobStoreTest, TwoCreatedBlobsHaveDifferentKeys) {
auto blobStore = this->fixture.createBlobStore();
auto blob1 = blobStore->create(1024);
auto blob2 = blobStore->create(1024);
EXPECT_NE(blob1.key, blob2.key);
}
REGISTER_TYPED_TEST_CASE_P(BlobStoreTest,
CreatedBlobHasCorrectSize,
LoadingUnchangedBlobHasCorrectSize,
CreatedBlobIsZeroedOut,
LoadingUnchangedBlobIsZeroedOut,
LoadedBlobIsCorrect,
LoadedBlobIsCorrectWhenLoadedDirectlyAfterFlushing,
AfterCreate_FlushingDoesntChangeBlob,
AfterLoad_FlushingDoesntChangeBlob,
AfterCreate_FlushesWhenDestructed,
AfterLoad_FlushesWhenDestructed,
LoadNonExistingBlobWithDefinitelyValidKey,
LoadNonExistingBlobWithMaybeInvalidKey,
LoadNonExistingBlobWithEmptyKey,
TwoCreatedBlobsHaveDifferentKeys
);
#endif

View File

@ -1,79 +0,0 @@
#pragma once
#ifndef TEST_BLOBSTORE_IMPLEMENTATIONS_TESTUTILS_BLOBSTOREWITHRANDOMKEYSTEST_H_
#define TEST_BLOBSTORE_IMPLEMENTATIONS_TESTUTILS_BLOBSTOREWITHRANDOMKEYSTEST_H_
#include <test/testutils/DataBlockFixture.h>
#include "test/testutils/TempDir.h"
#include "blobstore/interface/BlobStore.h"
#include "blobstore/utils/RandomKeyGenerator.h"
class BlobStoreWithRandomKeysTestFixture {
public:
virtual std::unique_ptr<blobstore::BlobStoreWithRandomKeys> createBlobStore() = 0;
};
template<class ConcreteBlobStoreWithRandomKeysTestFixture>
class BlobStoreWithRandomKeysTest: public ::testing::Test {
public:
BOOST_STATIC_ASSERT_MSG(
(std::is_base_of<BlobStoreWithRandomKeysTestFixture, ConcreteBlobStoreWithRandomKeysTestFixture>::value),
"Given test fixture for instantiating the (type parameterized) BlobStoreWithRandomKeysTest must inherit from BlobStoreWithRandomKeysTestFixture"
);
const std::vector<size_t> SIZES = {0, 1, 1024, 4096, 10*1024*1024};
ConcreteBlobStoreWithRandomKeysTestFixture fixture;
};
TYPED_TEST_CASE_P(BlobStoreWithRandomKeysTest);
TYPED_TEST_P(BlobStoreWithRandomKeysTest, CreateTwoBlobsWithSameKeyAndSameSize) {
auto blobStore = this->fixture.createBlobStore();
auto blob = blobStore->create("mykey", 1024);
auto blob2 = blobStore->create("mykey", 1024);
EXPECT_TRUE((bool)blob);
EXPECT_FALSE((bool)blob2);
}
TYPED_TEST_P(BlobStoreWithRandomKeysTest, CreateTwoBlobsWithSameKeyAndDifferentSize) {
auto blobStore = this->fixture.createBlobStore();
auto blob = blobStore->create("mykey", 1024);
auto blob2 = blobStore->create("mykey", 4096);
EXPECT_TRUE((bool)blob);
EXPECT_FALSE((bool)blob2);
}
TYPED_TEST_P(BlobStoreWithRandomKeysTest, CreateTwoBlobsWithSameKeyAndFirstNullSize) {
auto blobStore = this->fixture.createBlobStore();
auto blob = blobStore->create("mykey", 0);
auto blob2 = blobStore->create("mykey", 1024);
EXPECT_TRUE((bool)blob);
EXPECT_FALSE((bool)blob2);
}
TYPED_TEST_P(BlobStoreWithRandomKeysTest, CreateTwoBlobsWithSameKeyAndSecondNullSize) {
auto blobStore = this->fixture.createBlobStore();
auto blob = blobStore->create("mykey", 1024);
auto blob2 = blobStore->create("mykey", 0);
EXPECT_TRUE((bool)blob);
EXPECT_FALSE((bool)blob2);
}
TYPED_TEST_P(BlobStoreWithRandomKeysTest, CreateTwoBlobsWithSameKeyAndBothNullSize) {
auto blobStore = this->fixture.createBlobStore();
auto blob = blobStore->create("mykey", 0);
auto blob2 = blobStore->create("mykey", 0);
EXPECT_TRUE((bool)blob);
EXPECT_FALSE((bool)blob2);
}
REGISTER_TYPED_TEST_CASE_P(BlobStoreWithRandomKeysTest,
CreateTwoBlobsWithSameKeyAndSameSize,
CreateTwoBlobsWithSameKeyAndDifferentSize,
CreateTwoBlobsWithSameKeyAndFirstNullSize,
CreateTwoBlobsWithSameKeyAndSecondNullSize,
CreateTwoBlobsWithSameKeyAndBothNullSize
);
#endif

View File

@ -1,172 +0,0 @@
#include <test/testutils/DataBlockFixture.h>
#include "gtest/gtest.h"
#include "blobstore/utils/Data.h"
#include "blobstore/utils/FileDoesntExistException.h"
#include "test/testutils/TempFile.h"
#include <fstream>
using ::testing::Test;
using ::testing::WithParamInterface;
using ::testing::Values;
using std::ifstream;
using std::ofstream;
using namespace blobstore;
class DataTest: public Test {
public:
bool DataIsZeroes(const Data &data) {
for (size_t i = 0; i != data.size(); ++ i) {
if (((char*)data.data())[i] != 0) {
return false;
}
}
return true;
}
void FillData(const DataBlockFixture &fillData, Data *data) {
ASSERT_EQ(fillData.size(), data->size());
std::memcpy(data->data(), fillData.data(), fillData.size());
}
void EXPECT_DATA_CORRECT(const DataBlockFixture &expectedData, const Data &data) {
ASSERT_EQ(expectedData.size(), data.size());
EXPECT_EQ(0, std::memcmp(expectedData.data(), data.data(), expectedData.size()));
}
};
class DataTestWithSizeParam: public DataTest, public WithParamInterface<size_t> {
public:
DataBlockFixture randomData;
DataTestWithSizeParam(): randomData(GetParam()) {}
void FillData(Data *data) {
DataTest::FillData(randomData, data);
}
void StoreData(const bf::path &filepath) {
ofstream file(filepath.c_str(), std::ios::binary | std::ios::trunc);
file.write(randomData.data(), randomData.size());
}
void EXPECT_STORED_FILE_DATA_CORRECT(const bf::path &filepath) {
EXPECT_EQ(randomData.size(), bf::file_size(filepath));
ifstream file(filepath.c_str(), std::ios::binary);
char *read_data = new char[randomData.size()];
file.read(read_data, randomData.size());
EXPECT_EQ(0, std::memcmp(randomData.data(), read_data, randomData.size()));
delete[] read_data;
}
void EXPECT_DATA_CORRECT(const Data &data) {
DataTest::EXPECT_DATA_CORRECT(randomData, data);
}
};
INSTANTIATE_TEST_CASE_P(DataTestWithSizeParam, DataTestWithSizeParam, Values(0, 1, 2, 1024, 4096, 10*1024*1024));
// Working on a large data area without a crash is a good indicator that we
// are actually working on memory that was validly allocated for us.
TEST_P(DataTestWithSizeParam, WriteAndCheck) {
Data data(GetParam());
FillData(&data);
EXPECT_DATA_CORRECT(data);
}
TEST_P(DataTestWithSizeParam, Size) {
Data data(GetParam());
EXPECT_EQ(GetParam(), data.size());
}
TEST_P(DataTestWithSizeParam, CheckStoredFile) {
Data data(GetParam());
FillData(&data);
TempFile file;
data.StoreToFile(file.path());
EXPECT_STORED_FILE_DATA_CORRECT(file.path());
}
TEST_P(DataTestWithSizeParam, CheckLoadedData) {
TempFile file;
StoreData(file.path());
Data data = Data::LoadFromFile(file.path());
EXPECT_DATA_CORRECT(data);
}
TEST_P(DataTestWithSizeParam, StoreDoesntChangeData) {
Data data(GetParam());
FillData(&data);
TempFile file;
data.StoreToFile(file.path());
EXPECT_DATA_CORRECT(data);
}
TEST_P(DataTestWithSizeParam, StoreAndLoad) {
Data data(GetParam());
FillData(&data);
TempFile file;
data.StoreToFile(file.path());
Data loaded_data = Data::LoadFromFile(file.path());
EXPECT_DATA_CORRECT(loaded_data);
}
TEST_F(DataTest, InitializeWithZeroes) {
Data data(10*1024);
data.FillWithZeroes();
EXPECT_TRUE(DataIsZeroes(data));
}
TEST_F(DataTest, FillModifiedDataWithZeroes) {
Data data(10*1024);
DataBlockFixture randomData(10*1024);
FillData(randomData, &data);
EXPECT_FALSE(DataIsZeroes(data));
data.FillWithZeroes();
EXPECT_TRUE(DataIsZeroes(data));
}
//Needs 64bit for representation. This value isn't in the size param list, because the list is also used for read/write checks.
TEST_F(DataTest, LargesizeSize) {
size_t size = 10L*1024*1024*1024;
Data data(size);
EXPECT_EQ(size, data.size());
}
// This test doesn't ensure that the Data class gives the memory region free,
// but it is a good indicator.
TEST_F(DataTest, InaccessibleAfterDeletion) {
Data *data = new Data(1);
((char*)data->data())[0] = 0x3E; // Access data byte 0
delete data;
EXPECT_DEATH(
((char*)data->data())[0] = 0x3E,
""
);
}
TEST_F(DataTest, LoadingNonexistingFile) {
TempFile file(false); // Pass false to constructor, so the tempfile is not created
EXPECT_THROW(
Data::LoadFromFile(file.path()),
FileDoesntExistException
);
}

View File

@ -1,20 +0,0 @@
#include "gtest/gtest.h"
#include "blobstore/utils/RandomKeyGenerator.h"
using ::testing::Test;
using std::string;
using namespace blobstore;
class RandomKeyGeneratorTest: public Test {};
TEST_F(RandomKeyGeneratorTest, RunsWithoutCrashes) {
string result = RandomKeyGenerator::singleton().create();
}
TEST_F(RandomKeyGeneratorTest, KeySizeIsAsSpecified) {
string result = RandomKeyGenerator::singleton().create();
EXPECT_EQ(RandomKeyGenerator::KEYLENGTH, result.size());
}