#include "blockstore/interface/BlockStore2.h" #include #include #include using ::testing::Test; using ::testing::_; using ::testing::Return; using ::testing::Invoke; using ::testing::Eq; using ::testing::ByRef; using std::string; using cpputils::Data; using cpputils::DataFixture; using cpputils::unique_ref; using boost::optional; using namespace blockstore; class BlockStore2Mock: public BlockStore2 { public: MOCK_CONST_METHOD0(createBlockId, BlockId()); MOCK_METHOD2(tryCreate, bool(const BlockId &blockId, const cpputils::Data &data)); MOCK_METHOD2(store, void(const BlockId &, const Data &data)); MOCK_CONST_METHOD1(load, optional(const BlockId &)); MOCK_METHOD1(remove, bool(const BlockId &)); MOCK_CONST_METHOD0(numBlocks, uint64_t()); MOCK_CONST_METHOD0(estimateNumFreeBytes, uint64_t()); MOCK_CONST_METHOD1(blockSizeFromPhysicalBlockSize, uint64_t(uint64_t)); MOCK_CONST_METHOD1(forEachBlock, void(std::function)); }; class BlockStore2Test: public Test { public: BlockStore2Test() :blockStoreMock(), blockStore(blockStoreMock), blockId1(BlockId::FromString("1491BB4932A389EE14BC7090AC772972")), blockId2(BlockId::FromString("AC772971491BB4932A389EE14BC7090A")), blockId3(BlockId::FromString("1BB4932A38AC77C7090A2971499EE14B")) {} BlockStore2Mock blockStoreMock; BlockStore2 &blockStore; const BlockId blockId1; const BlockId blockId2; const BlockId blockId3; Data createDataWithSize(size_t size) { Data fixture(DataFixture::generate(size)); Data data(size); std::memcpy(data.data(), fixture.data(), size); return data; } }; TEST_F(BlockStore2Test, DataIsPassedThrough0) { Data data = createDataWithSize(0); EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); EXPECT_CALL(blockStoreMock, tryCreate(_, Eq(ByRef(data)))).WillOnce(Return(true)); EXPECT_EQ(blockId1, blockStore.create(data)); } TEST_F(BlockStore2Test, DataIsPassedThrough1) { Data data = createDataWithSize(1); EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); EXPECT_CALL(blockStoreMock, tryCreate(_, Eq(ByRef(data)))).WillOnce(Return(true)); EXPECT_EQ(blockId1, blockStore.create(data)); } TEST_F(BlockStore2Test, DataIsPassedThrough1024) { Data data = createDataWithSize(1024); EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); EXPECT_CALL(blockStoreMock, tryCreate(_, Eq(ByRef(data)))).WillOnce(Return(true)); EXPECT_EQ(blockId1, blockStore.create(data)); } TEST_F(BlockStore2Test, BlockIdIsCorrect) { Data data = createDataWithSize(1024); EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); EXPECT_CALL(blockStoreMock, tryCreate(blockId1, _)).WillOnce(Return(true)); EXPECT_EQ(blockId1, blockStore.create(data)); } TEST_F(BlockStore2Test, TwoBlocksGetDifferentIds) { EXPECT_CALL(blockStoreMock, createBlockId()) .WillOnce(Return(blockId1)) .WillOnce(Return(blockId2)); EXPECT_CALL(blockStoreMock, tryCreate(_, _)) .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { EXPECT_EQ(blockId1, blockId); return true; })) .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { EXPECT_EQ(blockId2, blockId); return true; })); Data data = createDataWithSize(1024); EXPECT_EQ(blockId1, blockStore.create(data)); EXPECT_EQ(blockId2, blockStore.create(data)); } TEST_F(BlockStore2Test, WillTryADifferentIdIfKeyAlreadyExists) { Data data = createDataWithSize(1024); EXPECT_CALL(blockStoreMock, createBlockId()) .WillOnce(Return(blockId1)) .WillOnce(Return(blockId2)); EXPECT_CALL(blockStoreMock, tryCreate(_, Eq(ByRef(data)))) .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { EXPECT_EQ(blockId1, blockId); return false; })) .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { EXPECT_EQ(blockId2, blockId); return true; })); EXPECT_EQ(blockId2, blockStore.create(data)); } TEST_F(BlockStore2Test, WillTryADifferentIdIfIdAlreadyExistsTwoTimes) { Data data = createDataWithSize(1024); EXPECT_CALL(blockStoreMock, createBlockId()) .WillOnce(Return(blockId1)) .WillOnce(Return(blockId2)) .WillOnce(Return(blockId3)); EXPECT_CALL(blockStoreMock, tryCreate(_, Eq(ByRef(data)))) .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { EXPECT_EQ(blockId1, blockId); return false; })) .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { EXPECT_EQ(blockId2, blockId); return false; })) .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { EXPECT_EQ(blockId3, blockId); return true; })); EXPECT_EQ(blockId3, blockStore.create(data)); }