summaryrefslogtreecommitdiffstats
path: root/src/cowtest/main.c
blob: 559d332b01b4da5db35c8598e326854977dd7ad6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
#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>


static bool run = true;

const size_t l2Size = 1024;
const size_t bitfieldByteSize = 40;
const size_t blocksize = 4096;
const size_t l2Capacity = l2Size * blocksize * bitfieldByteSize;

const size_t testFileSize = l2Size * bitfieldByteSize * blocksize * 5;

const char standartValue = 'a';
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 follwing for: \n" );
	printf( "   c <path>      Creates test file at the path. \n" );
	printf( "   t <path>      Runs the standart test procedure. \n" );
}

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, size );
			printf( "Got: \n " );
			printCharInHexadecimal( buff, 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 testFirstBit()
{
	char buff[blocksize];
	char expected[blocksize];
	memset( expected, 0, blocksize );
	if ( !readSizeTested( fh, buff, 4096, 0, "FirstBit test Failed: read to small" ) )
		return false;

	if ( !compare( buff, expected, 4096, "FirstBit test Failed: initial read" ) )
		return false;
	expected[0] = 1;
	if ( !writeSizeTested( fh, expected, 4096, 0, "FirstBit test Failed: write failed" ) )
		return false;
	if ( !readSizeTested( fh, buff, 4096, 0, "FirstBit test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, 4096, "FirstBit test Failed: write not as expected" ) )
		return false;
	printf( "testFirstBit successful!\n" );
	return true;
}

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

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


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

bool fileSizeChanges()
{
	// increase filesize

	printf( "Truncate file to: %zu\n", testFileSize + 2 * l2Capacity );
	if ( truncate( filePath, testFileSize + 2 * l2Capacity ) != 0 ) {
		perror( "fileSizeChanges test Failed: first truncate failed." );
		return false;
	}
	// verify
	struct stat st;
	stat( filePath, &st );
	size_t size = st.st_size;

	if ( size != testFileSize + 2 * l2Capacity ) {
		printf( "fileSizeChanges test Failed\n expectedSize: %zu\n got: %zu\n", testFileSize + 2 * l2Capacity, size );
		return false;
	}
	// check if increased is 0
	char buff[blocksize * 10];
	char expected[blocksize * 10];
	memset( expected, 0, blocksize * 10 );
	if ( !readSizeTested(
				  fh, buff, blocksize * 10, testFileSize + l2Capacity, "fileSizeChanges test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, blocksize * 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, blocksize * 10 );
	if ( !writeSizeTested( fh, expected, blocksize * 10, testFileSize, "fileSizeChanges test Failed: write failed" ) )
		return false;
	if ( !readSizeTested( fh, buff, blocksize * 10, testFileSize, "fileSizeChanges test Failed: read to small" ) )
		return false;
	if ( !compare( buff, expected, blocksize * 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 ( truncate( filePath, testFileSize ) != 0 ) {
		perror( "fileSizeChanges test Failed: second truncate failed." );
		return false;
	}
	// verify
	printf( "truncate done, verifing...\n" );
	stat( filePath, &st );
	size = st.st_size;
	if ( size != testFileSize ) {
		printf(
				"fileSizeChanges test Failed, decrease not worked.\n expectedSize: %zu\n got: %zu\n", testFileSize, size );
		return false;
	}
	printf( "size verified\n" );
	// increase again, check its 0 again
	printf( "Truncate file to: %zu\n", testFileSize + 2 * l2Capacity );
	if ( truncate( filePath, testFileSize + 2 * l2Capacity ) != 0 ) {
		perror( "fileSizeChanges test Failed: second increase failed." );
		return false;
	}
	printf( "truncate done, verifing...\n" );
	stat( filePath, &st );
	size = st.st_size;
	if ( size != ( testFileSize + 2 * l2Capacity ) ) {
		printf( "fileSizeChanges test Failed, increse not worked.\n expectedSize: %zu\n got: %zu\n", testFileSize, size );
		return false;
	}
	printf( "size verified\n" );
	memset( expected, 0, blocksize * 10 );


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

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 ( !testFirstBit() )
		return;
	if ( !writeOverTwoBlocks() )
		return;
	if ( !writeOverL2() )
		return;
	if ( !fileSizeChanges() )
		return;
	printf( "All test's successful.\n" );
}


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;
	}
}

void execCommand( char command, char *parameters )
{
	switch ( command ) {
	case 'c':
		if ( parameters[0] == '\0' ) {
			printUsage();
			break;
		}
		generateTestFile( parameters, 3 * l2Capacity );
		break;
	case 't':
		if ( parameters[0] == '\0' ) {
			printUsage();
			break;
		}
		printf( "starting standart test\n" );
		runTest( parameters );
		break;
	case 'v':
		if ( parameters[0] == '\0' ) {
			printUsage();
			break;
		}
		printf( "verifing file \n" );
		runTest( parameters );
	default:
		printf( "Command not Found \n" );
		printUsage();
		break;
	}
}


int main( int argc, char *argv[] )
{
	if ( argc == 3 ) {
		execCommand( argv[1][0], argv[2] );
	} else {
		printUsage();
	}
	return 0;
}


/*
  methode to generate test file.
*/
/* Tests to impelment:

1. Read & Writes over block borders (l1, l2, metadata).
2. Parallel writes on different unchanged blocks.(test for race condition on cow file increse).
3. Test truncate file (smaller and lager).
4. Random read writes.
5. Read & Writes over data which is partially in cow file
6. Read & Write single byte
*/