Rename blobstore to blockstore
This commit is contained in:
parent
c306d8be66
commit
93a624b228
@ -1,3 +0,0 @@
|
|||||||
add_subdirectory(interface)
|
|
||||||
add_subdirectory(utils)
|
|
||||||
add_subdirectory(implementations)
|
|
@ -1,2 +0,0 @@
|
|||||||
add_subdirectory(ondisk)
|
|
||||||
add_subdirectory(inmemory)
|
|
@ -1,3 +0,0 @@
|
|||||||
add_library(blobstore_inmemory InMemoryBlob.cpp InMemoryBlobStore.cpp)
|
|
||||||
|
|
||||||
target_link_libraries(blobstore_inmemory blobstore_interface blobstore_utils)
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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)
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||||||
add_library(blobstore_interface helpers/BlobStoreWithRandomKeys.cpp)
|
|
@ -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();
|
|
||||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||||||
add_library(blobstore_utils Data.cpp RandomKeyGenerator.cpp FileDoesntExistException.cpp)
|
|
||||||
|
|
||||||
target_link_libraries(blobstore_utils cryptopp)
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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);
|
|
@ -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);
|
|
@ -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()));
|
|
||||||
}
|
|
@ -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();
|
|
||||||
}
|
|
@ -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())
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
/*
|
|
||||||
* Tests that the header can be included without needing additional header includes as dependencies.
|
|
||||||
*/
|
|
||||||
#include "blobstore/interface/BlobStore.h"
|
|
@ -1,4 +0,0 @@
|
|||||||
/*
|
|
||||||
* Tests that the header can be included without needing additional header includes as dependencies.
|
|
||||||
*/
|
|
||||||
#include "blobstore/interface/Blob.h"
|
|
@ -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);
|
|
||||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
||||||
);
|
|
||||||
}
|
|
@ -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());
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user