diff --git a/src/blobstore/implementations/onblocks/impl/DataNodeView.h b/src/blobstore/implementations/onblocks/impl/DataNodeView.h index ceeb81e8..48b03ae5 100644 --- a/src/blobstore/implementations/onblocks/impl/DataNodeView.h +++ b/src/blobstore/implementations/onblocks/impl/DataNodeView.h @@ -8,13 +8,16 @@ #include "fspp/utils/macros.h" #include +#include namespace blobstore { namespace onblocks { class DataNodeView { public: - DataNodeView(std::unique_ptr block): _block(std::move(block)) {} + DataNodeView(std::unique_ptr block): _block(std::move(block)) { + assert(_block->size() == BLOCKSIZE_BYTES); + } virtual ~DataNodeView() {} DataNodeView(DataNodeView &&rhs) = default; @@ -73,18 +76,16 @@ public: return const_cast(const_cast(this)->DataEnd()); } -protected: - +private: template const Type *GetOffset() const { return (Type*)(((const int8_t*)_block->data())+offset); } -private: - DISALLOW_COPY_AND_ASSIGN(DataNodeView); - std::unique_ptr _block; + DISALLOW_COPY_AND_ASSIGN(DataNodeView); + }; } diff --git a/src/test/blobstore/implementations/onblocks/impl/DataNodeViewTest.cpp b/src/test/blobstore/implementations/onblocks/impl/DataNodeViewTest.cpp new file mode 100644 index 00000000..db4b74b7 --- /dev/null +++ b/src/test/blobstore/implementations/onblocks/impl/DataNodeViewTest.cpp @@ -0,0 +1,134 @@ +#include + +#include "blockstore/implementations/inmemory/InMemoryBlockStore.h" +#include "blockstore/implementations/inmemory/InMemoryBlock.h" +#include "blobstore/implementations/onblocks/BlobStoreOnBlocks.h" +#include "blobstore/implementations/onblocks/impl/DataNodeView.h" +#include "test/testutils/DataBlockFixture.h" + +using ::testing::Test; +using ::testing::WithParamInterface; +using ::testing::Values; +using std::unique_ptr; +using std::make_unique; +using std::string; + +using blockstore::BlockStore; +using blockstore::inmemory::InMemoryBlockStore; +using namespace blobstore; +using namespace blobstore::onblocks; + +class DataNodeViewTest: public Test { +public: + unique_ptr blockStore = make_unique(); +}; + +TEST_F(DataNodeViewTest, MagicNumberIsStored) { + auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE); + { + DataNodeView view(std::move(block.block)); + *view.MagicNumber() = 0x3F; + } + DataNodeView view(blockStore->load(block.key)); + EXPECT_EQ(0x3F, *view.MagicNumber()); +} + +class DataNodeViewSizeTest: public DataNodeViewTest, public WithParamInterface { +}; +INSTANTIATE_TEST_CASE_P(DataNodeViewSizeTest, DataNodeViewSizeTest, Values(0, 50, 64, 1024, 1024*1024*1024)); + +TEST_P(DataNodeViewSizeTest, SizeIsStored) { + auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE); + { + DataNodeView view(std::move(block.block)); + *view.Size() = GetParam(); + } + DataNodeView view(blockStore->load(block.key)); + EXPECT_EQ(GetParam(), *view.Size()); +} + +TEST_F(DataNodeViewTest, DataIsStored) { + DataBlockFixture randomData(DataNodeView::DATASIZE_BYTES); + auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE); + { + DataNodeView view(std::move(block.block)); + std::memcpy(view.DataBegin(), randomData.data(), DataNodeView::DATASIZE_BYTES); + } + DataNodeView view(blockStore->load(block.key)); + EXPECT_EQ(0, std::memcmp(view.DataBegin(), randomData.data(), DataNodeView::DATASIZE_BYTES)); +} + +TEST_F(DataNodeViewTest, HeaderAndBodyDontOverlap) { + DataBlockFixture randomData(DataNodeView::DATASIZE_BYTES); + auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE); + { + DataNodeView view(std::move(block.block)); + *view.MagicNumber() = 0xAA; + *view.Size() = 1000000000u; + std::memcpy(view.DataBegin(), randomData.data(), DataNodeView::DATASIZE_BYTES); + } + DataNodeView view(blockStore->load(block.key)); + EXPECT_EQ(0xAA, *view.MagicNumber()); + EXPECT_EQ(1000000000u, *view.Size()); + EXPECT_EQ(0, std::memcmp(view.DataBegin(), randomData.data(), DataNodeView::DATASIZE_BYTES)); +} + +TEST_F(DataNodeViewTest, DataBeginWorksWithOneByteEntries) { + auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE); + uint8_t *blockBegin = (uint8_t*)block.block->data(); + DataNodeView view(std::move(block.block)); + + EXPECT_EQ(blockBegin+view.HEADERSIZE_BYTES, view.DataBegin()); +} + +TEST_F(DataNodeViewTest, DataBeginWorksWithEightByteEntries) { + auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE); + uint8_t *blockBegin = (uint8_t*)block.block->data(); + DataNodeView view(std::move(block.block)); + + EXPECT_EQ(blockBegin+view.HEADERSIZE_BYTES, (uint8_t*)view.DataBegin()); +} + +TEST_F(DataNodeViewTest, DataEndWorksWithOneByteEntries) { + auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE); + uint8_t *blockBegin = (uint8_t*)block.block->data(); + DataNodeView view(std::move(block.block)); + + EXPECT_EQ(blockBegin+view.BLOCKSIZE_BYTES, view.DataEnd()); +} + +TEST_F(DataNodeViewTest, DataEndWorksWithEightByteEntries) { + auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE); + uint8_t *blockBegin = (uint8_t*)block.block->data(); + DataNodeView view(std::move(block.block)); + + EXPECT_EQ(blockBegin+view.BLOCKSIZE_BYTES, (uint8_t*)view.DataEnd()); +} + +struct SizedDataEntry { + uint8_t data[6]; +}; +BOOST_STATIC_ASSERT_MSG(DataNodeView::DATASIZE_BYTES % sizeof(SizedDataEntry) != 0, + "This test case only makes sense, if the data entries don't fill up the whole space. " + "There should be some space left at the end that is not used, because it isn't enough space for a full entry. " + "If this static assertion fails, please use a different size for SizedDataEntry."); + +TEST_F(DataNodeViewTest, DataBeginWorksWithStructEntries) { + auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE); + uint8_t *blockBegin = (uint8_t*)block.block->data(); + DataNodeView view(std::move(block.block)); + + EXPECT_EQ(blockBegin+view.HEADERSIZE_BYTES, (uint8_t*)view.DataBegin()); +} + +TEST_F(DataNodeViewTest, DataEndWorksWithStructByteEntries) { + auto block = blockStore->create(BlobStoreOnBlocks::BLOCKSIZE); + uint8_t *blockBegin = (uint8_t*)block.block->data(); + DataNodeView view(std::move(block.block)); + + unsigned int numFittingEntries = view.DATASIZE_BYTES / sizeof(SizedDataEntry); + + uint8_t *dataEnd = (uint8_t*)view.DataEnd(); + EXPECT_EQ(blockBegin+view.HEADERSIZE_BYTES + numFittingEntries * sizeof(SizedDataEntry), dataEnd); + EXPECT_LT(dataEnd, blockBegin + view.BLOCKSIZE_BYTES); +}