summaryrefslogblamecommitdiffstats
path: root/src/cowtest/main.c
blob: 1fdfc54ee78d6b3a94be33dd12bca4533695684f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11










                      
                        


                      
 






                             
 




                                


                                   
                                                                           
                                              
 




                                     
              
































                                                                                           
                                                
                                                                                                  
                                                                       
                                                                          
                                                         

                                                                                                                                                   




















                                                                              
                                                                      
                                             
                                                                  

























                                                                                         

















                                                                                                             
                      




                                                
                                                                                                             
                             
                                                                                                                 
                             

                        
                                           




                                                                                                                             


                    
                    
 


                                                






                                                                                                                 

                             



                                                                                                                             

                             

                                                                                                                                            
                             
                                 








                                                                                                                                           
                             
                                                                                                                   
                             
                                                     




                         




                                                                                                                                           
                             
                                                                                                          
                             


                                                                                        
                             











                                                                                                                    
                             

                                                                                                                   
                             

                                              




                    




                                                                                                                  
                             
                                                                                                        
                             

                                                                                                                      
                             











                                                                                                                            
                             
                                                                                                                           
                             
                                                        


                    


                                              




                                                                                                                            
                             
                                                                                                                  
                             


                                                                                                                                   
                             
                                             

 

















































                                                                                                                                       
 



                            
                                                                                    

                             
 
                                  




                                                                                         
                             
                                                                                                                     


                                                      


                                                                                                                                    
                             
                                                                                                                             
                             

                                                                                                                                          



                                                           
                                                                   




                                                                           
                                                                                    

                             
 
                                    
                                                     

 
                                                                                                                             
                             

                                                                                                       




                                                  



















                                                                                                                         


                                                




                                                                                                                       
                             
                                                                                                                

                             

                                                                                                                        

                             

                                                                                                                            


                                                                                   

                                                                                
 

                                                                                                                  

                             

                                                                                                                            

                                                                                   
                                       

 

                           




                                                                 
                                                                                                     






                                                                                      

                     




                                                                 

                                        








                                                                                                             
                                           
                                                         
                                       





                                      








                                                                       
 
                               


                                    



                                       



                                 

                                 
                                  

                       


                                              
 
 



                                             



                                        
                                                                                 



                                                                                                             

                                                                                                                          

                                                                                                                   

 






                                                                       












                                                                                                            
                                                                   





                                            
                              



                                           
 
 
                                     
                                                                                  
























                                                                                                          

 
 





























































































































































                                                                                                                                  


                                  
                         
                             
                         
         
                





























                                                                        

                                             










                                                                     

                 
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <stdint.h>
#include <dnbd3/types.h>
#include <stdatomic.h>
#include <time.h>
#include <pthread.h>

typedef bool ( *func_ptr )();
typedef struct verify_test
{
	off_t offset;
	size_t size;
	func_ptr test;
} verify_test_t;

typedef struct random_write_args
{
	char *mountedImage;
	char *normalImage;
} random_write_args_t;

const size_t l2Size = 1024;
const size_t bitfieldByteSize = 40;
const size_t l2Capacity = l2Size * DNBD3_BLOCK_SIZE * bitfieldByteSize * 8;
const size_t testFileSize = l2Capacity * 2.9L;

#define MAX_WRITE_SIZE 4096 * 320
#define TRUNCATE_PROBABILITY 5
#define UNALIGNED_WRITE_PROBABILITY 5


int delay = 0;
static char filePath[400];
static int fh = 0;

bool printOnError = true;
/**
 * @brief generates a Test file
 * 
 * @param path Location where the file is created
 * @param size Size of the file in byte
 */

void generateTestFile( char *path, size_t size )
{
	int fh;
	strcpy( filePath, path );
	if ( ( fh = open( path, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR ) ) == -1 ) {
		perror( "Could not create test file: " );
		return;
	}
	if ( ftruncate( fh, size ) == -1 ) {
		perror( "Error while expanding test file: " );
		return;
	}


	close( fh );
	printf( "Generated Test File of size: %zu bytes. \n", size );
	//todo write markers:
}


void printUsage()
{
	printf( "Press the following for: \n" );
	printf( "   d <delay>     Delay in Seconds for multiple block write (must be first).\n" );
	printf( "   c <path>      Creates test file at the path. \n" );
	printf( "   t <path>      Runs the standard test procedure. \n" );
	printf( "   v <path>      verifies a file. \n" );
	printf(
			"	r <mountedImage> <normalImage> randomly writes in both images and after cancel compares them if they are equal." );
}

void printCharInHexadecimal( const char *str, int len )
{
	for ( int i = 0; i < len; ++i ) {
		uint8_t val = str[i];
		char tbl[] = "0123456789ABCDEF";
		printf( "0x" );
		printf( "%c", tbl[val / 16] );
		printf( "%c", tbl[val % 16] );
		printf( " " );
	}
	printf( "\n" );
}

bool compare( char buff[], char expected[], size_t size, char errorMessage[] )
{
	if ( memcmp( buff, expected, size ) != 0 ) {
		perror( errorMessage );
		if ( printOnError ) {
			printf( "Expected: \n" );
			printCharInHexadecimal( expected, (int)size );
			printf( "Got: \n " );
			printCharInHexadecimal( buff, (int)size );
		}
		return false;
	}
	return true;
}


bool readSizeTested( int fh, char *buf, ssize_t size, off_t off, char *error )
{
	ssize_t readSize = pread( fh, buf, size, off );
	if ( readSize < size ) {
		printf( "%s \n size read: %zu\n Expected %zu\n", error, readSize, size );
		return false;
	}
	return true;
}

bool writeSizeTested( int fh, char *buf, ssize_t size, off_t off, char *error )
{
	if ( pwrite( fh, buf, size, off ) < size ) {
		perror( error );
		return false;
	}
	return true;
}

bool changeFileSizeAndVerify( char *filePath, size_t size )
{
	if ( truncate( filePath, size ) != 0 ) {
		perror( "truncate failed: " );
		return false;
	}
	// verify
	struct stat st;
	stat( filePath, &st );
	size_t newSize = st.st_size;

	if ( size != newSize ) {
		printf( "truncate failed, wrong file size\n expectedSize: %zu\n got: %zu\n", size, newSize );
		return false;
	}
	return true;
}

bool verifySingleBit()
{
	char buff[DNBD3_BLOCK_SIZE];
	char expected[DNBD3_BLOCK_SIZE];
	memset( expected, 0, DNBD3_BLOCK_SIZE );
	expected[0] = 1;
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE, 0, "SingleBit test Failed: first read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE, "SingleBit test Failed: first write not as expected" ) )
		return false;

	expected[0] = 0;
	expected[DNBD3_BLOCK_SIZE / 2] = 1;
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE, DNBD3_BLOCK_SIZE, "SingleBit test Failed: second read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE, "SingleBit test Failed: second write not as expected" ) )
		return false;
	printf( "testSingleBit successful!\n" );
	return true;
}

bool testSingleBit()
{
	char buff[DNBD3_BLOCK_SIZE];
	char expected[DNBD3_BLOCK_SIZE];
	memset( expected, 0, DNBD3_BLOCK_SIZE );
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE, 0, "SingleBit test Failed: first read to small" ) )
		return false;

	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE, "SingleBit test Failed: initial read" ) )
		return false;
	expected[0] = 1;
	if ( !writeSizeTested( fh, expected, DNBD3_BLOCK_SIZE, 0, "SingleBit test Failed: first write failed" ) )
		return false;

	expected[0] = 0;
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE, DNBD3_BLOCK_SIZE, "SingleBit test Failed: second read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE, "SingleBit test Failed: second read" ) )
		return false;
	expected[0] = 1;
	if ( !writeSizeTested(
				  fh, expected, 1, DNBD3_BLOCK_SIZE + DNBD3_BLOCK_SIZE / 2, "SingleBit test Failed: second write failed" ) )
		return false;
	return verifySingleBit();
}

bool verifyWriteOverTwoBlocks()
{
	char buff[DNBD3_BLOCK_SIZE * 2];
	char expected[DNBD3_BLOCK_SIZE * 2];
	memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
	if ( !readSizeTested(
				  fh, buff, DNBD3_BLOCK_SIZE * 2, DNBD3_BLOCK_SIZE * 3, "writeOverTwoBlocks test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "OverTwoBlocks test Failed: write not as expected" ) )
		return false;
	printf( "writeOverTwoBlocks successful!\n" );
	return true;
}

bool writeOverTwoBlocks()
{
	char buff[DNBD3_BLOCK_SIZE * 2];
	char expected[DNBD3_BLOCK_SIZE * 2];
	memset( expected, 0, DNBD3_BLOCK_SIZE * 2 );
	if ( !readSizeTested(
				  fh, buff, DNBD3_BLOCK_SIZE * 2, DNBD3_BLOCK_SIZE * 3, "writeOverTwoBlocks test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "OverTwoBlocks test Failed: initial read" ) )
		return false;
	memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
	if ( !writeSizeTested( fh, expected, DNBD3_BLOCK_SIZE * 2, DNBD3_BLOCK_SIZE * 3,
				  "writeOverTwoBlocks test Failed: write failed" ) )
		return false;
	return verifyWriteOverTwoBlocks();
}


bool verifyWriteOverL2()
{
	char buff[DNBD3_BLOCK_SIZE * 2];
	char expected[DNBD3_BLOCK_SIZE * 2];

	memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
	size_t offset = l2Capacity * 2 - DNBD3_BLOCK_SIZE;
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 2, offset, "writeOverL2 test Failed: read to small" ) ) {
		return false;
	}
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "writeOverL2 test Failed: write not as expected" ) ) {
		return false;
	}
	printf( "writeOverL2 successful!\n" );
	return true;
}

bool writeOverL2()
{
	char buff[DNBD3_BLOCK_SIZE * 2];
	char expected[DNBD3_BLOCK_SIZE * 2];
	memset( expected, 0, DNBD3_BLOCK_SIZE * 2 );
	size_t offset = l2Capacity * 2 - DNBD3_BLOCK_SIZE;
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 2, offset, "writeOverL2 test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "writeOverL2 test Failed: initial read" ) )
		return false;
	memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
	if ( !writeSizeTested( fh, expected, DNBD3_BLOCK_SIZE * 2, offset, "writeOverL2 test Failed: write failed" ) )
		return false;

	return verifyWriteOverL2();
}


bool verifyWriteNotOnBlockBorder()
{
	char buff[DNBD3_BLOCK_SIZE * 2];
	char expected[DNBD3_BLOCK_SIZE * 2];
	memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
	size_t offset = DNBD3_BLOCK_SIZE * 11 - DNBD3_BLOCK_SIZE / 2;
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 2, offset, "writeNotOnBlockBorder test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "writeNotOnBlockBorder test Failed: write not as expected" ) )
		return false;
	printf( "writeNotOnBlockBorder successful!\n" );
	return true;
}

// perhaps do some initial markers on the file
bool writeNotOnBlockBorder()
{
	char buff[DNBD3_BLOCK_SIZE * 2];
	char expected[DNBD3_BLOCK_SIZE * 2];
	memset( expected, 0, DNBD3_BLOCK_SIZE * 2 );
	size_t offset = DNBD3_BLOCK_SIZE * 11 - DNBD3_BLOCK_SIZE / 2;
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 2, offset, "writeNotOnBlockBorder test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2, "writeNotOnBlockBorder test Failed: initial read" ) )
		return false;
	memset( expected, 1, DNBD3_BLOCK_SIZE * 2 );
	if ( !writeSizeTested(
				  fh, expected, DNBD3_BLOCK_SIZE * 2, offset, "writeNotOnBlockBorder test Failed: write failed" ) )
		return false;
	return verifyWriteNotOnBlockBorder();
}

bool verifyLongNonAlignedPattern()
{
	int size = DNBD3_BLOCK_SIZE * 10;
	char buffer[size];
	char expected[size];
	for ( int i = 0; i < size; i++ ) {
		expected[i] = (char)( i % 255 );
	}

	off_t offset = l2Capacity * 3 - 1;
	size_t totalSize = l2Capacity + 2;
	off_t endOffset = offset + totalSize;

	while ( offset < endOffset ) {
		size_t sizeToRead = MIN( size, endOffset - offset );
		if ( !readSizeTested( fh, buffer, sizeToRead, offset, "writeLongNonAlignedPattern test Failed: read failed" ) ) {
			return false;
		}
		if ( !compare( buffer, expected, sizeToRead, "writeLongNonAlignedPattern test Failed:  read failed" ) )
			return false;
		offset += sizeToRead;
	}
	printf( "LongNonAlignedPattern successful!\n" );
	return true;
}

bool writeLongNonAlignedPattern()
{
	int size = DNBD3_BLOCK_SIZE * 10;
	char buffer[size];

	for ( int i = 0; i < size; i++ ) {
		buffer[i] = (char)( i % 255 );
	}

	off_t offset = l2Capacity * 3 - 1;
	size_t totalSize = l2Capacity + 2;
	off_t endOffset = offset + totalSize;

	while ( offset < endOffset ) {
		size_t sizeToWrite = MIN( size, endOffset - offset );
		if ( !writeSizeTested(
					  fh, buffer, sizeToWrite, offset, "writeLongNonAlignedPattern test Failed: write failed" ) ) {
			return false;
		}
		offset += sizeToWrite;
	}
	return verifyLongNonAlignedPattern();
}


bool fileSizeChanges()
{
	// increase filesize

	if ( !changeFileSizeAndVerify( filePath, testFileSize + 2 * l2Capacity ) ) {
		return false;
	}

	// check if increased is 0
	char buff[DNBD3_BLOCK_SIZE * 10];
	char expected[DNBD3_BLOCK_SIZE * 10];
	memset( expected, 0, DNBD3_BLOCK_SIZE * 10 );
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 10, testFileSize + l2Capacity,
				  "fileSizeChanges test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 10, "fileSizeChanges test Failed: increased data not 0" ) )
		return false;
	printf( "increased data is 0 as expected\n" );
	// write on increased blocks
	memset( expected, 1, DNBD3_BLOCK_SIZE * 10 );
	if ( !writeSizeTested(
				  fh, expected, DNBD3_BLOCK_SIZE * 10, testFileSize, "fileSizeChanges test Failed: write failed" ) )
		return false;
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 10, testFileSize, "fileSizeChanges test Failed: read to small" ) )
		return false;
	if ( !compare(
				  buff, expected, DNBD3_BLOCK_SIZE * 10, "fileSizeChanges test Failed: write on increased size failed" ) )
		return false;
	printf( "writes to new Block Ok\n" );
	// decrease filesize
	printf( "Truncate file to: %zu \n", testFileSize );
	if ( !changeFileSizeAndVerify( filePath, testFileSize ) ) {
		return false;
	}
	printf( "size verified\n" );
	// increase again, check its 0 again
	printf( "Truncate file to: %zu\n", testFileSize + 2 * l2Capacity );
	if ( !changeFileSizeAndVerify( filePath, testFileSize + 2 * l2Capacity ) ) {
		return false;
	}

	printf( "size verified\n" );
	memset( expected, 0, DNBD3_BLOCK_SIZE * 10 );


	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 10, testFileSize, "fileSizeChanges test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 2,
				  "fileSizeChanges test Failed: increased data (second time) not 0" ) )
		return false;
	printf( "fileSizeChanges successful!\n" );
	return true;
}


bool verifyInterleavedTest()
{
	char buff[DNBD3_BLOCK_SIZE * 10];
	char expected[DNBD3_BLOCK_SIZE * 10];
	off_t offset = 35 * DNBD3_BLOCK_SIZE;
	memset( expected, 0, DNBD3_BLOCK_SIZE * 10 );
	memset( expected, 10, DNBD3_BLOCK_SIZE );
	memset( ( expected + ( DNBD3_BLOCK_SIZE * 2 ) ), 12, DNBD3_BLOCK_SIZE );
	memset( ( expected + ( DNBD3_BLOCK_SIZE * 4 ) ), 14, DNBD3_BLOCK_SIZE );
	memset( ( expected + ( DNBD3_BLOCK_SIZE * 5 ) ), 15, DNBD3_BLOCK_SIZE );
	memset( ( expected + ( DNBD3_BLOCK_SIZE * 8 ) ), 18, DNBD3_BLOCK_SIZE );
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 10, offset, "interleavedTest test Failed: read 2 to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 10, "interleavedTest test Failed: read not as expected" ) )
		return false;
	printf( "interleavedTest successful!\n" );
	return true;
}

bool interleavedTest()
{
	printf( "starting interleavedTest \n" );
	char buff[DNBD3_BLOCK_SIZE * 10];
	char expected[DNBD3_BLOCK_SIZE * 10];
	off_t offset = 35 * DNBD3_BLOCK_SIZE;
	memset( expected, 0, DNBD3_BLOCK_SIZE * 10 );
	if ( !readSizeTested( fh, buff, DNBD3_BLOCK_SIZE * 10, offset, "interleavedTest test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, DNBD3_BLOCK_SIZE * 10, "interleavedTest test Failed: read data not 0" ) )
		return false;

	memset( expected, 10, DNBD3_BLOCK_SIZE );
	if ( !writeSizeTested( fh, expected, DNBD3_BLOCK_SIZE, offset, "interleavedTest test Failed: write 1 failed" ) )
		return false;

	memset( ( expected + ( DNBD3_BLOCK_SIZE * 2 ) ), 12, DNBD3_BLOCK_SIZE );
	if ( !writeSizeTested( fh, ( expected + ( DNBD3_BLOCK_SIZE * 2 ) ), DNBD3_BLOCK_SIZE, offset + DNBD3_BLOCK_SIZE * 2,
				  "interleavedTest test Failed: write 2 failed" ) )
		return false;

	memset( ( expected + ( DNBD3_BLOCK_SIZE * 4 ) ), 14, DNBD3_BLOCK_SIZE );
	memset( ( expected + ( DNBD3_BLOCK_SIZE * 5 ) ), 15, DNBD3_BLOCK_SIZE );

	if ( !writeSizeTested( fh, ( expected + ( DNBD3_BLOCK_SIZE * 4 ) ), DNBD3_BLOCK_SIZE * 2,
				  offset + DNBD3_BLOCK_SIZE * 4, "interleavedTest test Failed: write 3 failed" ) )
		return false;

	memset( ( expected + ( DNBD3_BLOCK_SIZE * 8 ) ), 18, DNBD3_BLOCK_SIZE );
	if ( !writeSizeTested( fh, ( expected + ( DNBD3_BLOCK_SIZE * 8 ) ), DNBD3_BLOCK_SIZE, offset + DNBD3_BLOCK_SIZE * 8,
				  "interleavedTest test Failed: write 4 failed" ) )
		return false;
	return verifyInterleavedTest();
}

bool verifyMultipleWrites()
{
	size_t size = DNBD3_BLOCK_SIZE * 10 * bitfieldByteSize;
	char buff[size];
	char expected[size];
	off_t offset = 100 * DNBD3_BLOCK_SIZE * bitfieldByteSize;
	memset( expected, 3, size );
	if ( !readSizeTested( fh, buff, size, offset, "multipleWrites test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, size, "multipleWrites: read incorrect data" ) )
		return false;
	printf( "MultipleWrites successful!\n" );
	return true;
}

bool multipleWrites()
{
	printf( "starting multipleWrites\n" );
	size_t size = DNBD3_BLOCK_SIZE * 10 * bitfieldByteSize;
	char buff[size];
	char expected[size];
	off_t offset = 100 * DNBD3_BLOCK_SIZE * bitfieldByteSize;

	for ( int i = 1; i <= 3; i++ ) {
		printf( "multipleWrites: %i/3 \n", i );

		memset( expected, i, size );
		if ( !writeSizeTested( fh, expected, size, offset, "multipleWrites: write Failed" ) )
			return false;
		if ( !readSizeTested( fh, buff, size, offset, "multipleWrites test Failed: read to small" ) )
			return false;
		if ( !compare( buff, expected, size, "multipleWrites: read incorrect data" ) )
			return false;
		if ( delay > 0 && i < 3 ) {
			printf( "waiting %is\n", delay );
			sleep( delay );
		}
	}
	return verifyMultipleWrites();
}


void runTest( char *path )
{
	if ( ( fh = open( path, O_RDWR, S_IRUSR | S_IWUSR ) ) == -1 ) {
		perror( "Could not open test file" );
		printf( "Given path: %s \n", path );
		return;
	}
	strcpy( filePath, path );
	printf( "file opened: %s\n", path );

	if ( !testSingleBit() )
		return;
	if ( !writeOverTwoBlocks() )
		return;

	if ( !writeNotOnBlockBorder() )
		return;

	if ( !writeOverL2() )
		return;
	if ( !fileSizeChanges() )
		return;
	if ( !interleavedTest() )
		return;
	if ( !multipleWrites() ) {
		return;
	}
	if ( !writeLongNonAlignedPattern() ) {
		return;
	}


	printf( "All test's successful.\n" );
}


void verifyTests( verify_test_t *tests )
{
	// offset, size, function

	tests[0] = ( verify_test_t ){ 0, 2 * DNBD3_BLOCK_SIZE, verifySingleBit };
	tests[1] = ( verify_test_t ){ DNBD3_BLOCK_SIZE * 3, DNBD3_BLOCK_SIZE * 3, verifyWriteOverTwoBlocks };
	tests[2] = ( verify_test_t ){ DNBD3_BLOCK_SIZE * 11 - DNBD3_BLOCK_SIZE / 2, DNBD3_BLOCK_SIZE * 2,
		verifyWriteNotOnBlockBorder };
	tests[3] = ( verify_test_t ){ 35 * DNBD3_BLOCK_SIZE, DNBD3_BLOCK_SIZE * 10, verifyInterleavedTest };
	tests[4] = ( verify_test_t ){ 100 * DNBD3_BLOCK_SIZE * bitfieldByteSize, DNBD3_BLOCK_SIZE * 10 * bitfieldByteSize,
		verifyMultipleWrites };
	tests[5] = ( verify_test_t ){ l2Capacity * 2 - DNBD3_BLOCK_SIZE, DNBD3_BLOCK_SIZE * 2, verifyWriteOverL2 };
	tests[6] = ( verify_test_t ){ l2Capacity * 3 - 1, l2Capacity + 2, verifyLongNonAlignedPattern };
}

void verifyFinalFile( char *path )
{
	if ( ( fh = open( path, O_RDWR, S_IRUSR | S_IWUSR ) ) == -1 ) {
		perror( "Could not open test file" );
		printf( "Given path: %s \n", path );
		return;
	}
	// verify file size

	size_t fileSize = testFileSize + 2 * l2Capacity;
	struct stat st;
	stat( path, &st );
	size_t size = st.st_size;
	if ( size != fileSize ) {
		printf( "verify Failed, wrong file size\n expectedSize: %zu\n got: %zu\n", fileSize, size );
		return;
	}

	// read to whole file

	int maxReadSize = DNBD3_BLOCK_SIZE * COW_BITFIELD_SIZE * 8;
	char buffer[maxReadSize];
	char emptyData[maxReadSize];
	memset( emptyData, 0, maxReadSize );
	size_t offset = 0;


	int numberOfTests = 7;
	verify_test_t tests[numberOfTests];
	verifyTests( tests );

	int currentTest = 0;


	while ( offset < fileSize ) {
		size_t sizeToRead = MIN( (size_t)maxReadSize, fileSize - offset );
		if ( currentTest < numberOfTests ) {
			sizeToRead = MIN( sizeToRead, tests[currentTest].offset - offset );
		}
		if ( currentTest < numberOfTests && tests[currentTest].offset == (off_t)offset ) {
			if ( !tests[currentTest].test() ) {
				return;
			}
			offset += tests[currentTest].size;
			currentTest++;
		} else {
			ssize_t sizeRead = pread( fh, buffer, sizeToRead, offset );
			if ( sizeRead <= 0 ) {
				perror( "Error while reading data: " );
				printf( "verify failed. \n" );
				return;
			}
			if ( !compare( buffer, emptyData, sizeRead, "verify failed. Expected 0 data" ) ) {
				printf( "Offset: %zu \n", offset );
				return;
			}
			offset += (size_t)sizeRead;
		}
	}

	printf( "file verified successful.\n" );
}


void generateRandomData( int fhr, char *dest, size_t size )
{
	read( fhr, dest, size );
}


atomic_bool randomTestLoop = true;

void printProgress( float progress )
{
	progress = MIN( 1, progress );
	progress = MAX( 0, progress );
	int barWidth = 50;
	char buf[barWidth + 1];
	buf[barWidth] = 0;
	int pos = (int)( (float) barWidth * progress );
	memset( buf, '=', pos );
	memset( ( buf + pos ), ' ', ( barWidth - pos ) );
	printf( "\033[F[%s] %i%%\n", buf, (int)( progress * 100 ) );
}

void compareTwoFiles( char * mountedImagePath, char * normalImagePath, int fhm, int fhn) {
	char buf[MAX_WRITE_SIZE];
	char exBuf[MAX_WRITE_SIZE];
	off_t offset = 0;
	struct stat st;
	stat( mountedImagePath, &st );
	size_t sizeMounted = st.st_size;
	stat( normalImagePath, &st );
	size_t sizeNormal = st.st_size;

	if ( sizeMounted != sizeNormal ) {
		printf( "Error size difference, mounted: %zu normal: %zu \n", sizeMounted, sizeNormal );
		return;
	}
	while ( offset < (off_t)sizeMounted ) {
		size_t sizeToRead = MIN( MAX_WRITE_SIZE, sizeMounted - offset );
		read( fhm, buf, sizeToRead );

		read( fhn, exBuf, sizeToRead );

		if ( memcmp( buf, exBuf, sizeToRead ) != 0 ) {
			printf( "Error: Different data  offset: %zu size:%zu\n", offset, sizeToRead );
			return;
		}

		offset += sizeToRead;
		printProgress( ( (float)offset ) / ( (float)sizeMounted ) );
	}
	printf( "\nTest successful !!!\n" );
}

void startCompareTwoFiles( char * mountedImagePath, char * normalImagePath ) {
	int fhm, fhn;
	if ( ( fhm = open( mountedImagePath, O_RDWR, S_IRUSR | S_IWUSR ) ) == -1 ) {
		perror( "Could not open mounted Image" );
		printf( "Given path: %s \n", mountedImagePath );
		return;
	}
	if ( ( fhn = open( normalImagePath, O_RDWR, S_IRUSR | S_IWUSR ) ) == -1 ) {
		perror( "Could not open mounted Image" );
		printf( "Given path: %s \n", normalImagePath );
		return;
	}
	compareTwoFiles( mountedImagePath, normalImagePath, fhm, fhn);
}

void *randomWriteTest( void *args )
{
	char *mountedImagePath = ( (random_write_args_t *)args )->mountedImage;
	char *normalImagePath = ( (random_write_args_t *)args )->normalImage;
	free( args );
	int fhm;
	int fhn;
	int fhr;
	srand( (unsigned)time( NULL ) );
	char buf[MAX_WRITE_SIZE];

	printf( "===starting random write test ===\n" );
	printf( "mounted image path %s\n", mountedImagePath );
	printf( "normal image path %s\n", normalImagePath );

	size_t maxOffset = (size_t)( testFileSize * 1.1L );

	if ( ( fhm = open( mountedImagePath, O_RDWR, S_IRUSR | S_IWUSR ) ) == -1 ) {
		perror( "Could not open mounted Image" );
		printf( "Given path: %s \n", mountedImagePath );
		return NULL;
	}
	if ( ( fhn = open( normalImagePath, O_RDWR, S_IRUSR | S_IWUSR ) ) == -1 ) {
		perror( "Could not open mounted Image" );
		printf( "Given path: %s \n", normalImagePath );
		return NULL;
	}
	if ( ( fhr = open( "/dev/urandom", O_RDONLY ) ) == -1 ) {
		perror( "Could not open /dev/urandom" );
		return NULL;
	}

	// RANDOM WRITE LOOP
	printf( "Press any key to cancel\n" );
	while ( randomTestLoop ) {
		//select test
		int r = rand() % 100;

		if ( r < TRUNCATE_PROBABILITY ) {
			// truncate both images
			size_t size = (size_t)( ( rand() % (int)( (double) testFileSize * 0.2 ) ) + (double) testFileSize * 0.9 );
			printf( "change filesize to: %zu\n", size );
			if ( !changeFileSizeAndVerify( mountedImagePath, size ) ) {
				return NULL;
			}
			if ( !changeFileSizeAndVerify( normalImagePath, size ) ) {
				return NULL;
			}

		} else {
			off_t offset = rand() % maxOffset;
			size_t size = rand() % MAX_WRITE_SIZE;
			size = MAX( size, 1 );
			if ( r > TRUNCATE_PROBABILITY + UNALIGNED_WRITE_PROBABILITY ) {
				offset = offset - ( offset % 4096 );
				size = MAX( size - ( size % 4096 ), 4096 );
			}

			generateRandomData( fhr, buf, size );
			printf( "write offset: %zu size: %zu\n", offset, size );
			if ( !writeSizeTested( fhm, buf, size, offset, "failed to write on mounted image" ) )
				return NULL;
			if ( !writeSizeTested( fhn, buf, size, offset, "failed to write on normal image" ) )
				return NULL;
		}
	}

	// COMPARE BOTH IMAGES
	printf( "comparing both files: \n\n" );
	compareTwoFiles( mountedImagePath, normalImagePath, fhm, fhn );
	
	return NULL;
}


void startRandomWriteTest( char *mountedImagePath, char *normalImagePath )
{
	// start Thread

	pthread_t tid;
	random_write_args_t *args = malloc( sizeof( random_write_args_t ) );

	args->mountedImage = mountedImagePath;

	args->normalImage = normalImagePath;
	pthread_create( &tid, NULL, &randomWriteTest, args );
	// wait for key
	getchar();
	randomTestLoop = false;
	pthread_join( tid, NULL );
}

int main( int argc, char *argv[] )
{
	if ( argc < 1 ) {
		printUsage();
		return 0;
	}
	int opt;
	while ( ( opt = getopt( argc, argv, "d:c:t:v:r:x:" ) ) != -1 ) {
		char *pEnd;

		switch ( opt ) {
		case 'd':
			delay = (int)strtol( optarg, &pEnd, 10 );
			printf( "Delay set to %i\n", delay );
			break;
		case 'c': 
			generateTestFile( optarg, testFileSize ); 
			break;
		case 't':
			printf( "starting standard test\n" );
			runTest( optarg );
			break;
		case 'v':
			printf( "verifying file \n" );
			verifyFinalFile( optarg );
			break;
		case 'r':
			if ( optind >= argc ) {
				printUsage();
				return 0;
			}
			startRandomWriteTest( optarg, argv[optind] );
			return 0;
			break;
		case 'x':
			
			if ( optind >= argc ) {
				printUsage();
				return 0;
			}
			startCompareTwoFiles( optarg, argv[optind] );
			return 0;
			break;

		default:
			printUsage();
			return 0;
			break;
		}
	}
	return 0;
}