From b13b9d86891adb5318f51a0d6b0132357349ebe1 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Sun, 8 Mar 2015 02:15:31 +0100 Subject: [PATCH] Added test cases for BlockStore::write() --- test/testutils/BlockStoreTest.h | 171 ++------------------------- test/testutils/BlockStoreTest_Data.h | 107 +++++++++++++++++ test/testutils/BlockStoreTest_Size.h | 158 +++++++++++++++++++++++++ 3 files changed, 273 insertions(+), 163 deletions(-) create mode 100644 test/testutils/BlockStoreTest_Data.h create mode 100644 test/testutils/BlockStoreTest_Size.h diff --git a/test/testutils/BlockStoreTest.h b/test/testutils/BlockStoreTest.h index ef90a08b..a6425eae 100644 --- a/test/testutils/BlockStoreTest.h +++ b/test/testutils/BlockStoreTest.h @@ -21,171 +21,11 @@ public: "Given test fixture for instantiating the (type parameterized) BlockStoreTest must inherit from BlockStoreTestFixture" ); - const std::vector SIZES = {0, 1, 1024, 4096, 10*1024*1024}; - ConcreteBlockStoreTestFixture fixture; }; -template -class BlockStoreSizeParameterizedTest { -public: - BlockStoreSizeParameterizedTest(ConcreateBlockStoreTestFixture &fixture, size_t size_): blockStore(fixture.createBlockStore()), size(size_) {} - - void TestCreatedBlockHasCorrectSize() { - auto block = blockStore->create(size); - EXPECT_EQ(size, block->size()); - } - - void TestLoadingUnchangedBlockHasCorrectSize() { - auto block = blockStore->create(size); - auto loaded_block = blockStore->load(block->key()); - EXPECT_EQ(size, loaded_block->size()); - } - - void TestCreatedBlockIsZeroedOut() { - auto block = blockStore->create(size); - EXPECT_EQ(0, std::memcmp(ZEROES(size).data(), block->data(), size)); - } - - void TestLoadingUnchangedBlockIsZeroedOut() { - auto block = blockStore->create(size); - auto loaded_block = blockStore->load(block->key()); - EXPECT_EQ(0, std::memcmp(ZEROES(size).data(), loaded_block->data(), size)); - } - - void TestLoadedBlockIsCorrect() { - DataBlockFixture randomData(size); - auto loaded_block = StoreDataToBlockAndLoadIt(randomData); - EXPECT_EQ(size, loaded_block->size()); - EXPECT_EQ(0, std::memcmp(randomData.data(), loaded_block->data(), size)); - } - - void TestLoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing() { - DataBlockFixture randomData(size); - auto loaded_block = StoreDataToBlockAndLoadItDirectlyAfterFlushing(randomData); - EXPECT_EQ(size, loaded_block->size()); - EXPECT_EQ(0, std::memcmp(randomData.data(), loaded_block->data(), size)); - } - - void TestAfterCreate_FlushingDoesntChangeBlock() { - DataBlockFixture randomData(size); - auto block = CreateBlock(); - WriteDataToBlock(block.get(), randomData); - block->flush(); - - EXPECT_BLOCK_DATA_CORRECT(*block, randomData); - } - - void TestAfterLoad_FlushingDoesntChangeBlock() { - DataBlockFixture randomData(size); - auto block = CreateBlockAndLoadIt(); - WriteDataToBlock(block.get(), randomData); - block->flush(); - - EXPECT_BLOCK_DATA_CORRECT(*block, randomData); - } - - void TestAfterCreate_FlushesWhenDestructed() { - DataBlockFixture randomData(size); - blockstore::Key key = key; - { - auto block = blockStore->create(size); - key = block->key(); - WriteDataToBlock(block.get(), randomData); - } - auto loaded_block = blockStore->load(key); - EXPECT_BLOCK_DATA_CORRECT(*loaded_block, randomData); - } - - void TestAfterLoad_FlushesWhenDestructed() { - DataBlockFixture randomData(size); - blockstore::Key key = key; - { - key = blockStore->create(size)->key(); - auto block = blockStore->load(key); - WriteDataToBlock(block.get(), randomData); - } - auto loaded_block = blockStore->load(key); - EXPECT_BLOCK_DATA_CORRECT(*loaded_block, randomData); - } - - void TestLoadNonExistingBlock() { - EXPECT_FALSE( - (bool)blockStore->load(key) - ); - } - -private: - const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); - std::unique_ptr blockStore; - size_t size; - - blockstore::Data ZEROES(size_t size) { - blockstore::Data ZEROES(size); - ZEROES.FillWithZeroes(); - return ZEROES; - } - - std::unique_ptr StoreDataToBlockAndLoadIt(const DataBlockFixture &data) { - blockstore::Key key = StoreDataToBlockAndGetKey(data); - return blockStore->load(key); - } - - blockstore::Key StoreDataToBlockAndGetKey(const DataBlockFixture &data) { - auto block = blockStore->create(data.size()); - block->write(data.data(), 0, data.size()); - return block->key(); - } - - std::unique_ptr StoreDataToBlockAndLoadItDirectlyAfterFlushing(const DataBlockFixture &data) { - auto block = blockStore->create(data.size()); - block->write(data.data(), 0, data.size()); - block->flush(); - return blockStore->load(block->key()); - } - - std::unique_ptr CreateBlockAndLoadIt() { - blockstore::Key key = blockStore->create(size)->key(); - return blockStore->load(key); - } - - std::unique_ptr CreateBlock() { - return blockStore->create(size); - } - - void WriteDataToBlock(blockstore::Block *block, const DataBlockFixture &randomData) { - block->write(randomData.data(), 0, randomData.size()); - } - - void EXPECT_BLOCK_DATA_CORRECT(const blockstore::Block &block, const DataBlockFixture &randomData) { - EXPECT_EQ(randomData.size(), block.size()); - EXPECT_EQ(0, std::memcmp(randomData.data(), block.data(), randomData.size())); - } -}; - TYPED_TEST_CASE_P(BlockStoreTest); -#define TYPED_TEST_P_FOR_ALL_SIZES(TestName) \ - TYPED_TEST_P(BlockStoreTest, TestName) { \ - for (auto size: this->SIZES) { \ - BlockStoreSizeParameterizedTest(this->fixture, size) \ - .Test##TestName(); \ - } \ - } \ - - -TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockHasCorrectSize); -TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockHasCorrectSize); -TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockIsZeroedOut); -TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockIsZeroedOut); -TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrect); -TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing); -TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushingDoesntChangeBlock); -TYPED_TEST_P_FOR_ALL_SIZES(AfterLoad_FlushingDoesntChangeBlock); -TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushesWhenDestructed); -TYPED_TEST_P_FOR_ALL_SIZES(AfterLoad_FlushesWhenDestructed); -TYPED_TEST_P_FOR_ALL_SIZES(LoadNonExistingBlock); - TYPED_TEST_P(BlockStoreTest, TwoCreatedBlocksHaveDifferentKeys) { auto blockStore = this->fixture.createBlockStore(); auto block1 = blockStore->create(1024); @@ -235,6 +75,10 @@ TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingABlock) { EXPECT_EQ(1, blockStore->numBlocks()); } +#include "BlockStoreTest_Size.h" +#include "BlockStoreTest_Data.h" + + REGISTER_TYPED_TEST_CASE_P(BlockStoreTest, CreatedBlockHasCorrectSize, LoadingUnchangedBlockHasCorrectSize, @@ -253,10 +97,11 @@ REGISTER_TYPED_TEST_CASE_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingOneBlock, NumBlocksIsCorrectAfterRemovingTheLastBlock, NumBlocksIsCorrectAfterAddingTwoBlocks, - NumBlocksIsCorrectAfterRemovingABlock + NumBlocksIsCorrectAfterRemovingABlock, + WriteAndReadImmediately, + WriteAndReadAfterLoading, + OverwriteAndRead ); #endif - -//TODO Add a test for write() writing and rereading parts of a block, rereading both immediately and after loading (similar to the one in messmer/blobstore/.../DataLeafTest) diff --git a/test/testutils/BlockStoreTest_Data.h b/test/testutils/BlockStoreTest_Data.h new file mode 100644 index 00000000..bcdfd8a8 --- /dev/null +++ b/test/testutils/BlockStoreTest_Data.h @@ -0,0 +1,107 @@ +// This file is meant to be included by BlockStoreTest.h only + +struct DataRange { + constexpr DataRange(size_t blocksize_, off_t offset_, size_t count_): blocksize(blocksize_), offset(offset_), count(count_) {} + size_t blocksize; + off_t offset; + size_t count; +}; + +class BlockStoreDataParametrizedTest { +public: + BlockStoreDataParametrizedTest(std::unique_ptr blockStore_, const DataRange &testData_) + : blockStore(std::move(blockStore_)), + testData(testData_), + foregroundData(testData.count), backgroundData(testData.blocksize) { + DataBlockFixture _foregroundData(testData.count); + DataBlockFixture _backgroundData(testData.blocksize); + std::memcpy(foregroundData.data(), _foregroundData.data(), foregroundData.size()); + std::memcpy(backgroundData.data(), _backgroundData.data(), backgroundData.size()); + } + + void TestWriteAndReadImmediately() { + auto block = blockStore->create(testData.blocksize); + 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); + + auto loaded_block = blockStore->load(key); + 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() { + auto block = blockStore->create(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); + } + +private: + std::unique_ptr blockStore; + DataRange testData; + blockstore::Data foregroundData; + blockstore::Data backgroundData; + + void EXPECT_DATA_EQ(const blockstore::Data &expected, const blockstore::Data &actual) { + EXPECT_EQ(expected.size(), actual.size()); + EXPECT_EQ(0, std::memcmp(expected.data(), actual.data(), expected.size())); + } + + blockstore::Key CreateBlockWriteToItAndReturnKey(const blockstore::Data &to_write) { + auto newblock = blockStore->create(testData.blocksize); + + newblock->write(to_write.data(), testData.offset, testData.count); + return newblock->key(); + } + + void EXPECT_DATA_READS_AS(const blockstore::Data &expected, const blockstore::Block &block, off_t offset, size_t count) { + blockstore::Data read(count); + std::memcpy(read.data(), (uint8_t*)block.data() + offset, count); + EXPECT_DATA_EQ(expected, read); + } + + void EXPECT_DATA_READS_AS_OUTSIDE_OF(const blockstore::Data &expected, const blockstore::Block &block, off_t start, size_t count) { + blockstore::Data begin(start); + blockstore::Data end(testData.blocksize - count - start); + + 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) { + blockstore::Data ZEROES(testData.blocksize); + ZEROES.FillWithZeroes(); + EXPECT_DATA_READS_AS_OUTSIDE_OF(ZEROES, block, start, count); + } +}; +constexpr std::initializer_list DATA_RANGES = { + 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(OverwriteAndRead); diff --git a/test/testutils/BlockStoreTest_Size.h b/test/testutils/BlockStoreTest_Size.h new file mode 100644 index 00000000..79c09c3f --- /dev/null +++ b/test/testutils/BlockStoreTest_Size.h @@ -0,0 +1,158 @@ +// This file is meant to be included by BlockStoreTest.h only + +class BlockStoreSizeParameterizedTest { +public: + BlockStoreSizeParameterizedTest(std::unique_ptr blockStore_, size_t size_): blockStore(std::move(blockStore_)), size(size_) {} + + void TestCreatedBlockHasCorrectSize() { + auto block = blockStore->create(size); + EXPECT_EQ(size, block->size()); + } + + void TestLoadingUnchangedBlockHasCorrectSize() { + auto block = blockStore->create(size); + auto loaded_block = blockStore->load(block->key()); + EXPECT_EQ(size, loaded_block->size()); + } + + void TestCreatedBlockIsZeroedOut() { + auto block = blockStore->create(size); + EXPECT_EQ(0, std::memcmp(ZEROES(size).data(), block->data(), size)); + } + + void TestLoadingUnchangedBlockIsZeroedOut() { + auto block = blockStore->create(size); + auto loaded_block = blockStore->load(block->key()); + EXPECT_EQ(0, std::memcmp(ZEROES(size).data(), loaded_block->data(), size)); + } + + void TestLoadedBlockIsCorrect() { + DataBlockFixture randomData(size); + auto loaded_block = StoreDataToBlockAndLoadIt(randomData); + EXPECT_EQ(size, loaded_block->size()); + EXPECT_EQ(0, std::memcmp(randomData.data(), loaded_block->data(), size)); + } + + void TestLoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing() { + DataBlockFixture randomData(size); + auto loaded_block = StoreDataToBlockAndLoadItDirectlyAfterFlushing(randomData); + EXPECT_EQ(size, loaded_block->size()); + EXPECT_EQ(0, std::memcmp(randomData.data(), loaded_block->data(), size)); + } + + void TestAfterCreate_FlushingDoesntChangeBlock() { + DataBlockFixture randomData(size); + auto block = CreateBlock(); + WriteDataToBlock(block.get(), randomData); + block->flush(); + + EXPECT_BLOCK_DATA_CORRECT(*block, randomData); + } + + void TestAfterLoad_FlushingDoesntChangeBlock() { + DataBlockFixture randomData(size); + auto block = CreateBlockAndLoadIt(); + WriteDataToBlock(block.get(), randomData); + block->flush(); + + EXPECT_BLOCK_DATA_CORRECT(*block, randomData); + } + + void TestAfterCreate_FlushesWhenDestructed() { + DataBlockFixture randomData(size); + blockstore::Key key = key; + { + auto block = blockStore->create(size); + key = block->key(); + WriteDataToBlock(block.get(), randomData); + } + auto loaded_block = blockStore->load(key); + EXPECT_BLOCK_DATA_CORRECT(*loaded_block, randomData); + } + + void TestAfterLoad_FlushesWhenDestructed() { + DataBlockFixture randomData(size); + blockstore::Key key = key; + { + key = blockStore->create(size)->key(); + auto block = blockStore->load(key); + WriteDataToBlock(block.get(), randomData); + } + auto loaded_block = blockStore->load(key); + EXPECT_BLOCK_DATA_CORRECT(*loaded_block, randomData); + } + + void TestLoadNonExistingBlock() { + EXPECT_FALSE( + (bool)blockStore->load(key) + ); + } + +private: + const blockstore::Key key = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972"); + std::unique_ptr blockStore; + size_t size; + + blockstore::Data ZEROES(size_t size) { + blockstore::Data ZEROES(size); + ZEROES.FillWithZeroes(); + return ZEROES; + } + + std::unique_ptr StoreDataToBlockAndLoadIt(const DataBlockFixture &data) { + blockstore::Key key = StoreDataToBlockAndGetKey(data); + return blockStore->load(key); + } + + blockstore::Key StoreDataToBlockAndGetKey(const DataBlockFixture &data) { + auto block = blockStore->create(data.size()); + block->write(data.data(), 0, data.size()); + return block->key(); + } + + std::unique_ptr StoreDataToBlockAndLoadItDirectlyAfterFlushing(const DataBlockFixture &data) { + auto block = blockStore->create(data.size()); + block->write(data.data(), 0, data.size()); + block->flush(); + return blockStore->load(block->key()); + } + + std::unique_ptr CreateBlockAndLoadIt() { + blockstore::Key key = blockStore->create(size)->key(); + return blockStore->load(key); + } + + std::unique_ptr CreateBlock() { + return blockStore->create(size); + } + + void WriteDataToBlock(blockstore::Block *block, const DataBlockFixture &randomData) { + block->write(randomData.data(), 0, randomData.size()); + } + + void EXPECT_BLOCK_DATA_CORRECT(const blockstore::Block &block, const DataBlockFixture &randomData) { + EXPECT_EQ(randomData.size(), block.size()); + EXPECT_EQ(0, std::memcmp(randomData.data(), block.data(), randomData.size())); + } +}; + +constexpr std::initializer_list SIZES = {0, 1, 1024, 4096, 10*1024*1024}; +#define TYPED_TEST_P_FOR_ALL_SIZES(TestName) \ + TYPED_TEST_P(BlockStoreTest, TestName) { \ + for (auto size: SIZES) { \ + BlockStoreSizeParameterizedTest(this->fixture.createBlockStore(), size) \ + .Test##TestName(); \ + } \ + } \ + +TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockHasCorrectSize); +TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockHasCorrectSize); +TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockIsZeroedOut); +TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockIsZeroedOut); +TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrect); +TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing); +TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushingDoesntChangeBlock); +TYPED_TEST_P_FOR_ALL_SIZES(AfterLoad_FlushingDoesntChangeBlock); +TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushesWhenDestructed); +TYPED_TEST_P_FOR_ALL_SIZES(AfterLoad_FlushesWhenDestructed); +TYPED_TEST_P_FOR_ALL_SIZES(LoadNonExistingBlock);