1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
#pragma once
#ifndef MESSMER_BLOCKSTORE_TEST_TESTUTILS_BLOCKSTORETEST_DATA_H_
#define MESSMER_BLOCKSTORE_TEST_TESTUTILS_BLOCKSTORETEST_DATA_H_
// This file is meant to be included by BlockStoreTest.h only
struct DataRange {
uint64_t blocksize;
uint64_t offset;
uint64_t count;
};
class BlockStoreDataParametrizedTest {
public:
BlockStoreDataParametrizedTest(cpputils::unique_ref<blockstore::BlockStore> blockStore_, const DataRange &testData_)
: blockStore(std::move(blockStore_)),
testData(testData_),
foregroundData(cpputils::DataFixture::generate(testData.count, 0)),
backgroundData(cpputils::DataFixture::generate(testData.blocksize, 1)) {
}
void TestWriteAndReadImmediately() {
auto block = blockStore->create(cpputils::Data(testData.blocksize).FillWithZeroes());
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() {
const blockstore::BlockId blockId = CreateBlockWriteToItAndReturnKey(foregroundData);
auto loaded_block = blockStore->load(blockId).value();
EXPECT_DATA_READS_AS(foregroundData, *loaded_block, testData.offset, testData.count);
EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(*loaded_block, testData.offset, testData.count);
}
void TestWriteTwiceAndRead() {
auto block = blockStore->create(cpputils::Data(testData.blocksize));
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);
}
void TestOverwriteSameSizeAndReadImmediately() {
auto blockId = blockStore->create(cpputils::Data(testData.blocksize))->blockId();
auto block = blockStore->overwrite(blockId, backgroundData.copy());
EXPECT_EQ(testData.blocksize, block->size());
EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize);
}
void TestOverwriteSameSizeAndReadAfterLoading() {
auto blockId = blockStore->create(cpputils::Data(testData.blocksize))->blockId();
blockStore->overwrite(blockId, backgroundData.copy());
auto block = blockStore->load(blockId).value();
EXPECT_EQ(testData.blocksize, block->size());
EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize);
}
void TestOverwriteSmallerSizeAndReadImmediately() {
auto blockId = blockStore->create(cpputils::Data(testData.blocksize))->blockId();
auto block = blockStore->overwrite(blockId, foregroundData.copy());
EXPECT_EQ(testData.count, block->size());
EXPECT_DATA_READS_AS(foregroundData, *block, 0, testData.count);
}
void TestOverwriteSmallerSizeAndReadAfterLoading() {
auto blockId = blockStore->create(cpputils::Data(testData.blocksize))->blockId();
blockStore->overwrite(blockId, foregroundData.copy());
auto block = blockStore->load(blockId).value();
EXPECT_EQ(testData.count, block->size());
EXPECT_DATA_READS_AS(foregroundData, *block, 0, testData.count);
}
void TestOverwriteLargerSizeAndReadImmediately() {
auto blockId = blockStore->create(cpputils::Data(testData.count))->blockId();
auto block = blockStore->overwrite(blockId, backgroundData.copy());
EXPECT_EQ(testData.blocksize, block->size());
EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize);
}
void TestOverwriteLargerSizeAndReadAfterLoading() {
auto blockId = blockStore->create(cpputils::Data(testData.count))->blockId();
blockStore->overwrite(blockId, backgroundData.copy());
auto block = blockStore->load(blockId).value();
EXPECT_EQ(testData.blocksize, block->size());
EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize);
}
void TestOverwriteNonexistingAndReadImmediately() {
auto blockId = blockStore->createBlockId();
auto block = blockStore->overwrite(blockId, backgroundData.copy());
EXPECT_EQ(testData.blocksize, block->size());
EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize);
}
void TestOverwriteNonexistingAndReadAfterLoading() {
auto blockId = blockStore->createBlockId();
blockStore->overwrite(blockId, backgroundData.copy());
auto block = blockStore->load(blockId).value();
EXPECT_EQ(testData.blocksize, block->size());
EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize);
}
private:
cpputils::unique_ref<blockstore::BlockStore> blockStore;
DataRange testData;
cpputils::Data foregroundData;
cpputils::Data backgroundData;
blockstore::BlockId CreateBlockWriteToItAndReturnKey(const cpputils::Data &to_write) {
auto newblock = blockStore->create(cpputils::Data(testData.blocksize).FillWithZeroes());
newblock->write(to_write.data(), testData.offset, testData.count);
return newblock->blockId();
}
void EXPECT_DATA_READS_AS(const cpputils::Data &expected, const blockstore::Block &block, uint64_t offset, uint64_t count) {
cpputils::Data read(count);
std::memcpy(read.data(), static_cast<const uint8_t*>(block.data()) + offset, count);
EXPECT_EQ(expected, read);
}
void EXPECT_DATA_READS_AS_OUTSIDE_OF(const cpputils::Data &expected, const blockstore::Block &block, uint64_t start, uint64_t count) {
cpputils::Data begin(start);
cpputils::Data end(testData.blocksize - count - start);
std::memcpy(begin.data(), expected.data(), start);
std::memcpy(end.data(), expected.dataOffset(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, uint64_t start, uint64_t count) {
cpputils::Data ZEROES(testData.blocksize);
ZEROES.FillWithZeroes();
EXPECT_DATA_READS_AS_OUTSIDE_OF(ZEROES, block, start, count);
}
};
inline std::vector<DataRange> DATA_RANGES() {
return {
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
};
};
#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(WriteTwiceAndRead);
TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteSameSizeAndReadImmediately);
TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteSameSizeAndReadAfterLoading);
TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteSmallerSizeAndReadImmediately);
TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteSmallerSizeAndReadAfterLoading);
TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteLargerSizeAndReadImmediately);
TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteLargerSizeAndReadAfterLoading);
TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteNonexistingAndReadImmediately);
TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteNonexistingAndReadAfterLoading);
#endif
|