2014-12-09 17:19:59 +01:00
# pragma once
# ifndef TEST_BLOCKSTORE_IMPLEMENTATIONS_TESTUTILS_BLOCKSTORETEST_H_
# define TEST_BLOCKSTORE_IMPLEMENTATIONS_TESTUTILS_BLOCKSTORETEST_H_
2015-02-17 00:23:33 +01:00
# include "google/gtest/gtest.h"
# include "DataBlockFixture.h"
# include "../../interface/BlockStore.h"
2014-12-09 17:19:59 +01:00
class BlockStoreTestFixture {
public :
virtual std : : unique_ptr < blockstore : : BlockStore > createBlockStore ( ) = 0 ;
} ;
template < class ConcreteBlockStoreTestFixture >
class BlockStoreTest : public : : testing : : Test {
public :
BOOST_STATIC_ASSERT_MSG (
( std : : is_base_of < BlockStoreTestFixture , ConcreteBlockStoreTestFixture > : : value ) ,
" Given test fixture for instantiating the (type parameterized) BlockStoreTest must inherit from BlockStoreTestFixture "
) ;
const std : : vector < size_t > SIZES = { 0 , 1 , 1024 , 4096 , 10 * 1024 * 1024 } ;
ConcreteBlockStoreTestFixture fixture ;
} ;
template < class ConcreateBlockStoreTestFixture >
class BlockStoreSizeParameterizedTest {
public :
BlockStoreSizeParameterizedTest ( ConcreateBlockStoreTestFixture & fixture , size_t size_ ) : blockStore ( fixture . createBlockStore ( ) ) , size ( size_ ) { }
void TestCreatedBlockHasCorrectSize ( ) {
auto block = blockStore - > create ( size ) ;
2015-01-24 22:27:14 +01:00
EXPECT_EQ ( size , block - > size ( ) ) ;
2014-12-09 17:19:59 +01:00
}
void TestLoadingUnchangedBlockHasCorrectSize ( ) {
auto block = blockStore - > create ( size ) ;
2015-01-24 22:27:14 +01:00
auto loaded_block = blockStore - > load ( block - > key ( ) ) ;
2014-12-09 17:19:59 +01:00
EXPECT_EQ ( size , loaded_block - > size ( ) ) ;
}
void TestCreatedBlockIsZeroedOut ( ) {
auto block = blockStore - > create ( size ) ;
2015-01-24 22:27:14 +01:00
EXPECT_EQ ( 0 , std : : memcmp ( ZEROES ( size ) . data ( ) , block - > data ( ) , size ) ) ;
2014-12-09 17:19:59 +01:00
}
void TestLoadingUnchangedBlockIsZeroedOut ( ) {
auto block = blockStore - > create ( size ) ;
2015-01-24 22:27:14 +01:00
auto loaded_block = blockStore - > load ( block - > key ( ) ) ;
2014-12-09 17:19:59 +01:00
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 ) ;
2014-12-09 20:57:10 +01:00
blockstore : : Key key = key ;
2014-12-09 17:19:59 +01:00
{
auto block = blockStore - > create ( size ) ;
2015-01-24 22:27:14 +01:00
key = block - > key ( ) ;
WriteDataToBlock ( block . get ( ) , randomData ) ;
2014-12-09 17:19:59 +01:00
}
auto loaded_block = blockStore - > load ( key ) ;
EXPECT_BLOCK_DATA_CORRECT ( * loaded_block , randomData ) ;
}
void TestAfterLoad_FlushesWhenDestructed ( ) {
DataBlockFixture randomData ( size ) ;
2014-12-09 20:57:10 +01:00
blockstore : : Key key = key ;
2014-12-09 17:19:59 +01:00
{
2015-01-24 22:27:14 +01:00
key = blockStore - > create ( size ) - > key ( ) ;
2014-12-09 17:19:59 +01:00
auto block = blockStore - > load ( key ) ;
WriteDataToBlock ( block . get ( ) , randomData ) ;
}
auto loaded_block = blockStore - > load ( key ) ;
EXPECT_BLOCK_DATA_CORRECT ( * loaded_block , randomData ) ;
}
2014-12-09 20:36:32 +01:00
void TestLoadNonExistingBlock ( ) {
2014-12-09 17:19:59 +01:00
EXPECT_FALSE (
2014-12-09 20:57:10 +01:00
( bool ) blockStore - > load ( key )
2014-12-09 17:19:59 +01:00
) ;
}
private :
2014-12-09 20:57:10 +01:00
const blockstore : : Key key = blockstore : : Key : : FromString ( " 1491BB4932A389EE14BC7090AC772972 " ) ;
2014-12-09 17:19:59 +01:00
std : : unique_ptr < blockstore : : BlockStore > blockStore ;
size_t size ;
blockstore : : Data ZEROES ( size_t size ) {
blockstore : : Data ZEROES ( size ) ;
ZEROES . FillWithZeroes ( ) ;
return ZEROES ;
}
std : : unique_ptr < blockstore : : Block > StoreDataToBlockAndLoadIt ( const DataBlockFixture & data ) {
2014-12-09 20:36:32 +01:00
blockstore : : Key key = StoreDataToBlockAndGetKey ( data ) ;
2014-12-09 17:19:59 +01:00
return blockStore - > load ( key ) ;
}
2014-12-09 20:36:32 +01:00
blockstore : : Key StoreDataToBlockAndGetKey ( const DataBlockFixture & data ) {
2014-12-09 17:19:59 +01:00
auto block = blockStore - > create ( data . size ( ) ) ;
2015-03-04 20:47:02 +01:00
block - > write ( data . data ( ) , 0 , data . size ( ) ) ;
2015-01-24 22:27:14 +01:00
return block - > key ( ) ;
2014-12-09 17:19:59 +01:00
}
std : : unique_ptr < blockstore : : Block > StoreDataToBlockAndLoadItDirectlyAfterFlushing ( const DataBlockFixture & data ) {
auto block = blockStore - > create ( data . size ( ) ) ;
2015-03-04 20:47:02 +01:00
block - > write ( data . data ( ) , 0 , data . size ( ) ) ;
2015-01-24 22:27:14 +01:00
block - > flush ( ) ;
return blockStore - > load ( block - > key ( ) ) ;
2014-12-09 17:19:59 +01:00
}
std : : unique_ptr < blockstore : : Block > CreateBlockAndLoadIt ( ) {
2015-01-24 22:27:14 +01:00
blockstore : : Key key = blockStore - > create ( size ) - > key ( ) ;
2014-12-09 17:19:59 +01:00
return blockStore - > load ( key ) ;
}
std : : unique_ptr < blockstore : : Block > CreateBlock ( ) {
2015-01-24 22:27:14 +01:00
return blockStore - > create ( size ) ;
2014-12-09 17:19:59 +01:00
}
void WriteDataToBlock ( blockstore : : Block * block , const DataBlockFixture & randomData ) {
2015-03-04 20:47:02 +01:00
block - > write ( randomData . data ( ) , 0 , randomData . size ( ) ) ;
2014-12-09 17:19:59 +01:00
}
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 < TypeParam > ( 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 ) ;
2014-12-09 20:36:32 +01:00
TYPED_TEST_P_FOR_ALL_SIZES ( LoadNonExistingBlock ) ;
2014-12-09 17:19:59 +01:00
TYPED_TEST_P ( BlockStoreTest , TwoCreatedBlocksHaveDifferentKeys ) {
auto blockStore = this - > fixture . createBlockStore ( ) ;
auto block1 = blockStore - > create ( 1024 ) ;
auto block2 = blockStore - > create ( 1024 ) ;
2015-01-24 22:27:14 +01:00
EXPECT_NE ( block1 - > key ( ) , block2 - > key ( ) ) ;
2014-12-09 17:19:59 +01:00
}
2015-02-22 00:29:21 +01:00
TYPED_TEST_P ( BlockStoreTest , BlockIsNotLoadableAfterDeleting ) {
auto blockStore = this - > fixture . createBlockStore ( ) ;
auto blockkey = blockStore - > create ( 1024 ) - > key ( ) ;
2015-02-22 16:53:49 +01:00
auto block = blockStore - > load ( blockkey ) ;
2015-02-24 17:37:39 +01:00
EXPECT_NE ( nullptr , block . get ( ) ) ;
2015-02-22 16:53:49 +01:00
blockStore - > remove ( std : : move ( block ) ) ;
2015-02-24 17:37:39 +01:00
EXPECT_EQ ( nullptr , blockStore - > load ( blockkey ) . get ( ) ) ;
2015-02-22 00:29:21 +01:00
}
2015-02-24 14:42:26 +01:00
TYPED_TEST_P ( BlockStoreTest , NumBlocksIsCorrectOnEmptyBlockstore ) {
auto blockStore = this - > fixture . createBlockStore ( ) ;
EXPECT_EQ ( 0 , blockStore - > numBlocks ( ) ) ;
}
TYPED_TEST_P ( BlockStoreTest , NumBlocksIsCorrectAfterAddingOneBlock ) {
auto blockStore = this - > fixture . createBlockStore ( ) ;
blockStore - > create ( 1 ) ;
EXPECT_EQ ( 1 , blockStore - > numBlocks ( ) ) ;
}
TYPED_TEST_P ( BlockStoreTest , NumBlocksIsCorrectAfterRemovingTheLastBlock ) {
auto blockStore = this - > fixture . createBlockStore ( ) ;
auto block = blockStore - > create ( 1 ) ;
blockStore - > remove ( std : : move ( block ) ) ;
EXPECT_EQ ( 0 , blockStore - > numBlocks ( ) ) ;
}
TYPED_TEST_P ( BlockStoreTest , NumBlocksIsCorrectAfterAddingTwoBlocks ) {
auto blockStore = this - > fixture . createBlockStore ( ) ;
blockStore - > create ( 1 ) ;
blockStore - > create ( 0 ) ;
EXPECT_EQ ( 2 , blockStore - > numBlocks ( ) ) ;
}
TYPED_TEST_P ( BlockStoreTest , NumBlocksIsCorrectAfterRemovingABlock ) {
auto blockStore = this - > fixture . createBlockStore ( ) ;
auto block = blockStore - > create ( 1 ) ;
blockStore - > create ( 1 ) ;
blockStore - > remove ( std : : move ( block ) ) ;
EXPECT_EQ ( 1 , blockStore - > numBlocks ( ) ) ;
}
2014-12-09 17:19:59 +01:00
REGISTER_TYPED_TEST_CASE_P ( BlockStoreTest ,
CreatedBlockHasCorrectSize ,
LoadingUnchangedBlockHasCorrectSize ,
CreatedBlockIsZeroedOut ,
LoadingUnchangedBlockIsZeroedOut ,
LoadedBlockIsCorrect ,
LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing ,
AfterCreate_FlushingDoesntChangeBlock ,
AfterLoad_FlushingDoesntChangeBlock ,
AfterCreate_FlushesWhenDestructed ,
AfterLoad_FlushesWhenDestructed ,
2014-12-09 20:36:32 +01:00
LoadNonExistingBlock ,
2015-02-22 00:29:21 +01:00
TwoCreatedBlocksHaveDifferentKeys ,
2015-02-24 14:42:26 +01:00
BlockIsNotLoadableAfterDeleting ,
NumBlocksIsCorrectOnEmptyBlockstore ,
NumBlocksIsCorrectAfterAddingOneBlock ,
NumBlocksIsCorrectAfterRemovingTheLastBlock ,
NumBlocksIsCorrectAfterAddingTwoBlocks ,
NumBlocksIsCorrectAfterRemovingABlock
2014-12-09 17:19:59 +01:00
) ;
# endif
2015-03-06 02:28:41 +01:00
//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)