2015-03-08 02:15:31 +01:00
|
|
|
// This file is meant to be included by BlockStoreTest.h only
|
|
|
|
|
|
|
|
struct DataRange {
|
|
|
|
size_t blocksize;
|
|
|
|
off_t offset;
|
|
|
|
size_t count;
|
|
|
|
};
|
|
|
|
|
|
|
|
class BlockStoreDataParametrizedTest {
|
|
|
|
public:
|
|
|
|
BlockStoreDataParametrizedTest(std::unique_ptr<blockstore::BlockStore> blockStore_, const DataRange &testData_)
|
|
|
|
: blockStore(std::move(blockStore_)),
|
|
|
|
testData(testData_),
|
2015-04-25 16:43:52 +02:00
|
|
|
foregroundData(cpputils::DataFixture::generate(testData.count, 0)),
|
|
|
|
backgroundData(cpputils::DataFixture::generate(testData.blocksize, 1)) {
|
2015-03-08 02:15:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestWriteAndReadImmediately() {
|
2015-04-25 02:48:41 +02:00
|
|
|
auto block = blockStore->create(cpputils::Data(testData.blocksize).FillWithZeroes());
|
2015-03-08 02:15:31 +01:00
|
|
|
block->write(foregroundData.data(), testData.offset, testData.count);
|
|
|
|
|
|
|
|
EXPECT_DATA_READS_AS(foregroundData, *block, testData.offset, testData.count);
|
|
|
|
EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(*block, testData.offset, testData.count);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestWriteAndReadAfterLoading() {
|
|
|
|
blockstore::Key key = CreateBlockWriteToItAndReturnKey(foregroundData);
|
|
|
|
|
2015-07-21 14:50:52 +02:00
|
|
|
auto loaded_block = blockStore->load(key).value();
|
2015-03-08 02:15:31 +01:00
|
|
|
EXPECT_DATA_READS_AS(foregroundData, *loaded_block, testData.offset, testData.count);
|
|
|
|
EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(*loaded_block, testData.offset, testData.count);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestOverwriteAndRead() {
|
2015-04-25 02:48:41 +02:00
|
|
|
auto block = blockStore->create(cpputils::Data(testData.blocksize));
|
2015-03-08 02:15:31 +01:00
|
|
|
block->write(backgroundData.data(), 0, testData.blocksize);
|
|
|
|
block->write(foregroundData.data(), testData.offset, testData.count);
|
|
|
|
EXPECT_DATA_READS_AS(foregroundData, *block, testData.offset, testData.count);
|
|
|
|
EXPECT_DATA_READS_AS_OUTSIDE_OF(backgroundData, *block, testData.offset, testData.count);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::unique_ptr<blockstore::BlockStore> blockStore;
|
|
|
|
DataRange testData;
|
2015-04-25 02:48:41 +02:00
|
|
|
cpputils::Data foregroundData;
|
|
|
|
cpputils::Data backgroundData;
|
2015-03-08 02:15:31 +01:00
|
|
|
|
2015-04-25 02:48:41 +02:00
|
|
|
blockstore::Key CreateBlockWriteToItAndReturnKey(const cpputils::Data &to_write) {
|
|
|
|
auto newblock = blockStore->create(cpputils::Data(testData.blocksize).FillWithZeroes());
|
2015-03-08 02:15:31 +01:00
|
|
|
|
|
|
|
newblock->write(to_write.data(), testData.offset, testData.count);
|
|
|
|
return newblock->key();
|
|
|
|
}
|
|
|
|
|
2015-04-25 02:48:41 +02:00
|
|
|
void EXPECT_DATA_READS_AS(const cpputils::Data &expected, const blockstore::Block &block, off_t offset, size_t count) {
|
|
|
|
cpputils::Data read(count);
|
2015-03-08 02:15:31 +01:00
|
|
|
std::memcpy(read.data(), (uint8_t*)block.data() + offset, count);
|
2015-04-25 17:17:06 +02:00
|
|
|
EXPECT_EQ(expected, read);
|
2015-03-08 02:15:31 +01:00
|
|
|
}
|
|
|
|
|
2015-04-25 02:48:41 +02:00
|
|
|
void EXPECT_DATA_READS_AS_OUTSIDE_OF(const cpputils::Data &expected, const blockstore::Block &block, off_t start, size_t count) {
|
|
|
|
cpputils::Data begin(start);
|
|
|
|
cpputils::Data end(testData.blocksize - count - start);
|
2015-03-08 02:15:31 +01:00
|
|
|
|
|
|
|
std::memcpy(begin.data(), expected.data(), start);
|
|
|
|
std::memcpy(end.data(), (uint8_t*)expected.data()+start+count, end.size());
|
|
|
|
|
|
|
|
EXPECT_DATA_READS_AS(begin, block, 0, start);
|
|
|
|
EXPECT_DATA_READS_AS(end, block, start + count, end.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
void EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(const blockstore::Block &block, off_t start, size_t count) {
|
2015-04-25 02:48:41 +02:00
|
|
|
cpputils::Data ZEROES(testData.blocksize);
|
2015-03-08 02:15:31 +01:00
|
|
|
ZEROES.FillWithZeroes();
|
|
|
|
EXPECT_DATA_READS_AS_OUTSIDE_OF(ZEROES, block, start, count);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
constexpr std::initializer_list<DataRange> DATA_RANGES = {
|
2015-06-21 14:40:57 +02:00
|
|
|
DataRange{1024, 0, 1024}, // full size leaf, access beginning to end
|
|
|
|
DataRange{1024, 100, 1024-200}, // full size leaf, access middle to middle
|
|
|
|
DataRange{1024, 0, 1024-100}, // full size leaf, access beginning to middle
|
|
|
|
DataRange{1024, 100, 1024-100}, // full size leaf, access middle to end
|
|
|
|
DataRange{1024-100, 0, 1024-100}, // non-full size leaf, access beginning to end
|
|
|
|
DataRange{1024-100, 100, 1024-300}, // non-full size leaf, access middle to middle
|
|
|
|
DataRange{1024-100, 0, 1024-200}, // non-full size leaf, access beginning to middle
|
|
|
|
DataRange{1024-100, 100, 1024-200} // non-full size leaf, access middle to end
|
2015-03-08 02:15:31 +01:00
|
|
|
};
|
|
|
|
#define TYPED_TEST_P_FOR_ALL_DATA_RANGES(TestName) \
|
|
|
|
TYPED_TEST_P(BlockStoreTest, TestName) { \
|
|
|
|
for (auto dataRange: DATA_RANGES) { \
|
|
|
|
BlockStoreDataParametrizedTest(this->fixture.createBlockStore(), dataRange) \
|
|
|
|
.Test##TestName(); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
TYPED_TEST_P_FOR_ALL_DATA_RANGES(WriteAndReadImmediately);
|
|
|
|
TYPED_TEST_P_FOR_ALL_DATA_RANGES(WriteAndReadAfterLoading);
|
|
|
|
TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteAndRead);
|