1 | /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB |
2 | |
3 | This program is free software; you can redistribute it and/or modify |
4 | it under the terms of the GNU General Public License as published by |
5 | the Free Software Foundation; version 2 of the License. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License |
13 | along with this program; if not, write to the Free Software |
14 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ |
15 | |
16 | /* Unit test of the control file module of the Aria engine WL#3234 */ |
17 | |
18 | /* |
19 | Note that it is not possible to test the durability of the write (can't |
20 | pull the plug programmatically :) |
21 | */ |
22 | |
23 | #include <my_global.h> |
24 | #include <my_sys.h> |
25 | #include <tap.h> |
26 | #ifdef _WIN32 |
27 | #include <direct.h> /* rmdir */ |
28 | #endif |
29 | #ifndef WITH_ARIA_STORAGE_ENGINE |
30 | /* |
31 | If Aria is not compiled in, normally we don't come to building this test. |
32 | */ |
33 | #error "Aria engine is not compiled in, test cannot be built" |
34 | #endif |
35 | |
36 | #include "maria.h" |
37 | #include "../../../storage/maria/maria_def.h" |
38 | #include <my_getopt.h> |
39 | |
40 | #define |
41 | #include "../ma_control_file.c" |
42 | #undef EXTRACT_DEFINITIONS |
43 | |
44 | char file_name[FN_REFLEN]; |
45 | |
46 | /* The values we'll set and expect the control file module to return */ |
47 | LSN expect_checkpoint_lsn; |
48 | uint32 expect_logno; |
49 | TrID expect_max_trid; |
50 | uint8 expect_recovery_failures; |
51 | |
52 | static int delete_file(myf my_flags); |
53 | /* |
54 | Those are test-specific wrappers around the module's API functions: after |
55 | calling the module's API functions they perform checks on the result. |
56 | */ |
57 | static int close_file(void); /* wraps ma_control_file_end */ |
58 | /* wraps ma_control_file_open_or_create */ |
59 | static int open_file(void); |
60 | /* wraps ma_control_file_write_and_force */ |
61 | static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid, |
62 | uint8 rec_failures); |
63 | |
64 | /* Tests */ |
65 | static int test_one_log_and_recovery_failures(void); |
66 | static int test_five_logs_and_max_trid(void); |
67 | static int test_3_checkpoints_and_2_logs(void); |
68 | static int test_binary_content(void); |
69 | static int test_start_stop(void); |
70 | static int test_2_open_and_2_close(void); |
71 | static int test_bad_magic_string(void); |
72 | static int test_bad_checksum(void); |
73 | static int test_bad_hchecksum(void); |
74 | static int test_future_size(void); |
75 | static int test_bad_blocksize(void); |
76 | static int test_bad_size(void); |
77 | |
78 | /* Utility */ |
79 | static int verify_module_values_match_expected(void); |
80 | static int verify_module_values_are_impossible(void); |
81 | static void usage(void); |
82 | static void get_options(int argc, char *argv[]); |
83 | |
84 | /* |
85 | If "expr" is FALSE, this macro will make the function print a diagnostic |
86 | message and immediately return 1. |
87 | This is inspired from assert() but does not crash the binary (sometimes we |
88 | may want to see how other tests go even if one fails). |
89 | RET_ERR means "return error". |
90 | */ |
91 | |
92 | #define RET_ERR_UNLESS(expr) \ |
93 | {if (!(expr)) {diag("line %d: failure: '%s'", __LINE__, #expr); assert(0);return 1;}} |
94 | |
95 | |
96 | /* Used to ignore error messages from ma_control_file_open() */ |
97 | |
98 | static void my_ignore_message(uint error __attribute__((unused)), |
99 | const char *str __attribute__((unused)), |
100 | myf MyFlags __attribute__((unused))) |
101 | { |
102 | DBUG_ENTER("my_message_no_curses" ); |
103 | DBUG_PRINT("enter" ,("message: %s" ,str)); |
104 | DBUG_VOID_RETURN; |
105 | } |
106 | |
107 | void (*default_error_handler_hook)(uint my_err, const char *str, |
108 | myf MyFlags) = 0; |
109 | |
110 | |
111 | /* like ma_control_file_open(), but without error messages */ |
112 | |
113 | static CONTROL_FILE_ERROR local_ma_control_file_open(void) |
114 | { |
115 | CONTROL_FILE_ERROR error; |
116 | error_handler_hook= my_ignore_message; |
117 | error= ma_control_file_open(TRUE, TRUE); |
118 | error_handler_hook= default_error_handler_hook; |
119 | return error; |
120 | } |
121 | |
122 | static char *create_tmpdir(const char *progname) |
123 | { |
124 | static char test_dirname[FN_REFLEN]; |
125 | char tmp_name[FN_REFLEN]; |
126 | size_t length; |
127 | |
128 | /* Create a temporary directory of name TMP-'executable', but without the -t extension */ |
129 | fn_format(tmp_name, progname, "" , "" , MY_REPLACE_DIR | MY_REPLACE_EXT); |
130 | length= strlen(tmp_name); |
131 | if (length > 2 && tmp_name[length-2] == '-' && tmp_name[length-1] == 't') |
132 | tmp_name[length-2]= 0; |
133 | strxmov(test_dirname, "TMP-" , tmp_name, NullS); |
134 | |
135 | /* |
136 | Don't give an error if we can't create dir, as it may already exist from a previously aborted |
137 | run |
138 | */ |
139 | (void) my_mkdir(test_dirname, 0777, MYF(0)); |
140 | return test_dirname; |
141 | } |
142 | |
143 | |
144 | int main(int argc,char *argv[]) |
145 | { |
146 | MY_INIT(argv[0]); |
147 | my_init(); |
148 | |
149 | default_error_handler_hook= error_handler_hook; |
150 | |
151 | plan(12); |
152 | |
153 | maria_data_root= create_tmpdir(argv[0]); |
154 | |
155 | diag("Unit tests for control file" ); |
156 | |
157 | get_options(argc,argv); |
158 | |
159 | diag("Deleting control file at startup, if there is an old one" ); |
160 | RET_ERR_UNLESS(0 == delete_file(0)); /* if fails, can't continue */ |
161 | |
162 | diag("Tests of normal conditions" ); |
163 | ok(0 == test_one_log_and_recovery_failures(), |
164 | "test of creating one log and recording recovery failures" ); |
165 | ok(0 == test_five_logs_and_max_trid(), |
166 | "test of creating five logs and many transactions" ); |
167 | ok(0 == test_3_checkpoints_and_2_logs(), |
168 | "test of creating three checkpoints and two logs" ); |
169 | ok(0 == test_binary_content(), "test of the binary content of the file" ); |
170 | ok(0 == test_start_stop(), "test of multiple starts and stops" ); |
171 | diag("Tests of abnormal conditions" ); |
172 | ok(0 == test_2_open_and_2_close(), |
173 | "test of two open and two close (strange call sequence)" ); |
174 | ok(0 == test_bad_magic_string(), "test of bad magic string" ); |
175 | ok(0 == test_bad_checksum(), "test of bad checksum" ); |
176 | ok(0 == test_bad_hchecksum(), "test of bad hchecksum" ); |
177 | ok(0 == test_future_size(), "test of ability to handlr future versions" ); |
178 | ok(0 == test_bad_blocksize(), "test of bad blocksize" ); |
179 | ok(0 == test_bad_size(), "test of too small/big file" ); |
180 | |
181 | delete_file(0); |
182 | rmdir(maria_data_root); |
183 | |
184 | my_uuid_end(); |
185 | my_end(0); |
186 | return exit_status(); |
187 | } |
188 | |
189 | |
190 | static int delete_file(myf my_flags) |
191 | { |
192 | RET_ERR_UNLESS(fn_format(file_name, CONTROL_FILE_BASE_NAME, |
193 | maria_data_root, "" , MYF(MY_WME)) != NullS); |
194 | /* |
195 | Maybe file does not exist, ignore error. |
196 | The error will however be printed on stderr. |
197 | */ |
198 | my_delete(file_name, my_flags); |
199 | expect_checkpoint_lsn= LSN_IMPOSSIBLE; |
200 | expect_logno= FILENO_IMPOSSIBLE; |
201 | expect_max_trid= expect_recovery_failures= 0; |
202 | |
203 | return 0; |
204 | } |
205 | |
206 | /* |
207 | Verifies that global values last_checkpoint_lsn, last_logno, |
208 | max_trid_in_control_file (belonging to the module) match what we expect. |
209 | */ |
210 | static int verify_module_values_match_expected(void) |
211 | { |
212 | RET_ERR_UNLESS(last_logno == expect_logno); |
213 | RET_ERR_UNLESS(last_checkpoint_lsn == expect_checkpoint_lsn); |
214 | RET_ERR_UNLESS(max_trid_in_control_file == expect_max_trid); |
215 | RET_ERR_UNLESS(recovery_failures == expect_recovery_failures); |
216 | return 0; |
217 | } |
218 | |
219 | |
220 | /* |
221 | Verifies that global values last_checkpoint_lsn and last_logno (belonging |
222 | to the module) are impossible (this is used when the file has been closed). |
223 | */ |
224 | static int verify_module_values_are_impossible(void) |
225 | { |
226 | RET_ERR_UNLESS(last_logno == FILENO_IMPOSSIBLE); |
227 | RET_ERR_UNLESS(last_checkpoint_lsn == LSN_IMPOSSIBLE); |
228 | RET_ERR_UNLESS(max_trid_in_control_file == 0); |
229 | return 0; |
230 | } |
231 | |
232 | |
233 | static int close_file(void) |
234 | { |
235 | /* Simulate shutdown */ |
236 | ma_control_file_end(); |
237 | /* Verify amnesia */ |
238 | RET_ERR_UNLESS(verify_module_values_are_impossible() == 0); |
239 | return 0; |
240 | } |
241 | |
242 | static int open_file(void) |
243 | { |
244 | RET_ERR_UNLESS(local_ma_control_file_open() == CONTROL_FILE_OK); |
245 | /* Check that the module reports expected information */ |
246 | RET_ERR_UNLESS(verify_module_values_match_expected() == 0); |
247 | return 0; |
248 | } |
249 | |
250 | static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid, |
251 | uint8 rec_failures) |
252 | { |
253 | RET_ERR_UNLESS(ma_control_file_write_and_force(checkpoint_lsn, logno, trid, |
254 | rec_failures) |
255 | == 0); |
256 | /* Check that the module reports expected information */ |
257 | RET_ERR_UNLESS(verify_module_values_match_expected() == 0); |
258 | return 0; |
259 | } |
260 | |
261 | static int test_one_log_and_recovery_failures(void) |
262 | { |
263 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
264 | expect_logno= 123; |
265 | RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno, |
266 | max_trid_in_control_file, |
267 | recovery_failures) == 0); |
268 | expect_recovery_failures= 158; |
269 | RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno, |
270 | max_trid_in_control_file, |
271 | expect_recovery_failures) == 0); |
272 | RET_ERR_UNLESS(close_file() == 0); |
273 | return 0; |
274 | } |
275 | |
276 | static int test_five_logs_and_max_trid(void) |
277 | { |
278 | uint i; |
279 | |
280 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
281 | expect_logno= 100; |
282 | expect_max_trid= 14111978111ULL; |
283 | for (i= 0; i<5; i++) |
284 | { |
285 | expect_logno*= 3; |
286 | RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno, |
287 | expect_max_trid, |
288 | recovery_failures) == 0); |
289 | } |
290 | RET_ERR_UNLESS(close_file() == 0); |
291 | return 0; |
292 | } |
293 | |
294 | static int test_3_checkpoints_and_2_logs(void) |
295 | { |
296 | /* |
297 | Simulate one checkpoint, one log creation, two checkpoints, one |
298 | log creation. |
299 | */ |
300 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
301 | expect_checkpoint_lsn= MAKE_LSN(5, 10000); |
302 | RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno, |
303 | max_trid_in_control_file, |
304 | recovery_failures) == 0); |
305 | |
306 | expect_logno= 17; |
307 | RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno, |
308 | max_trid_in_control_file, |
309 | recovery_failures) == 0); |
310 | |
311 | expect_checkpoint_lsn= MAKE_LSN(17, 20000); |
312 | RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno, |
313 | max_trid_in_control_file, |
314 | recovery_failures) == 0); |
315 | |
316 | expect_checkpoint_lsn= MAKE_LSN(17, 45000); |
317 | RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno, |
318 | max_trid_in_control_file, |
319 | recovery_failures) == 0); |
320 | |
321 | expect_logno= 19; |
322 | RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno, |
323 | max_trid_in_control_file, |
324 | recovery_failures) == 0); |
325 | RET_ERR_UNLESS(close_file() == 0); |
326 | return 0; |
327 | } |
328 | |
329 | static int test_binary_content(void) |
330 | { |
331 | uint i; |
332 | int fd; |
333 | |
334 | /* |
335 | TEST4: actually check by ourselves the content of the file. |
336 | Note that constants (offsets) are hard-coded here, precisely to prevent |
337 | someone from changing them in the control file module and breaking |
338 | backward-compatibility. |
339 | TODO: when we reach the format-freeze state, we may even just do a |
340 | comparison with a raw binary string, to not depend on any uint4korr |
341 | future change/breakage. |
342 | */ |
343 | |
344 | uchar buffer[45]; |
345 | RET_ERR_UNLESS((fd= my_open(file_name, |
346 | O_BINARY | O_RDWR, |
347 | MYF(MY_WME))) >= 0); |
348 | RET_ERR_UNLESS(my_read(fd, buffer, 45, MYF(MY_FNABP | MY_WME)) == 0); |
349 | RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0); |
350 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
351 | i= uint3korr(buffer + 34 ); |
352 | RET_ERR_UNLESS(i == LSN_FILE_NO(last_checkpoint_lsn)); |
353 | i= uint4korr(buffer + 37); |
354 | RET_ERR_UNLESS(i == LSN_OFFSET(last_checkpoint_lsn)); |
355 | i= uint4korr(buffer + 41); |
356 | RET_ERR_UNLESS(i == last_logno); |
357 | RET_ERR_UNLESS(close_file() == 0); |
358 | return 0; |
359 | } |
360 | |
361 | static int test_start_stop(void) |
362 | { |
363 | /* TEST5: Simulate start/nothing/stop/start/nothing/stop/start */ |
364 | |
365 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
366 | RET_ERR_UNLESS(close_file() == 0); |
367 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
368 | RET_ERR_UNLESS(close_file() == 0); |
369 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
370 | RET_ERR_UNLESS(close_file() == 0); |
371 | return 0; |
372 | } |
373 | |
374 | static int test_2_open_and_2_close(void) |
375 | { |
376 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
377 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
378 | RET_ERR_UNLESS(close_file() == 0); |
379 | RET_ERR_UNLESS(close_file() == 0); |
380 | return 0; |
381 | } |
382 | |
383 | |
384 | static int test_bad_magic_string(void) |
385 | { |
386 | uchar buffer[4]; |
387 | int fd; |
388 | |
389 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
390 | RET_ERR_UNLESS(close_file() == 0); |
391 | |
392 | /* Corrupt magic string */ |
393 | RET_ERR_UNLESS((fd= my_open(file_name, |
394 | O_BINARY | O_RDWR, |
395 | MYF(MY_WME))) >= 0); |
396 | RET_ERR_UNLESS(my_pread(fd, buffer, 4, 0, MYF(MY_FNABP | MY_WME)) == 0); |
397 | RET_ERR_UNLESS(my_pwrite(fd, (const uchar *)"papa" , 4, 0, |
398 | MYF(MY_FNABP | MY_WME)) == 0); |
399 | |
400 | /* Check that control file module sees the problem */ |
401 | RET_ERR_UNLESS(local_ma_control_file_open() == |
402 | CONTROL_FILE_BAD_MAGIC_STRING); |
403 | /* Restore magic string */ |
404 | RET_ERR_UNLESS(my_pwrite(fd, buffer, 4, 0, MYF(MY_FNABP | MY_WME)) == 0); |
405 | RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0); |
406 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
407 | RET_ERR_UNLESS(close_file() == 0); |
408 | return 0; |
409 | } |
410 | |
411 | static int test_bad_checksum(void) |
412 | { |
413 | uchar buffer[4]; |
414 | int fd; |
415 | |
416 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
417 | RET_ERR_UNLESS(close_file() == 0); |
418 | |
419 | /* Corrupt checksum */ |
420 | RET_ERR_UNLESS((fd= my_open(file_name, |
421 | O_BINARY | O_RDWR, |
422 | MYF(MY_WME))) >= 0); |
423 | RET_ERR_UNLESS(my_pread(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0); |
424 | buffer[0]+= 3; /* mangle checksum */ |
425 | RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0); |
426 | /* Check that control file module sees the problem */ |
427 | RET_ERR_UNLESS(local_ma_control_file_open() == |
428 | CONTROL_FILE_BAD_CHECKSUM); |
429 | /* Restore checksum */ |
430 | buffer[0]-= 3; |
431 | RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0); |
432 | RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0); |
433 | |
434 | return 0; |
435 | } |
436 | |
437 | |
438 | static int test_bad_blocksize(void) |
439 | { |
440 | maria_block_size<<= 1; |
441 | /* Check that control file module sees the problem */ |
442 | RET_ERR_UNLESS(local_ma_control_file_open() == |
443 | CONTROL_FILE_WRONG_BLOCKSIZE); |
444 | /* Restore blocksize */ |
445 | maria_block_size>>= 1; |
446 | |
447 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
448 | RET_ERR_UNLESS(close_file() == 0); |
449 | return 0; |
450 | } |
451 | |
452 | |
453 | static int test_future_size(void) |
454 | { |
455 | /* |
456 | Here we check ability to add fields only so we can use |
457 | defined constants |
458 | */ |
459 | uint32 sum; |
460 | int fd; |
461 | uchar buffer[CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE + 2]; |
462 | RET_ERR_UNLESS((fd= my_open(file_name, |
463 | O_BINARY | O_RDWR, |
464 | MYF(MY_WME))) >= 0); |
465 | RET_ERR_UNLESS(my_read(fd, buffer, |
466 | CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE, |
467 | MYF(MY_FNABP | MY_WME)) == 0); |
468 | RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0); |
469 | /* "add" new field of 1 byte (value 1) to header and variable part */ |
470 | memmove(buffer + CF_CREATE_TIME_TOTAL_SIZE + 1, |
471 | buffer + CF_CREATE_TIME_TOTAL_SIZE, |
472 | CF_CHANGEABLE_TOTAL_SIZE); |
473 | buffer[CF_CREATE_TIME_TOTAL_SIZE - CF_CHECKSUM_SIZE]= '\1'; |
474 | buffer[CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE + 1]= '\1'; |
475 | /* fix lengths */ |
476 | int2store(buffer + CF_CREATE_TIME_SIZE_OFFSET, CF_CREATE_TIME_TOTAL_SIZE + 1); |
477 | int2store(buffer + CF_CHANGEABLE_SIZE_OFFSET, CF_CHANGEABLE_TOTAL_SIZE + 1); |
478 | /* recalculete checksums */ |
479 | sum= (uint32) my_checksum(0, buffer, CF_CREATE_TIME_TOTAL_SIZE - |
480 | CF_CHECKSUM_SIZE + 1); |
481 | int4store(buffer + CF_CREATE_TIME_TOTAL_SIZE - CF_CHECKSUM_SIZE + 1, sum); |
482 | sum= (uint32) my_checksum(0, buffer + CF_CREATE_TIME_TOTAL_SIZE + 1 + |
483 | CF_CHECKSUM_SIZE, |
484 | CF_CHANGEABLE_TOTAL_SIZE - CF_CHECKSUM_SIZE + 1); |
485 | int4store(buffer + CF_CREATE_TIME_TOTAL_SIZE + 1, sum); |
486 | /* write new file and check it */ |
487 | RET_ERR_UNLESS((fd= my_open(file_name, |
488 | O_BINARY | O_RDWR, |
489 | MYF(MY_WME))) >= 0); |
490 | RET_ERR_UNLESS(my_pwrite(fd, buffer, |
491 | CF_CREATE_TIME_TOTAL_SIZE + |
492 | CF_CHANGEABLE_TOTAL_SIZE + 2, |
493 | 0, MYF(MY_FNABP | MY_WME)) == 0); |
494 | RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0); |
495 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
496 | RET_ERR_UNLESS(close_file() == 0); |
497 | |
498 | return(0); |
499 | } |
500 | |
501 | static int test_bad_hchecksum(void) |
502 | { |
503 | uchar buffer[4]; |
504 | int fd; |
505 | |
506 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
507 | RET_ERR_UNLESS(close_file() == 0); |
508 | |
509 | /* Corrupt checksum */ |
510 | RET_ERR_UNLESS((fd= my_open(file_name, |
511 | O_BINARY | O_RDWR, |
512 | MYF(MY_WME))) >= 0); |
513 | RET_ERR_UNLESS(my_pread(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0); |
514 | buffer[0]+= 3; /* mangle checksum */ |
515 | RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0); |
516 | /* Check that control file module sees the problem */ |
517 | RET_ERR_UNLESS(local_ma_control_file_open() == |
518 | CONTROL_FILE_BAD_HEAD_CHECKSUM); |
519 | /* Restore checksum */ |
520 | buffer[0]-= 3; |
521 | RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0); |
522 | RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0); |
523 | |
524 | return 0; |
525 | } |
526 | |
527 | |
528 | static int test_bad_size(void) |
529 | { |
530 | uchar buffer[]= |
531 | "123456789012345678901234567890123456789012345678901234567890123456" ; |
532 | int fd, i; |
533 | |
534 | /* A too short file */ |
535 | RET_ERR_UNLESS(delete_file(MYF(MY_WME)) == 0); |
536 | RET_ERR_UNLESS((fd= my_open(file_name, |
537 | O_BINARY | O_RDWR | O_CREAT, |
538 | MYF(MY_WME))) >= 0); |
539 | RET_ERR_UNLESS(my_write(fd, buffer, 10, MYF(MY_FNABP | MY_WME)) == 0); |
540 | /* Check that control file module sees the problem */ |
541 | RET_ERR_UNLESS(local_ma_control_file_open() == |
542 | CONTROL_FILE_TOO_SMALL); |
543 | for (i= 0; i < 8; i++) |
544 | { |
545 | RET_ERR_UNLESS(my_write(fd, buffer, 66, MYF(MY_FNABP | MY_WME)) == 0); |
546 | } |
547 | /* Check that control file module sees the problem */ |
548 | RET_ERR_UNLESS(local_ma_control_file_open() == |
549 | CONTROL_FILE_TOO_BIG); |
550 | RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0); |
551 | |
552 | /* Leave a correct control file */ |
553 | RET_ERR_UNLESS(delete_file(MYF(MY_WME)) == 0); |
554 | RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK); |
555 | RET_ERR_UNLESS(close_file() == 0); |
556 | |
557 | return 0; |
558 | } |
559 | |
560 | |
561 | static struct my_option my_long_options[] = |
562 | { |
563 | #ifndef DBUG_OFF |
564 | {"debug" , '#', "Debug log." , |
565 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
566 | #endif |
567 | {"help" , '?', "Display help and exit" , |
568 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
569 | {"version" , 'V', "Print version number and exit" , |
570 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
571 | { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} |
572 | }; |
573 | |
574 | |
575 | static void version(void) |
576 | { |
577 | printf("ma_control_file_test: unit test for the control file " |
578 | "module of the Aria storage engine. Ver 1.0 \n" ); |
579 | } |
580 | |
581 | static my_bool |
582 | get_one_option(int optid, const struct my_option *opt __attribute__((unused)), |
583 | char *argument __attribute__((unused))) |
584 | { |
585 | switch(optid) { |
586 | case 'V': |
587 | version(); |
588 | exit(0); |
589 | case '#': |
590 | DBUG_PUSH (argument); |
591 | break; |
592 | case '?': |
593 | version(); |
594 | usage(); |
595 | exit(0); |
596 | } |
597 | return 0; |
598 | } |
599 | |
600 | |
601 | /* Read options */ |
602 | |
603 | static void get_options(int argc, char *argv[]) |
604 | { |
605 | int ho_error; |
606 | |
607 | if ((ho_error=handle_options(&argc, &argv, my_long_options, |
608 | get_one_option))) |
609 | exit(ho_error); |
610 | |
611 | return; |
612 | } /* get options */ |
613 | |
614 | |
615 | static void usage(void) |
616 | { |
617 | printf("Usage: %s [options]\n\n" , my_progname); |
618 | my_print_help(my_long_options); |
619 | my_print_variables(my_long_options); |
620 | } |
621 | |
622 | #include "../ma_check_standalone.h" |
623 | |