diff options
-rw-r--r-- | client/mysql_upgrade.c | 1 | ||||
-rw-r--r-- | client/mysqltest.c | 736 | ||||
-rw-r--r-- | mysql-test/lib/mtr_process.pl | 21 | ||||
-rw-r--r-- | mysql-test/lib/mtr_report.pl | 108 | ||||
-rw-r--r-- | mysql-test/lib/mtr_timer.pl | 30 | ||||
-rwxr-xr-x | mysql-test/mysql-test-run.pl | 23 | ||||
-rw-r--r-- | mysql-test/r/mysqltest.result | 19 | ||||
-rw-r--r-- | mysql-test/t/bootstrap.test | 7 | ||||
-rw-r--r-- | mysql-test/t/csv.test | 5 | ||||
-rw-r--r-- | mysql-test/t/mysql.test | 3 | ||||
-rw-r--r-- | mysql-test/t/mysqladmin.test | 3 | ||||
-rw-r--r-- | mysql-test/t/mysqltest.test | 112 | ||||
-rw-r--r-- | mysql-test/t/sp-destruct.test | 1 |
13 files changed, 769 insertions, 300 deletions
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 5da0235c913..7a36a382c97 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -468,6 +468,7 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, NULL); my_close(fd, MYF(0)); + my_delete(query_file_path, MYF(0)); DBUG_RETURN(ret); } diff --git a/client/mysqltest.c b/client/mysqltest.c index 7ba57f7515c..a854becbda7 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -60,16 +60,10 @@ #define QUERY_SEND_FLAG 1 #define QUERY_REAP_FLAG 2 - enum { - RESULT_OK= 0, - RESULT_CONTENT_MISMATCH= 1, - RESULT_LENGTH_MISMATCH= 2 - }; - enum { OPT_SKIP_SAFEMALLOC=OPT_MAX_CLIENT_OPTION, OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, - OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR + OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES }; static int record= 0, opt_sleep= -1; @@ -103,6 +97,9 @@ static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer; static uint start_lineno= 0; /* Start line of current command */ static uint my_end_arg= 0; +/* Number of lines of the result to include in failure report */ +static uint opt_tail_lines= 0; + static char delimiter[MAX_DELIMITER_LENGTH]= ";"; static uint delimiter_length= 1; @@ -224,7 +221,7 @@ struct st_connection #endif /*EMBEDDED_LIBRARY*/ }; struct st_connection connections[128]; -struct st_connection* cur_con, *next_con, *connections_end; +struct st_connection* cur_con= NULL, *next_con, *connections_end; /* List of commands in mysqltest @@ -441,7 +438,6 @@ void free_tmp_sh_file(); void free_win_path_patterns(); #endif -static int eval_result = 0; /* For replace_column */ static char *replace_column[MAX_COLUMNS]; @@ -489,11 +485,11 @@ void handle_no_error(struct st_command*); pthread_attr_t cn_thd_attrib; /* - send_one_query executes query in separate thread what is + send_one_query executes query in separate thread, which is necessary in embedded library to run 'send' in proper way. This implementation doesn't handle errors returned by mysql_send_query. It's technically possible, though - i don't see where it is needed. + I don't see where it is needed. */ pthread_handler_t send_one_query(void *arg) { @@ -594,6 +590,77 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query, } +/* + Show any warnings just before the error. Since the last error + is added to the warning stack, only print @@warning_count-1 warnings. + + NOTE! This function should be safe to call when an error + has occured and this any further errors will be ignored(although logged) + + SYNOPSIS + show_warnings_before_error + mysql - connection to use + +*/ + +static void show_warnings_before_error(MYSQL* mysql) +{ + MYSQL_RES* res; + const char* query= "SHOW WARNINGS"; + DBUG_ENTER("show_warnings_before_error"); + + if (!mysql) + DBUG_VOID_RETURN; + + if (mysql_query(mysql, query)) + { + log_msg("Error running query '%s': %d %s", + query, mysql_errno(mysql), mysql_error(mysql)); + DBUG_VOID_RETURN; + } + + if ((res= mysql_store_result(mysql)) == NULL) + { + /* No result set returned */ + DBUG_VOID_RETURN; + } + + if (mysql_num_rows(res) <= 1) + { + /* Don't display the last row, it's "last error" */ + } + else + { + MYSQL_ROW row; + unsigned int row_num= 0; + unsigned int num_fields= mysql_num_fields(res); + + fprintf(stderr, "\nWarnings from just before the error:\n"); + while ((row= mysql_fetch_row(res))) + { + unsigned int i; + unsigned long *lengths= mysql_fetch_lengths(res); + + if (++row_num >= mysql_num_rows(res)) + { + /* Don't display the last row, it's "last error" */ + break; + } + + for(i= 0; i < num_fields; i++) + { + fprintf(stderr, "%.*s ", (int)lengths[i], + row[i] ? row[i] : "NULL"); + } + fprintf(stderr, "\n"); + } + } + mysql_free_result(res); + + DBUG_VOID_RETURN; +} + + enum arg_type { ARG_STRING, @@ -672,6 +739,15 @@ void check_command_args(struct st_command *command, command->first_word_len, command->query); } + /* Check for too many arguments passed */ + ptr= command->last_argument; + while(ptr <= command->end) + { + if (*ptr && *ptr != ' ') + die("Extra argument '%s' passed to '%.*s'", + ptr, command->first_word_len, command->query); + ptr++; + } DBUG_VOID_RETURN; } @@ -865,6 +941,24 @@ void die(const char *fmt, ...) fprintf(stderr, "\n"); fflush(stderr); + /* Show results from queries just before failure */ + if (ds_res.length && opt_tail_lines) + { + int tail_lines= opt_tail_lines; + char* show_from= ds_res.str + ds_res.length - 1; + while(show_from > ds_res.str && tail_lines > 0 ) + { + show_from--; + if (*show_from == '\n') + tail_lines--; + } + fprintf(stderr, "\nThe result from queries just before the failure was:\n"); + if (show_from > ds_res.str) + fprintf(stderr, "< snip >"); + fprintf(stderr, "%s", show_from); + fflush(stderr); + } + /* Dump the result that has been accumulated so far to .log file */ if (result_file_name && ds_res.length) dump_result_to_log_file(ds_res.str, ds_res.length); @@ -873,6 +967,13 @@ void die(const char *fmt, ...) if (result_file_name && ds_warning_messages.length) dump_warning_messages(); + /* + Help debugging by displaying any warnings that might have + been produced prior to the error + */ + if (cur_con) + show_warnings_before_error(&cur_con->mysql); + cleanup_and_exit(1); } @@ -976,11 +1077,10 @@ void warning_msg(const char *fmt, ...) void log_msg(const char *fmt, ...) { va_list args; - char buff[512]; + char buff[1024]; size_t len; DBUG_ENTER("log_msg"); - memset(buff, 0, sizeof(buff)); va_start(args, fmt); len= my_vsnprintf(buff, sizeof(buff)-1, fmt, args); va_end(args); @@ -993,77 +1093,372 @@ void log_msg(const char *fmt, ...) /* - Compare content of the string ds to content of file fname + Read a file and append it to ds + + SYNOPSIS + cat_file + ds - pointer to dynamic string where to add the files content + filename - name of the file to read + */ -int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) +void cat_file(DYNAMIC_STRING* ds, const char* filename) { - MY_STAT stat_info; - char *tmp, *res_ptr; - char eval_file[FN_REFLEN]; - int res; - uint res_len; int fd; - DYNAMIC_STRING res_ds; - DBUG_ENTER("dyn_string_cmp"); + uint len; + char buff[512]; - if (!test_if_hard_path(fname)) + if ((fd= my_open(filename, O_RDONLY, MYF(0))) < 0) + die("Failed to open file %s", filename); + while((len= my_read(fd, (uchar*)&buff, + sizeof(buff), MYF(0))) > 0) { - strxmov(eval_file, opt_basedir, fname, NullS); - fn_format(eval_file, eval_file, "", "", MY_UNPACK_FILENAME); + char *p= buff, *start= buff; + while (p < buff+len) + { + /* Convert cr/lf to lf */ + if (*p == '\r' && *(p+1) && *(p+1)== '\n') + { + /* Add fake newline instead of cr and output the line */ + *p= '\n'; + p++; /* Step past the "fake" newline */ + dynstr_append_mem(ds, start, p-start); + p++; /* Step past the "fake" newline */ + start= p; + } + else + p++; + } + /* Output any chars that migh be left */ + dynstr_append_mem(ds, start, p-start); } - else - fn_format(eval_file, fname, "", "", MY_UNPACK_FILENAME); + my_close(fd, MYF(0)); +} - if (!my_stat(eval_file, &stat_info, MYF(MY_WME))) - die(NullS); - if (!eval_result && (uint) stat_info.st_size != ds->length) + +/* + Run the specified command with popen + + SYNOPSIS + run_command + cmd - command to execute(should be properly quoted + ds_res- pointer to dynamic string where to store the result + +*/ + +static int run_command(char* cmd, + DYNAMIC_STRING *ds_res) +{ + char buf[512]= {0}; + FILE *res_file; + int error; + + if (!(res_file= popen(cmd, "r"))) + die("popen(\"%s\", \"r\") failed", cmd); + + while (fgets(buf, sizeof(buf), res_file)) + { + DBUG_PRINT("info", ("buf: %s", buf)); + if(ds_res) + { + /* Save the output of this command in the supplied string */ + dynstr_append(ds_res, buf); + } + else + { + /* Print it directly on screen */ + fprintf(stdout, "%s", buf); + } + } + + error= pclose(res_file); + return WEXITSTATUS(error); +} + + +/* + Run the specified tool with variable number of arguments + + SYNOPSIS + run_tool + tool_path - the name of the tool to run + ds_res - pointer to dynamic string where to store the result + ... - variable number of arguments that will be properly + quoted and appended after the tool's name + +*/ + +static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...) +{ + int ret; + const char* arg; + va_list args; + DYNAMIC_STRING ds_cmdline; + + DBUG_ENTER("run_tool"); + DBUG_PRINT("enter", ("tool_path: %s", tool_path)); + + if (init_dynamic_string(&ds_cmdline, IF_WIN("\"", ""), FN_REFLEN, FN_REFLEN)) + die("Out of memory"); + + dynstr_append_os_quoted(&ds_cmdline, tool_path, NullS); + dynstr_append(&ds_cmdline, " "); + + va_start(args, ds_res); + + while ((arg= va_arg(args, char *))) { - DBUG_PRINT("info",("Size differs: result size: %u file size: %lu", - (uint) ds->length, (ulong) stat_info.st_size)); - DBUG_PRINT("info",("result: '%s'", ds->str)); - DBUG_RETURN(RESULT_LENGTH_MISMATCH); + /* Options should be os quoted */ + if (strncmp(arg, "--", 2) == 0) + dynstr_append_os_quoted(&ds_cmdline, arg, NullS); + else + dynstr_append(&ds_cmdline, arg); + dynstr_append(&ds_cmdline, " "); } - if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME)))) + + va_end(args); + +#ifdef __WIN__ + dynstr_append(&ds_cmdline, "\""); +#endif + + DBUG_PRINT("info", ("Running: %s", ds_cmdline.str)); + ret= run_command(ds_cmdline.str, ds_res); + DBUG_PRINT("exit", ("ret: %d", ret)); + dynstr_free(&ds_cmdline); + DBUG_RETURN(ret); +} + + +/* + Show the diff of two files using the systems builtin diff + command. If no such diff command exist, just dump the content + of the two files and inform about how to get "diff" + + SYNOPSIS + show_diff + ds - pointer to dynamic string where to add the diff(may be NULL) + filename1 - name of first file + filename2 - name of second file + +*/ + +void show_diff(DYNAMIC_STRING* ds, + const char* filename1, const char* filename2) +{ + + DYNAMIC_STRING ds_tmp; + + if (init_dynamic_string(&ds_tmp, "", 256, 256)) die("Out of memory"); - if ((fd = my_open(eval_file, O_RDONLY, MYF(MY_WME))) < 0) - die("Failed to open file %s", eval_file); - if (my_read(fd, (uchar*)tmp, stat_info.st_size, MYF(MY_WME|MY_NABP))) - die("Failed to read from file %s, errno: %d", eval_file, errno); - tmp[stat_info.st_size] = 0; - init_dynamic_string(&res_ds, "", stat_info.st_size+256, 256); - if (eval_result) - { - do_eval(&res_ds, tmp, tmp + stat_info.st_size, FALSE); - res_ptr= res_ds.str; - res_len= res_ds.length; - if (res_len != ds->length) + /* First try with unified diff */ + if (run_tool("diff", + &ds_tmp, /* Get output from diff in ds_tmp */ + "-u", + filename1, + filename2, + "2>&1", + NULL) > 1) /* Most "diff" tools return >1 if error */ + { + dynstr_set(&ds_tmp, ""); + + /* Fallback to context diff with "diff -c" */ + if (run_tool("diff", + &ds_tmp, /* Get output from diff in ds_tmp */ + "-c", + filename1, + filename2, + "2>&1", + NULL) > 1) /* Most "diff" tools return >1 if error */ { - res= RESULT_LENGTH_MISMATCH; - goto err; + /* + Fallback to dump both files to result file and inform + about installing "diff" + */ + dynstr_set(&ds_tmp, ""); + + dynstr_append(&ds_tmp, +"\n" +"The two files differ but it was not possible to execute 'diff' in\n" +"order to show only the difference, tried both 'diff -u' or 'diff -c'.\n" +"Instead the whole content of the two files was shown for you to diff manually. ;)\n\n" +"To get a better report you should install 'diff' on your system, which you\n" +"for example can get from http://www.gnu.org/software/diffutils/diffutils.html\n" +#ifdef __WIN__ +"or http://gnuwin32.sourceforge.net/packages/diffutils.htm\n" +#endif +"\n"); + + dynstr_append(&ds_tmp, " --- "); + dynstr_append(&ds_tmp, filename1); + dynstr_append(&ds_tmp, " >>>\n"); + cat_file(&ds_tmp, filename1); + dynstr_append(&ds_tmp, "<<<\n --- "); + dynstr_append(&ds_tmp, filename1); + dynstr_append(&ds_tmp, " >>>\n"); + cat_file(&ds_tmp, filename2); + dynstr_append(&ds_tmp, "<<<<\n"); } } + + if (ds) + { + /* Add the diff to output */ + dynstr_append_mem(ds, ds_tmp.str, ds_tmp.length); + } else { - res_ptr = tmp; - res_len = stat_info.st_size; + /* Print diff directly to stdout */ + fprintf(stderr, "%s\n", ds_tmp.str); } + + dynstr_free(&ds_tmp); - res= (memcmp(res_ptr, ds->str, res_len)) ? - RESULT_CONTENT_MISMATCH : RESULT_OK; +} -err: - if (res && eval_result) - str_to_file(fn_format(eval_file, fname, "", ".eval", - MY_REPLACE_EXT), - res_ptr, res_len); - dynstr_free(&res_ds); - my_free(tmp, MYF(0)); - my_close(fd, MYF(MY_WME)); +enum compare_files_result_enum { + RESULT_OK= 0, + RESULT_CONTENT_MISMATCH= 1, + RESULT_LENGTH_MISMATCH= 2 +}; + +/* + Compare two files, given a fd to the first file and + name of the second file + + SYNOPSIS + compare_files2 + fd - Open file descriptor of the first file + filename2 - Name of second file + + RETURN VALUES + According to the values in "compare_files_result_enum" + +*/ + +int compare_files2(File fd, const char* filename2) +{ + int error= RESULT_OK; + File fd2; + uint len, len2; + char buff[512], buff2[512]; + + if ((fd2= my_open(filename2, O_RDONLY, MYF(0))) < 0) + { + my_close(fd, MYF(0)); + die("Failed to open second file: %s", filename2); + } + while((len= my_read(fd, (uchar*)&buff, + sizeof(buff), MYF(0))) > 0) + { + if ((len2= my_read(fd2, (uchar*)&buff2, + sizeof(buff2), MYF(0))) < len) + { + /* File 2 was smaller */ + error= RESULT_LENGTH_MISMATCH; + break; + } + if (len2 > len) + { + /* File 1 was smaller */ + error= RESULT_LENGTH_MISMATCH; + break; + } + if ((memcmp(buff, buff2, len))) + { + /* Content of this part differed */ + error= RESULT_CONTENT_MISMATCH; + break; + } + } + if (!error && my_read(fd2, (uchar*)&buff2, + sizeof(buff2), MYF(0)) > 0) + { + /* File 1 was smaller */ + error= RESULT_LENGTH_MISMATCH; + } + + my_close(fd2, MYF(0)); - DBUG_RETURN(res); + return error; +} + + +/* + Compare two files, given their filenames + + SYNOPSIS + compare_files + filename1 - Name of first file + filename2 - Name of second file + + RETURN VALUES + See 'compare_files2' + +*/ + +int compare_files(const char* filename1, const char* filename2) +{ + File fd; + int error; + + if ((fd= my_open(filename1, O_RDONLY, MYF(0))) < 0) + die("Failed to open first file: %s", filename1); + + error= compare_files2(fd, filename2); + + my_close(fd, MYF(0)); + + return error; +} + + +/* + Compare content of the string in ds to content of file fname + + SYNOPSIS + dyn_string_cmp + ds - Dynamic string containing the string o be compared + fname - Name of file to compare with + + RETURN VALUES + See 'compare_files2' +*/ + +int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) +{ + int error; + File fd; + char ds_temp_file_path[FN_REFLEN]; + + DBUG_ENTER("dyn_string_cmp"); + DBUG_PRINT("enter", ("fname: %s", fname)); + + if ((fd= create_temp_file(ds_temp_file_path, NULL, + "tmp", O_CREAT | O_SHARE | O_RDWR, + MYF(MY_WME))) < 0) + die("Failed to create temporary file for ds"); + + /* Write ds to temporary file and set file pos to beginning*/ + if (my_write(fd, ds->str, ds->length, + MYF(MY_FNABP | MY_WME)) || + my_seek(fd, 0, SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR) + { + my_close(fd, MYF(0)); + /* Remove the temporary file */ + my_delete(ds_temp_file_path, MYF(0)); + die("Failed to write to '%s'", ds_temp_file_path); + } + + error= compare_files2(fd, fname); + + my_close(fd, MYF(0)); + /* Remove the temporary file */ + my_delete(ds_temp_file_path, MYF(0)); + + DBUG_RETURN(error); } @@ -1081,20 +1476,33 @@ err: void check_result(DYNAMIC_STRING* ds) { + const char* mess= "Result content mismatch\n"; + DBUG_ENTER("check_result"); DBUG_ASSERT(result_file_name); + DBUG_PRINT("enter", ("result_file_name: %s", result_file_name)); switch (dyn_string_cmp(ds, result_file_name)) { case RESULT_OK: break; /* ok */ case RESULT_LENGTH_MISMATCH: - dump_result_to_reject_file(ds->str, ds->length); - die("Result length mismatch"); - break; + mess= "Result length mismatch\n"; + /* Fallthrough */ case RESULT_CONTENT_MISMATCH: - dump_result_to_reject_file(ds->str, ds->length); - die("Result content mismatch"); + { + /* Result mismatched, dump results to .reject file and then show the diff */ + char reject_file[FN_REFLEN]; + fn_format(reject_file, result_file_name, "", ".reject", + MY_REPLACE_EXT); + DBUG_PRINT("enter", ("reject_file_name: %s", reject_file)); + str_to_file(reject_file, ds->str, ds->length); + + dynstr_set(ds, NULL); /* Don't create a .log file */ + + show_diff(NULL, result_file_name, reject_file); + die(mess); break; + } default: /* impossible */ die("Unknown error code from dyn_string_cmp()"); } @@ -1109,7 +1517,7 @@ void check_result(DYNAMIC_STRING* ds) indicating that test is not supported SYNOPSIS - check_result + check_require ds - content to be checked fname - name of file to check against @@ -1439,40 +1847,22 @@ void var_query_set(VAR *var, const char *query, const char** query_end) die("Query '%s' didn't return a result set", ds_query.str); dynstr_free(&ds_query); - if ((row = mysql_fetch_row(res)) && row[0]) + if ((row= mysql_fetch_row(res)) && row[0]) { /* - Concatenate all row results with tab in between to allow us to work - with results from many columns (for example from SHOW VARIABLES) + Concatenate all fields in the first row with tab in between + and assign that string to the $variable */ DYNAMIC_STRING result; uint i; ulong *lengths; -#ifdef NOT_YET - MYSQL_FIELD *fields= mysql_fetch_fields(res); -#endif - init_dynamic_string(&result, "", 2048, 2048); + init_dynamic_string(&result, "", 512, 512); lengths= mysql_fetch_lengths(res); - for (i=0; i < mysql_num_fields(res); i++) + for (i= 0; i < mysql_num_fields(res); i++) { - if (row[0]) + if (row[i]) { -#ifdef NOT_YET - /* Add to <var_name>_<col_name> */ - uint j; - char var_col_name[MAX_VAR_NAME_LENGTH]; - uint length= snprintf(var_col_name, MAX_VAR_NAME_LENGTH, - "$%s_%s", var->name, fields[i].name); - /* Convert characters not allowed in variable names to '_' */ - for (j= 1; j < length; j++) - { - if (!my_isvar(charset_info,var_col_name[j])) - var_col_name[j]= '_'; - } - var_set(var_col_name, var_col_name + length, - row[i], row[i] + lengths[i]); -#endif /* Add column to tab separated string */ dynstr_append_mem(&result, row[i], lengths[i]); } @@ -1514,7 +1904,7 @@ void var_query_set(VAR *var, const char *query, const char** query_end) void var_set_query_get_value(struct st_command *command, VAR *var) { - ulong row_no; + long row_no; int col_no= -1; MYSQL_RES* res; MYSQL* mysql= &cur_con->mysql; @@ -1586,7 +1976,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var) { /* Get the value */ MYSQL_ROW row; - ulong rows= 0; + long rows= 0; const char* value= "No such row"; while ((row= mysql_fetch_row(res))) @@ -1953,7 +2343,7 @@ void do_exec(struct st_command *command) if (command->abort_on_error) { - log_msg("exec of '%s failed, error: %d, status: %d, errno: %d", + log_msg("exec of '%s' failed, error: %d, status: %d, errno: %d", ds_cmd.str, error, status, errno); dynstr_free(&ds_cmd); die("command \"%s\" failed", command->first_argument); @@ -2196,8 +2586,8 @@ void do_copy_file(struct st_command *command) command command handle DESCRIPTION - chmod <octal> <file> - Change file permission of <file> + chmod_file <octal> <file_name> + Change file permission of <file_name> */ @@ -2207,8 +2597,8 @@ void do_chmod_file(struct st_command *command) static DYNAMIC_STRING ds_mode; static DYNAMIC_STRING ds_file; const struct command_arg chmod_file_args[] = { - { "mode", ARG_STRING, TRUE, &ds_mode, "Mode of file" }, - { "file", ARG_STRING, TRUE, &ds_file, "Filename of file to modify" } + { "mode", ARG_STRING, TRUE, &ds_mode, "Mode of file(octal) ex. 0660"}, + { "filename", ARG_STRING, TRUE, &ds_file, "Filename of file to modify" } }; DBUG_ENTER("do_chmod_file"); @@ -2303,8 +2693,22 @@ void read_until_delimiter(DYNAMIC_STRING *ds, c= my_getc(cur_file->file); if (c == '\n') + { cur_file->lineno++; + /* Skip newline from the same line as the command */ + if (start_lineno == (cur_file->lineno - 1)) + continue; + } + else if (start_lineno == cur_file->lineno) + { + /* + No characters except \n are allowed on + the same line as the command + */ + die("Trailing characters found after command"); + } + if (feof(cur_file->file)) die("End of file encountered before '%s' delimiter was found", ds_delimiter->str); @@ -2342,6 +2746,12 @@ void do_write_file_command(struct st_command *command, my_bool append) if (ds_delimiter.length == 0) dynstr_set(&ds_delimiter, "EOF"); + if (!append && access(ds_filename.str, F_OK) == 0) + { + /* The file should not be overwritten */ + die("File already exist: '%s'", ds_filename.str); + } + init_dynamic_string(&ds_content, "", 1024, 1024); read_until_delimiter(&ds_content, &ds_delimiter); DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str)); @@ -2374,7 +2784,7 @@ void do_write_file_command(struct st_command *command, my_bool append) Write everything between the "write_file" command and 'delimiter' to "file_name" - NOTE! Overwrites existing file + NOTE! Will fail if <file_name> exists Default <delimiter> is EOF @@ -2431,9 +2841,6 @@ void do_append_file(struct st_command *command) void do_cat_file(struct st_command *command) { - int fd; - uint len; - char buff[512]; static DYNAMIC_STRING ds_filename; const struct command_arg cat_file_args[] = { { "filename", ARG_STRING, TRUE, &ds_filename, "File to read from" } @@ -2448,37 +2855,13 @@ void do_cat_file(struct st_command *command) DBUG_PRINT("info", ("Reading from, file: %s", ds_filename.str)); - if ((fd= my_open(ds_filename.str, O_RDONLY, MYF(0))) < 0) - die("Failed to open file %s", ds_filename.str); - while((len= my_read(fd, (uchar*)&buff, - sizeof(buff), MYF(0))) > 0) - { - char *p= buff, *start= buff; - while (p < buff+len) - { - /* Convert cr/lf to lf */ - if (*p == '\r' && *(p+1) && *(p+1)== '\n') - { - /* Add fake newline instead of cr and output the line */ - *p= '\n'; - p++; /* Step past the "fake" newline */ - dynstr_append_mem(&ds_res, start, p-start); - p++; /* Step past the "fake" newline */ - start= p; - } - else - p++; - } - /* Output any chars that migh be left */ - dynstr_append_mem(&ds_res, start, p-start); - } - my_close(fd, MYF(0)); + cat_file(&ds_res, ds_filename.str); + dynstr_free(&ds_filename); DBUG_VOID_RETURN; } - /* SYNOPSIS do_diff_files @@ -2494,9 +2877,6 @@ void do_cat_file(struct st_command *command) void do_diff_files(struct st_command *command) { int error= 0; - int fd, fd2; - uint len, len2; - char buff[512], buff2[512]; static DYNAMIC_STRING ds_filename; static DYNAMIC_STRING ds_filename2; const struct command_arg diff_file_args[] = { @@ -2511,39 +2891,14 @@ void do_diff_files(struct st_command *command) sizeof(diff_file_args)/sizeof(struct command_arg), ' '); - if ((fd= my_open(ds_filename.str, O_RDONLY, MYF(0))) < 0) - die("Failed to open first file %s", ds_filename.str); - if ((fd2= my_open(ds_filename2.str, O_RDONLY, MYF(0))) < 0) + if ((error= compare_files(ds_filename.str, ds_filename2.str))) { - my_close(fd, MYF(0)); - die("Failed to open second file %s", ds_filename2.str); - } - while((len= my_read(fd, (uchar*)&buff, - sizeof(buff), MYF(0))) > 0) - { - if ((len2= my_read(fd2, (uchar*)&buff2, - sizeof(buff2), MYF(0))) != len) - { - /* File 2 was smaller */ - error= 1; - break; - } - if ((memcmp(buff, buff2, len))) - { - /* Content of this part differed */ - error= 1; - break; - } - } - if (my_read(fd2, (uchar*)&buff2, - sizeof(buff2), MYF(0)) > 0) - { - /* File 1 was smaller */ - error= 1; + /* Compare of the two files failed, append them to output + so the failure can be analyzed + */ + show_diff(&ds_res, ds_filename.str, ds_filename2.str); } - my_close(fd, MYF(0)); - my_close(fd2, MYF(0)); dynstr_free(&ds_filename); dynstr_free(&ds_filename2); handle_command_error(command, error); @@ -2614,8 +2969,10 @@ void do_send_quit(struct st_command *command) void do_perl(struct st_command *command) { int error; - char buf[FN_REFLEN]; + File fd; FILE *res_file; + char buf[FN_REFLEN]; + char temp_file_path[FN_REFLEN]; static DYNAMIC_STRING ds_script; static DYNAMIC_STRING ds_delimiter; const struct command_arg perl_args[] = { @@ -2638,14 +2995,17 @@ void do_perl(struct st_command *command) DBUG_PRINT("info", ("Executing perl: %s", ds_script.str)); - /* Format a name for a tmp .pl file that is unique for this process */ - my_snprintf(buf, sizeof(buf), "%s/tmp/tmp_%d.pl", - getenv("MYSQLTEST_VARDIR"), getpid()); - str_to_file(buf, ds_script.str, ds_script.length); + /* Create temporary file name */ + if ((fd= create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"), + "tmp", O_CREAT | O_SHARE | O_RDWR, + MYF(MY_WME))) < 0) + die("Failed to create temporary file for perl command"); + my_close(fd, MYF(0)); - /* Format the perl <filename> command */ - my_snprintf(buf, sizeof(buf), "perl %s/tmp/tmp_%d.pl", - getenv("MYSQLTEST_VARDIR"), getpid()); + str_to_file(temp_file_path, ds_script.str, ds_script.length); + + /* Format the "perl <filename>" command */ + my_snprintf(buf, sizeof(buf), "perl %s", temp_file_path); if (!(res_file= popen(buf, "r")) && command->abort_on_error) die("popen(\"%s\", \"r\") failed", buf); @@ -2663,6 +3023,10 @@ void do_perl(struct st_command *command) } } error= pclose(res_file); + + /* Remove the temporary file */ + my_delete(temp_file_path, MYF(0)); + handle_command_error(command, WEXITSTATUS(error)); dynstr_free(&ds_script); dynstr_free(&ds_delimiter); @@ -3788,7 +4152,7 @@ void do_connect(struct st_command *command) mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_NAME, charset_info->csname); if (opt_charsets_dir) - mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_DIR, + mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_DIR, opt_charsets_dir); #ifdef HAVE_OPENSSL @@ -4401,7 +4765,7 @@ void check_eol_junk(const char *eol) terminated by new line '\n' regardless how many "delimiter" it contain. */ -#define MAX_QUERY (256*1024) /* 256K -- a test in sp-big is >128K */ +#define MAX_QUERY (256*1024*2) /* 256K -- a test in sp-big is >128K */ static char read_command_buf[MAX_QUERY]; int read_command(struct st_command** command_ptr) @@ -4449,9 +4813,13 @@ int read_command(struct st_command** command_ptr) if (!(command->query_buf= command->query= my_strdup(p, MYF(MY_WME)))) die("Out of memory"); - /* Calculate first word and first argument */ - for (p= command->query; *p && !my_isspace(charset_info, *p) ; p++) ; + /* Calculate first word length(the command), terminated by space or ( */ + p= command->query; + while (*p && !my_isspace(charset_info, *p) && *p != '(') + p++; command->first_word_len= (uint) (p - command->query); + DBUG_PRINT("info", ("first_word: %.*s", + command->first_word_len, command->query)); /* Skip spaces between command and first argument */ while (*p && my_isspace(charset_info, *p)) @@ -4541,6 +4909,10 @@ static struct my_option my_long_options[] = {"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select", (uchar**) &sp_protocol, (uchar**) &sp_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"tail-lines", OPT_TAIL_LINES, + "Number of lines of the resul to include in a failure report", + (uchar**) &opt_tail_lines, (uchar**) &opt_tail_lines, 0, + GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0}, #include "sslopt-longopts.h" {"test-file", 'x', "Read test from/in this file (default stdin).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -4797,14 +5169,6 @@ void str_to_file(const char *fname, char *str, int size) } -void dump_result_to_reject_file(char *buf, int size) -{ - char reject_file[FN_REFLEN]; - str_to_file(fn_format(reject_file, result_file_name, "", ".reject", - MY_REPLACE_EXT), - buf, size); -} - void dump_result_to_log_file(char *buf, int size) { char log_file[FN_REFLEN]; @@ -4812,6 +5176,8 @@ void dump_result_to_log_file(char *buf, int size) *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT : MY_REPLACE_EXT), buf, size); + fprintf(stderr, "\nMore results from queries before failure can be found in %s\n", + log_file); } void dump_progress(void) @@ -5793,7 +6159,7 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) init_dynamic_string(&ds_warnings, NULL, 0, 256); - /* Scan for warning before sendign to server */ + /* Scan for warning before sending to server */ scan_command_for_warnings(command); /* @@ -6225,7 +6591,6 @@ int main(int argc, char **argv) connections_end= connections + (sizeof(connections)/sizeof(struct st_connection)) - 1; next_con= connections + 1; - cur_con= connections; #ifdef EMBEDDED_LIBRARY /* set appropriate stack for the 'query' threads */ @@ -6301,6 +6666,7 @@ int main(int argc, char **argv) if (cursor_protocol_enabled) ps_protocol_enabled= 1; + cur_con= connections; if (!( mysql_init(&cur_con->mysql))) die("Failed in mysql_init()"); if (opt_compress) @@ -6425,7 +6791,7 @@ int main(int argc, char **argv) break; case Q_LET: do_let(command); break; case Q_EVAL_RESULT: - eval_result = 1; break; + die("'eval_result' command is deprecated"); case Q_EVAL: case Q_QUERY_VERTICAL: case Q_QUERY_HORIZONTAL: diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 69026d2c72f..8fd900330da 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -99,25 +99,26 @@ sub spawn_impl ($$$$$$$) { if ( $::opt_script_debug ) { - print STDERR "\n"; - print STDERR "#### ", "-" x 78, "\n"; - print STDERR "#### ", "STDIN $input\n" if $input; - print STDERR "#### ", "STDOUT $output\n" if $output; - print STDERR "#### ", "STDERR $error\n" if $error; - print STDERR "#### ", "$mode : $path ", join(" ",@$arg_list_t), "\n"; - print STDERR "#### ", "spawn options:\n"; + mtr_report(""); + mtr_debug("-" x 73); + mtr_debug("STDIN $input") if $input; + mtr_debug("STDOUT $output") if $output; + mtr_debug("STDERR $error") if $error; + mtr_debug("$mode: $path ", join(" ",@$arg_list_t)); + mtr_debug("spawn options:"); if ($spawn_opts) { foreach my $key (sort keys %{$spawn_opts}) { - print STDERR "#### ", " - $key: $spawn_opts->{$key}\n"; + mtr_debug(" - $key: $spawn_opts->{$key}"); } } else { - print STDERR "#### ", " none\n"; + mtr_debug(" none"); } - print STDERR "#### ", "-" x 78, "\n"; + mtr_debug("-" x 73); + mtr_report(""); } mtr_error("Can't spawn with empty \"path\"") unless defined $path; diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 1edace54d30..dcd7d1ec842 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -19,6 +19,7 @@ # same name. use strict; +use warnings; sub mtr_report_test_name($); sub mtr_report_test_passed($); @@ -26,7 +27,6 @@ sub mtr_report_test_failed($); sub mtr_report_test_skipped($); sub mtr_report_test_not_skipped_though_disabled($); -sub mtr_show_failed_diff ($); sub mtr_report_stats ($); sub mtr_print_line (); sub mtr_print_thick_line (); @@ -38,6 +38,9 @@ sub mtr_child_error (@); sub mtr_debug (@); sub mtr_verbose (@); +my $tot_real_time= 0; + + ############################################################################## # @@ -45,43 +48,10 @@ sub mtr_verbose (@); # ############################################################################## -# We can't use diff -u or diff -a as these are not portable - -sub mtr_show_failed_diff ($) { - my $tinfo= shift; - - # The reject and log files have been dumped to - # to filenames based on the result_file's name - my $base_file= mtr_match_extension($tinfo->{'result_file'}, - "result"); # Trim extension - my $reject_file= "$base_file.reject"; - my $result_file= "$base_file.result"; - my $log_file= "$base_file.log"; - - my $diffopts= $::opt_udiff ? "-u" : "-c"; - - if ( -f $reject_file ) - { - print "Below are the diffs between actual and expected results:\n"; - print "-------------------------------------------------------\n"; - # FIXME check result code?! - mtr_run("diff",[$diffopts,$result_file,$reject_file], "", "", "", ""); - print "-------------------------------------------------------\n"; - print "Please follow the instructions outlined at\n"; - print "http://www.mysql.com/doc/en/Reporting_mysqltest_bugs.html\n"; - print "to find the reason to this problem and how to report this.\n\n"; - } - - if ( -f $log_file ) - { - print "Result from queries before failure can be found in $log_file\n"; - # FIXME Maybe a tail -f -n 10 $log_file here - } -} - sub mtr_report_test_name ($) { my $tinfo= shift; + _mtr_log("$tinfo->{name}"); printf "%-30s ", $tinfo->{'name'}; } @@ -91,15 +61,15 @@ sub mtr_report_test_skipped ($) { $tinfo->{'result'}= 'MTR_RES_SKIPPED'; if ( $tinfo->{'disable'} ) { - print "[ disabled ] $tinfo->{'comment'}\n"; + mtr_report("[ disabled ] $tinfo->{'comment'}"); } elsif ( $tinfo->{'comment'} ) { - print "[ skipped ] $tinfo->{'comment'}\n"; + mtr_report("[ skipped ] $tinfo->{'comment'}"); } else { - print "[ skipped ]\n"; + mtr_report("[ skipped ]"); } } @@ -127,11 +97,11 @@ sub mtr_report_test_passed ($) { if ( $::opt_timer and -f "$::opt_vardir/log/timer" ) { $timer= mtr_fromfile("$::opt_vardir/log/timer"); - $::glob_tot_real_time += ($timer/1000); + $tot_real_time += ($timer/1000); $timer= sprintf "%12s", $timer; } $tinfo->{'result'}= 'MTR_RES_PASSED'; - print "[ pass ] $timer\n"; + mtr_report("[ pass ] $timer"); } sub mtr_report_test_failed ($) { @@ -140,27 +110,34 @@ sub mtr_report_test_failed ($) { $tinfo->{'result'}= 'MTR_RES_FAILED'; if ( defined $tinfo->{'timeout'} ) { - print "[ fail ] timeout\n"; + mtr_report("[ fail ] timeout"); return; } else { - print "[ fail ]\n"; + mtr_report("[ fail ]"); } if ( $tinfo->{'comment'} ) { - print "\nERROR: $tinfo->{'comment'}\n"; + # The test failure has been detected by mysql-test-run.pl + # when starting the servers or due to other error, the reason for + # failing the test is saved in "comment" + mtr_report("\nERROR: $tinfo->{'comment'}"); } elsif ( -f $::path_timefile ) { - print "\nErrors are (from $::path_timefile) :\n"; + # Test failure was detected by test tool and it's report + # about what failed has been saved to file. Display the report. + print "\n"; print mtr_fromfile($::path_timefile); # FIXME print_file() instead - print "\n(the last lines may be the most important ones)\n"; + print "\n"; } else { - print "\nUnexpected termination, probably when starting mysqld\n"; + # Neither this script or the test tool has recorded info + # about why the test has failed. Should be debugged. + mtr_report("\nUnexpected termination, probably when starting mysqld");; } } @@ -228,8 +205,10 @@ sub mtr_report_stats ($) { if ( $::opt_timer ) { - print - "Spent $::glob_tot_real_time seconds actually executing testcases\n" + use English; + + mtr_report("Spent", sprintf("%.3f", $tot_real_time),"of", + time - $BASETIME, "seconds executing testcases"); } # ---------------------------------------------------------------------- @@ -484,35 +463,66 @@ sub mtr_print_header () { ############################################################################## # -# Misc +# Log and reporting functions # ############################################################################## +use IO::File; + +my $log_file_ref= undef; + +sub mtr_log_init ($) { + my ($filename)= @_; + + mtr_error("Log is already open") if defined $log_file_ref; + + $log_file_ref= IO::File->new($filename, "a") or + mtr_warning("Could not create logfile $filename: $!"); +} + +sub _mtr_log (@) { + print $log_file_ref join(" ", @_),"\n" + if defined $log_file_ref; +} + sub mtr_report (@) { + # Print message to screen and log + _mtr_log(@_); print join(" ", @_),"\n"; } sub mtr_warning (@) { + # Print message to screen and log + _mtr_log("WARNING: ", @_); print STDERR "mysql-test-run: WARNING: ",join(" ", @_),"\n"; } sub mtr_error (@) { + # Print message to screen and log + _mtr_log("ERROR: ", @_); print STDERR "mysql-test-run: *** ERROR: ",join(" ", @_),"\n"; mtr_exit(1); } sub mtr_child_error (@) { + # Print message to screen and log + _mtr_log("ERROR(child): ", @_); print STDERR "mysql-test-run: *** ERROR(child): ",join(" ", @_),"\n"; exit(1); } sub mtr_debug (@) { + # Only print if --script-debug is used if ( $::opt_script_debug ) { + _mtr_log("###: ", @_); print STDERR "####: ",join(" ", @_),"\n"; } } + sub mtr_verbose (@) { + # Always print to log, print to screen only when --verbose is used + _mtr_log("> ",@_); if ( $::opt_verbose ) { print STDERR "> ",join(" ", @_),"\n"; diff --git a/mysql-test/lib/mtr_timer.pl b/mysql-test/lib/mtr_timer.pl index 86a9f58514f..d8b6953fb46 100644 --- a/mysql-test/lib/mtr_timer.pl +++ b/mysql-test/lib/mtr_timer.pl @@ -52,12 +52,10 @@ sub mtr_init_timers () { sub mtr_timer_start($$$) { my ($timers,$name,$duration)= @_; - mtr_verbose("mtr_timer_start: $name, $duration"); - if ( exists $timers->{'timers'}->{$name} ) { # We have an old running timer, kill it - mtr_verbose("There is an old timer running"); + mtr_warning("There is an old timer running"); mtr_timer_stop($timers,$name); } @@ -75,22 +73,22 @@ sub mtr_timer_start($$$) { } else { - mtr_error("can't fork"); + mtr_error("can't fork timer, error: $!"); } } if ( $tpid ) { # Parent, record the information - mtr_verbose("timer parent, record info($name, $tpid, $duration)"); + mtr_verbose("Starting timer for '$name',", + "duration: $duration, pid: $tpid"); $timers->{'timers'}->{$name}->{'pid'}= $tpid; $timers->{'timers'}->{$name}->{'duration'}= $duration; $timers->{'pids'}->{$tpid}= $name; } else { - # Child, redirect output and exec - # FIXME do we need to redirect streams? + # Child, install signal handlers and sleep for "duration" # Don't do the ^C cleanup in the timeout child processes! # There is actually a race here, if we get ^C after fork(), but before @@ -98,13 +96,13 @@ sub mtr_timer_start($$$) { $SIG{INT}= 'DEFAULT'; $SIG{TERM}= sub { - mtr_verbose("timer woke up, exiting!"); + mtr_verbose("timer $$ woke up, exiting!"); exit(0); }; $0= "mtr_timer(timers,$name,$duration)"; sleep($duration); - mtr_verbose("timer expired after $duration seconds"); + mtr_verbose("timer $$ expired after $duration seconds"); exit(0); } } @@ -114,12 +112,10 @@ sub mtr_timer_start($$$) { sub mtr_timer_stop ($$) { my ($timers,$name)= @_; - mtr_verbose("mtr_timer_stop: $name"); - if ( exists $timers->{'timers'}->{$name} ) { my $tpid= $timers->{'timers'}->{$name}->{'pid'}; - mtr_verbose("Stopping timer with pid $tpid"); + mtr_verbose("Stopping timer for '$name' with pid $tpid"); # FIXME as Cygwin reuses pids fast, maybe check that is # the expected process somehow?! @@ -134,11 +130,8 @@ sub mtr_timer_stop ($$) { return 1; } - else - { - mtr_error("Asked to stop timer \"$name\" not started"); - return 0; - } + + mtr_error("Asked to stop timer '$name' not started"); } @@ -158,7 +151,8 @@ sub mtr_timer_timeout ($$) { return "" unless exists $timers->{'pids'}->{$pid}; - # We got a timeout, return the name ot the timer + # Got a timeout(the process with $pid is recorded as being a timer) + # return the name of the timer return $timers->{'pids'}->{$pid}; } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 22b9499c37a..b6b349a9fde 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -83,7 +83,6 @@ require "lib/mtr_io.pl"; require "lib/mtr_gcov.pl"; require "lib/mtr_gprof.pl"; require "lib/mtr_report.pl"; -require "lib/mtr_diff.pl"; require "lib/mtr_match.pl"; require "lib/mtr_misc.pl"; require "lib/mtr_stress.pl"; @@ -282,8 +281,6 @@ our $opt_wait_for_slave; our $opt_warnings; -our $opt_udiff; - our $opt_skip_ndbcluster= 0; our $opt_skip_ndbcluster_slave= 0; our $opt_with_ndbcluster= 0; @@ -307,7 +304,6 @@ our @data_dir_lst; our $used_binlog_format; our $used_default_engine; our $debug_compiled_binaries; -our $glob_tot_real_time= 0; our %mysqld_variables; @@ -619,7 +615,6 @@ sub command_line_setup () { 'start-dirty' => \$opt_start_dirty, 'start-and-exit' => \$opt_start_and_exit, 'timer!' => \$opt_timer, - 'unified-diff|udiff' => \$opt_udiff, 'user=s' => \$opt_user, 'testcase-timeout=i' => \$opt_testcase_timeout, 'suite-timeout=i' => \$opt_suite_timeout, @@ -2944,6 +2939,9 @@ sub initialize_servers () { } } check_running_as_root(); + + mtr_log_init("$opt_vardir/log/mysql-test-run.log"); + } sub mysql_install_db () { @@ -3672,7 +3670,6 @@ sub report_failure_and_restart ($) { my $tinfo= shift; mtr_report_test_failed($tinfo); - mtr_show_failed_diff($tinfo); print "\n"; if ( $opt_force ) { @@ -3681,13 +3678,13 @@ sub report_failure_and_restart ($) { # Restore the snapshot of the installed test db restore_installed_db($tinfo->{'name'}); - print "Resuming Tests\n\n"; + mtr_report("Resuming Tests\n"); return; } my $test_mode= join(" ", @::glob_test_mode) || "default"; - print "Aborting: $tinfo->{'name'} failed in $test_mode mode. "; - print "To continue, re-run with '--force'.\n"; + mtr_report("Aborting: $tinfo->{'name'} failed in $test_mode mode. "); + mtr_report("To continue, re-run with '--force'."); if ( ! $glob_debugger and ! $opt_extern and ! $glob_use_embedded_server ) @@ -4146,11 +4143,11 @@ sub mysqld_start ($$$) { sub stop_all_servers () { - print "Stopping All Servers\n"; + mtr_report("Stopping All Servers"); if ( ! $opt_skip_im ) { - print "Shutting-down Instance Manager\n"; + mtr_report("Shutting-down Instance Manager"); unless (mtr_im_stop($instance_manager, "stop_all_servers")) { mtr_error("Failed to stop Instance Manager.") @@ -4860,6 +4857,9 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--test-file=%s", $tinfo->{'path'}); + # Number of lines of resut to include in failure report + mtr_add_arg($args, "--tail-lines=20"); + if ( defined $tinfo->{'result_file'} ) { mtr_add_arg($args, "--result-file=%s", $tinfo->{'result_file'}); } @@ -5273,7 +5273,6 @@ Misc options fast Don't try to clean up from earlier runs reorder Reorder tests to get fewer server restarts help Get this help text - unified-diff | udiff When presenting differences, use unified diff testcase-timeout=MINUTES Max test case run time (default $default_testcase_timeout) suite-timeout=MINUTES Max test suite run time (default $default_suite_timeout) diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 55f78d22272..202acfa3065 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -280,6 +280,18 @@ let $B = changed value of B; var2: content of variable 1 var3: content of variable 1 content of variable 1 length of var3 is longer than 0 +var1 +hi 1 hi there +var2 +2 +var2 again +2 +var3 two columns with same name +1 2 3 +var4 from query that returns NULL +var5 from query that returns no row +failing query in let +mysqltest: At line 1: Error running query 'failing query': 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'failing query' at line 1 mysqltest: At line 1: Missing required argument 'filename' to command 'source' mysqltest: At line 1: Could not open file ./non_existingFile mysqltest: In included file "MYSQLTEST_VARDIR/tmp/recursive.sql": At line 1: Source directives are nesting too deep @@ -461,7 +473,6 @@ root@localhost -------------------------------------------------------------------------------- this will be executed this will be executed -mysqltest: Result length mismatch mysqltest: The test didn't produce any output Failing multi statement query mysqltest: At line 3: query 'create table t1 (a int primary key); @@ -473,6 +484,8 @@ mysqltest: At line 3: query 'create table t1 (a int primary key); insert into t1 values (1); select 'select-me'; insertz 'error query'' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertz 'error query'' at line 1 + +More results from queries before failure can be found in MYSQLTEST_VARDIR/log/bug11731.log drop table t1; Multi statement using expected error create table t1 (a int primary key); @@ -520,6 +533,8 @@ drop table t1; mysqltest: At line 1: Missing required argument 'filename' to command 'remove_file' mysqltest: At line 1: Missing required argument 'filename' to command 'write_file' mysqltest: At line 1: End of file encountered before 'EOF' delimiter was found +Content for test_file1 +mysqltest: At line 1: File already exist: 'MYSQLTEST_VARDIR/tmp/test_file1.tmp' Some data for cat_file command of mysqltest @@ -530,7 +545,7 @@ mysqltest: At line 1: Missing required argument 'to_file' to command 'copy_file' mysqltest: At line 1: Missing required argument 'mode' to command 'chmod' mysqltest: At line 1: You must write a 4 digit octal number for mode mysqltest: At line 1: You must write a 4 digit octal number for mode -mysqltest: At line 1: Missing required argument 'file' to command 'chmod' +mysqltest: At line 1: Missing required argument 'filename' to command 'chmod' mysqltest: At line 1: You must write a 4 digit octal number for mode mysqltest: At line 1: You must write a 4 digit octal number for mode hello diff --git a/mysql-test/t/bootstrap.test b/mysql-test/t/bootstrap.test index 1c2952e93d0..203ba9b2914 100644 --- a/mysql-test/t/bootstrap.test +++ b/mysql-test/t/bootstrap.test @@ -9,12 +9,13 @@ drop table if exists t1; # # Check that --bootstrap reads from stdin # ---write_file $MYSQLTEST_VARDIR/tmp/bootstrap.sql +--write_file $MYSQLTEST_VARDIR/tmp/bootstrap_test.sql use test; CREATE TABLE t1(a int); EOF ---exec $MYSQLD_BOOTSTRAP_CMD < $MYSQLTEST_VARDIR/tmp/bootstrap.sql >> $MYSQLTEST_VARDIR/tmp/bootstrap.log 2>&1 +--exec $MYSQLD_BOOTSTRAP_CMD < $MYSQLTEST_VARDIR/tmp/bootstrap_test.sql >> $MYSQLTEST_VARDIR/tmp/bootstrap.log 2>&1 drop table t1; +remove_file $MYSQLTEST_VARDIR/tmp/bootstrap_test.sql; # # Check that --bootstrap of file with SQL error returns error @@ -28,6 +29,7 @@ EOF # Table t1 should not exists --error 1051 drop table t1; +remove_file $MYSQLTEST_VARDIR/tmp/bootstrap_error.sql; # # Bootstrap with a query larger than 2*thd->net.max_packet @@ -40,6 +42,7 @@ eval select * into outfile '$MYSQLTEST_VARDIR/tmp/long_query.sql' from t1; --enable_query_log --error 1 --exec $MYSQLD_BOOTSTRAP_CMD < $MYSQLTEST_VARDIR/tmp/long_query.sql >> $MYSQLTEST_VARDIR/tmp/bootstrap.log 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/long_query.sql; set global max_allowed_packet=@my_max_allowed_packet; drop table t1; diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test index 4aff4b27976..5c877557dfc 100644 --- a/mysql-test/t/csv.test +++ b/mysql-test/t/csv.test @@ -1424,6 +1424,7 @@ DROP TABLE test_repair_table2; # Corrupt csv file and see if we can repair it CREATE TABLE test_repair_table3 ( val integer ) ENGINE = CSV; +--remove_file $MYSQLTEST_VARDIR/master-data/test/test_repair_table3.CSV --write_file $MYSQLTEST_VARDIR/master-data/test/test_repair_table3.CSV "1" "4" @@ -1476,6 +1477,7 @@ CREATE TABLE test_repair_table5 ( ) ENGINE = CSV; # Corrupt a table -- put a file with wrong # of columns +--remove_file $MYSQLTEST_VARDIR/master-data/test/test_repair_table5.CSV --write_file $MYSQLTEST_VARDIR/master-data/test/test_repair_table5.CSV "1","101","IBM" EOF @@ -1629,6 +1631,7 @@ insert into bug22080_1 values(2,'string'); insert into bug22080_1 values(3,'string'); # Create first corrupt file as described in bug report +--remove_file $MYSQLTEST_VARDIR/master-data/test/bug22080_2.CSV --write_file $MYSQLTEST_VARDIR/master-data/test/bug22080_2.CSV 1,"string" 2","string" @@ -1636,6 +1639,7 @@ insert into bug22080_1 values(3,'string'); EOF # Create second corrupt file as described in bug report +--remove_file $MYSQLTEST_VARDIR/master-data/test/bug22080_3.CSV --write_file $MYSQLTEST_VARDIR/master-data/test/bug22080_3.CSV 1,"string" "2",string" @@ -1696,6 +1700,7 @@ check table t1; drop table t1; create table t1(a int, b int) engine=csv; +--remove_file $MYSQLTEST_VARDIR/master-data/test/t1.CSV --write_file $MYSQLTEST_VARDIR/master-data/test/t1.CSV 1, 1E-2 -2E2, .9 diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 16f5fecf051..ac713d49b92 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -242,18 +242,21 @@ DELIMITER / SELECT 1/ EOF --exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug21412.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/bug21412.sql; # This should give an error... --write_file $MYSQLTEST_VARDIR/tmp/bug21412.sql DELIMITER \ EOF --exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug21412.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/bug21412.sql; # As should this... --write_file $MYSQLTEST_VARDIR/tmp/bug21412.sql DELIMITER \\ EOF --exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug21412.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/bug21412.sql; # # Some coverage of not normally used parts diff --git a/mysql-test/t/mysqladmin.test b/mysql-test/t/mysqladmin.test index 3fa03fa910e..839ecf00b60 100644 --- a/mysql-test/t/mysqladmin.test +++ b/mysql-test/t/mysqladmin.test @@ -20,7 +20,7 @@ EOF --replace_regex /.*mysqladmin.*: unknown/mysqladmin: unknown/ --error 7 --exec $MYSQLADMIN --defaults-file=$MYSQLTEST_VARDIR/tmp/bug10608.cnf -S $MASTER_MYSOCK -P $MASTER_MYPORT -u root --password= ping 2>&1 - +remove_file $MYSQLTEST_VARDIR/tmp/bug10608.cnf; # When mysqladmin finds "loose-database" in .cnf file it shall print # a warning and continue @@ -32,3 +32,4 @@ EOF --replace_regex /Warning: .*mysqladmin.*: unknown/Warning: mysqladmin: unknown/ --exec $MYSQLADMIN --defaults-file=$MYSQLTEST_VARDIR/tmp/bug10608.cnf -S $MASTER_MYSOCK -P $MASTER_MYPORT -u root --password= ping 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/bug10608.cnf; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index b01579dce53..661fd302a1e 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -366,6 +366,7 @@ show status; EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; # # Missing delimiter until eof @@ -377,6 +378,7 @@ sleep 7 EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; # # Missing delimiter until "disable_query_log" @@ -391,6 +393,7 @@ disable_query_log; EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; # # Missing delimiter until "disable_query_log" @@ -406,6 +409,7 @@ disable_query_log; EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; # # Missing delimiter until eof @@ -422,6 +426,7 @@ disconnect default EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; # # Missing delimiter until eof @@ -436,6 +441,8 @@ EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; + # # Extra delimiter # @@ -734,38 +741,40 @@ if (`select length("$var3") > 0`) # Test to assign let from query # let $<var_name>=`<query>`; # ---------------------------------------------------------------------------- ---disable_parsing echo var1; let $var1= `select "hi" as "Col", 1 as "Column1", "hi there" as Col3`; echo $var1; -echo $var1_Col; -echo $var1_Column1; -echo $var1_Col3; echo var2; let $var2= `select 2 as "Column num 2"`; echo $var2; -echo $var2_Column num 2; -echo $var2_Column; echo var2 again; let $var2= `select 2 as "Column num 2"`; echo $var2; -echo $var2_Column num 2; -echo $var2_Column_num_2; -echo $var2_Column; echo var3 two columns with same name; let $var3= `select 1 as "Col", 2 as "Col", 3 as "var3"`; echo $var3; -echo $var3_Col; -echo $var3_Col; -echo $var3_var3; -#echo failing query in let; -#--error 1 -#--exec echo "let $var2= `failing query;`" | $MYSQL_TEST 2>&1 ---enable_parsing +echo var4 from query that returns NULL; +let $var4= `select NULL`; + +echo var5 from query that returns no row; +let $var5= `SHOW VARIABLES LIKE "nonexisting_variable"`; + +echo failing query in let; +--write_file $MYSQLTEST_VARDIR/tmp/let.sql +let $var2= `failing query`; +echo $var2; +EOF + +--error 1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/let.sql 2>&1 + +remove_file $MYSQLTEST_VARDIR/tmp/let.sql; + + # ---------------------------------------------------------------------------- # Test source command # ---------------------------------------------------------------------------- @@ -786,6 +795,7 @@ echo $var3_var3; --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1 --exec echo "source $MYSQLTEST_VARDIR/tmp/recursive.sql;" | $MYSQL_TEST 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/recursive.sql; # Source a file with error --exec echo "garbage ;" > $MYSQLTEST_VARDIR/tmp/error.sql @@ -793,6 +803,7 @@ echo $var3_var3; --error 1 --exec echo "source $MYSQLTEST_VARDIR/tmp/error.sql;" | $MYSQL_TEST 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/error.sql; # Test execution of source in a while loop --write_file $MYSQLTEST_VARDIR/tmp/sourced.inc @@ -963,7 +974,7 @@ if (!$counter) echo Counter is not 0, (counter=10); } let $counter=0; -if ($counter) +if($counter) { echo Counter is greater than 0, (counter=0); } @@ -1156,6 +1167,7 @@ echo hej; EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; --write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql while (0) @@ -1163,6 +1175,7 @@ while (0) EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; --write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql while (0){ @@ -1171,6 +1184,8 @@ EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; + # ---------------------------------------------------------------------------- # Test error messages returned from comments starting with a command # ---------------------------------------------------------------------------- @@ -1262,6 +1277,7 @@ while ($i) } EOF --exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql; echo OK;" | $MYSQL_TEST 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; # Repeat connect/disconnect --write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql @@ -1276,6 +1292,7 @@ EOF --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1 --exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql;" | $MYSQL_TEST 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; # Select disconnected connection --write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql @@ -1286,6 +1303,7 @@ EOF --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1 --exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql;" | $MYSQL_TEST 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; # Connection name already used --write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql @@ -1296,6 +1314,8 @@ EOF --error 1 --exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql;" | $MYSQL_TEST 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; + # connect when "disable_abort_on_error" caused "connection not found" --replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT --disable_abort_on_error @@ -1399,7 +1419,11 @@ select "this will be executed"; --exec touch $MYSQLTEST_VARDIR/tmp/zero_length_file.result --exec echo "echo ok;" > $MYSQLTEST_VARDIR/tmp/query.sql --error 1 ---exec $MYSQL_TEST -x $MYSQLTEST_VARDIR/tmp/query.sql -R $MYSQLTEST_VARDIR/tmp/zero_length_file.result 2>&1 +--exec $MYSQL_TEST -x $MYSQLTEST_VARDIR/tmp/query.sql -R $MYSQLTEST_VARDIR/tmp/zero_length_file.result > /dev/null 2>&1 + +remove_file $MYSQLTEST_VARDIR/tmp/zero_length_file.result; +remove_file $MYSQLTEST_VARDIR/tmp/zero_length_file.reject; + # # Test that a test file that does not generate any output fails. # @@ -1407,6 +1431,8 @@ select "this will be executed"; --error 1 --exec $MYSQL_TEST -x $MYSQLTEST_VARDIR/tmp/query.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/query.sql; + # # Test that mysqltest fails when there are no queries executed # but a result file exists @@ -1436,6 +1462,7 @@ echo Failing multi statement query; --exec $MYSQL_TEST -x $MYSQLTEST_VARDIR/tmp/bug11731.sql 2>&1 drop table t1; +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1 --exec $MYSQL_TEST --record -x $MYSQLTEST_VARDIR/tmp/bug11731.sql -R $MYSQLTEST_VARDIR/tmp/bug11731.out 2>&1 # The .out file should be non existent @@ -1462,6 +1489,9 @@ drop table t1; # The .out file should exist --exec test -s $MYSQLTEST_VARDIR/tmp/bug11731.out drop table t1; +remove_file $MYSQLTEST_VARDIR/tmp/bug11731.out; +remove_file $MYSQLTEST_VARDIR/log/bug11731.log; +remove_file $MYSQLTEST_VARDIR/tmp/bug11731.sql; # # Bug#19890 mysqltest: "query" command is broken @@ -1544,12 +1574,19 @@ write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; Content for test_file1 EOF file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +cat_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp END_DELIMITER; Content for test_file1 contains EOF END_DELIMITER file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; + +# write to already exisiting file +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error 1 +--exec echo "write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp;" | $MYSQL_TEST 2>&1 + remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; # ---------------------------------------------------------------------------- @@ -1571,6 +1608,8 @@ append_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; Appended text on nonexisting file EOF +remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; + # ---------------------------------------------------------------------------- # test for cat_file # ---------------------------------------------------------------------------- @@ -1581,6 +1620,7 @@ for cat_file command of mysqltest EOF cat_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; --error 1 --exec echo "cat_file non_existing_file;" | $MYSQL_TEST 2>&1 @@ -1607,19 +1647,48 @@ for diff_file command of mysqltest EOF +--write_file $MYSQLTEST_VARDIR/tmp/diff4.tmp +Some data +for diff_file command +of musqltest +EOF + # Compare equal files --diff_files $MYSQLTEST_VARDIR/tmp/diff1.tmp $MYSQLTEST_VARDIR/tmp/diff2.tmp --diff_files $MYSQLTEST_VARDIR/tmp/diff2.tmp $MYSQLTEST_VARDIR/tmp/diff1.tmp -# Compare files that differ +# Write the below commands to a intermediary file and execute them with +# mysqltest in --exec, since the output will vary depending on what "diff" +# is available it is sent to /dev/null +--write_file $MYSQLTEST_VARDIR/tmp/diff.test +# Compare files that differ in size +--error 2 +--diff_files $MYSQLTEST_VARDIR/tmp/diff1.tmp $MYSQLTEST_VARDIR/tmp/diff3.tmp +--error 2 +--diff_files $MYSQLTEST_VARDIR/tmp/diff3.tmp $MYSQLTEST_VARDIR/tmp/diff1.tmp + +# Compare files that differ only in content --error 1 ---diff_files $MYSQLTEST_VARDIR/tmp/diff3.tmp $MYSQLTEST_VARDIR/tmp/diff2.tmp +--diff_files $MYSQLTEST_VARDIR/tmp/diff1.tmp $MYSQLTEST_VARDIR/tmp/diff4.tmp --error 1 ---diff_files $MYSQLTEST_VARDIR/tmp/diff1.tmp $MYSQLTEST_VARDIR/tmp/diff3.tmp +--diff_files $MYSQLTEST_VARDIR/tmp/diff4.tmp $MYSQLTEST_VARDIR/tmp/diff1.tmp +EOF + +# Execute the above diffs, and send their output to /dev/null - only +# interesting to see that it returns correct error codes +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/diff.test > /dev/null 2>&1 + # Compare equal files, again... --diff_files $MYSQLTEST_VARDIR/tmp/diff1.tmp $MYSQLTEST_VARDIR/tmp/diff2.tmp +--remove_file $MYSQLTEST_VARDIR/tmp/diff1.tmp +--remove_file $MYSQLTEST_VARDIR/tmp/diff2.tmp +--remove_file $MYSQLTEST_VARDIR/tmp/diff3.tmp +--remove_file $MYSQLTEST_VARDIR/tmp/diff4.tmp +--remove_file $MYSQLTEST_VARDIR/tmp/diff.test + + # ---------------------------------------------------------------------------- # test for file_exist # ---------------------------------------------------------------------------- @@ -1672,6 +1741,7 @@ chmod 0000 $MYSQLTEST_VARDIR/tmp/file1.tmp; #EOF chmod 0777 $MYSQLTEST_VARDIR/tmp/file1.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/file1.tmp; --write_file $MYSQLTEST_VARDIR/tmp/file1.tmp test2 EOF diff --git a/mysql-test/t/sp-destruct.test b/mysql-test/t/sp-destruct.test index 04a581ab45f..56d99c4435c 100644 --- a/mysql-test/t/sp-destruct.test +++ b/mysql-test/t/sp-destruct.test @@ -50,6 +50,7 @@ insert into t1 values (0); flush table mysql.proc; # Thrashing the .frm file +--remove_file $MYSQLTEST_VARDIR/master-data/mysql/proc.frm --write_file $MYSQLTEST_VARDIR/master-data/mysql/proc.frm saljdfa EOF |