mysqltest的最新版本是V3.3。本文分析的代碼來自mysql-5.5.27,
下載地址http://www.mysql.com/downloads/mirror.php?id=408971(記得跳過登錄選擇“No thanks,just start my download!”)
mysqltest是mysql自帶的測試引擎,代碼有10000多行,源碼放在client目錄(使用libmysql)下,它實現了一種小語言,用來描述測試過程,並將測試結果與預期對比。小語言按照語法大致分爲三類:mysql command,sql,comment。sql和comment很容易理解,前者是mysql支持的sql,後者是註釋,一般用來描述測試過程。而mysql command雖然沒有高級語言(python,c)等強大,但也實現了測試控制最基本的語法,比如變量賦值、流程控制(if/while)、打印等等,以及mysql測試特有的一些指令(比如disable_query_log)。mysqltest的工作原理在測試領域很普遍,對於質量保證的同學,掌握它的實現非常有價值,可以順利的移植到其他系統的測試。
開頭便能看到以下的註釋:
- /*
- mysqltest
- Tool used for executing a .test file
- See the "MySQL Test framework manual" for more information
- http://dev.mysql.com/doc/mysqltest/en/index.html
- Please keep the test framework tools identical in all versions!
- */
- #define MTEST_VERSION "3.3"
mysqltest解釋的是以test爲後綴名的文本文件,具體的用法可以參考mysql官方的介紹。
一. 主要數據結構
1. 錯誤信息
--error指定的錯誤碼保存在一個元素類型爲st_match_err的數組裏面,每一個元素都記錄了error number或者sqlstate字符串。當有元素的matcho_err_type值爲ERR_EMPTY,表示結束。sql語句的執行結果會與它比較。
- enum match_err_type
- {
- ERR_EMPTY= 0,
- ERR_ERRNO,
- ERR_SQ
- struct st_match_err
- {
- enum match_err_type type;
- union
- {
- uint errnum;
- char sqlstate[SQLSTATE_LENGTH+1]; /* \0 terminated string */
- } code;
- };
- struct st_expected_errors
- {
- struct st_match_err err[10];
- uint count;
- };
- static struct st_expected_errors saved_expected_errors;
sql語句執行失敗後會有錯誤碼,錯誤碼是個非負整數(uint errnum),會對應一種錯誤類型,可以查看mysqld_error.h, 在該版本中最小值爲1000,最大值爲1727:
- #define ER_ERROR_FIRST 1000
- #define ER_HASHCHK 1000
- #define ER_NISAMCHK 1001
- #define ER_NO 1002
- ...
- #define ER_UNSUPPORTED_ENGINE 1726
- #define ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST 1727
- #define ER_ERROR_LAST 1727
從數據結構看出,錯誤碼errnum也可以用sqlstate字符串替換,編寫預期錯誤的時候二者選其一即可,用type區分。type有3個值: ERR_EMPTY= 0, ERR_ERRNO, ERR_SQLSTATE,分別對應未指定錯誤碼,error number,sqlstate。 sqlstate是sql標準規定的狀態碼,5個字節,表示不同的錯誤類型,所有的數據庫系統都要遵循這個標準,error number與sqlstate的對應關係由數據庫決定,mysql在sql_state.h 中有定義,關於sqlstate詳細可查看http://developer.mimer.com/documentation/html_92/Mimer_SQL_Mobile_DocSet/App_Return_Codes2.html。編寫CASE的時候mysqltest爲了區分這兩種類型,sqlstate前面需要加上S作爲開頭。
2 連接管理
EMBEDDED_LIBRARY暫時不關注。
向mysqld server發送query需要先建立連接,st_connection封裝了MYSQL(libmysql)數據結構。
- struct st_connection
- {
- MYSQL mysql;
- /* Used when creating views and sp, to avoid implicit commit */
- MYSQL* util_mysql;
- char *name;
- size_t name_len;
- MYSQL_STMT* stmt;
- /* Set after send to disallow other queries before reap */
- my_bool pending;
- #ifdef EMBEDDED_LIBRARY
- pthread_t tid;
- const char *cur_query;
- int cur_query_len;
- int command, result;
- pthread_mutex_t query_mutex;
- pthread_cond_t query_cond;
- pthread_mutex_t result_mutex;
- pthread_cond_t result_cond;
- int query_done;
- my_bool has_thread;
- #endif /*EMBEDDED_LIBRARY*/
- };
- struct st_connection *connections= NULL;
- struct st_connection* cur_con= NULL, *next_con, *connections_end;
3. mysqltest command
enum_command與commad_name數組必須一一對應起來,新的命令也必須加到QUNKNOWN前面。
- enum enum_commands {
- Q_CONNECTION=1, Q_QUERY,
- Q_CONNECT, Q_SLEEP, Q_REAL_SLEEP,
- Q_INC, Q_DEC,
- Q_SOURCE, Q_DISCONNECT,
- Q_LET, Q_ECHO,
- Q_WHILE, Q_END_BLOCK,
- Q_SYSTEM, Q_RESULT,
- Q_REQUIRE, Q_SAVE_MASTER_POS,
- Q_SYNC_WITH_MASTER,
- Q_SYNC_SLAVE_WITH_MASTER,
- Q_ERROR,
- Q_SEND, Q_REAP,
- Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN,
- Q_PING, Q_EVAL,
- Q_EVAL_RESULT,
- Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
- Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
- Q_ENABLE_CONNECT_LOG, Q_DISABLE_CONNECT_LOG,
- Q_WAIT_FOR_SLAVE_TO_STOP,
- Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS,
- Q_ENABLE_INFO, Q_DISABLE_INFO,
- Q_ENABLE_METADATA, Q_DISABLE_METADATA,
- Q_EXEC, Q_DELIMITER,
- Q_DISABLE_ABORT_ON_ERROR, Q_ENABLE_ABORT_ON_ERROR,
- Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS,
- Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, Q_SORTED_RESULT,
- Q_LOWERCASE,
- Q_START_TIMER, Q_END_TIMER,
- Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL,
- Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
- Q_IF,
- Q_DISABLE_PARSING, Q_ENABLE_PARSING,
- Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST,
- Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP,
- Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES,
- Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR,
- Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE,
- Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER,
- Q_RESULT_FORMAT_VERSION,
- Q_MOVE_FILE, Q_REMOVE_FILES_WILDCARD, Q_SEND_EVAL,
- Q_UNKNOWN, /* Unknown command. */
- Q_COMMENT, /* Comments, ignored. */
- Q_COMMENT_WITH_COMMAND,
- Q_EMPTY_LINE
- };
- const char *command_names[]=
- {
- "connection",
- "query",
- "connect",
- "sleep",
- "real_sleep",
- "inc",
- "dec",
- "source",
- "disconnect",
- "let",
- "echo",
- "while",
- "end",
- "system",
- "result",
- "require",
- "save_master_pos",
- "sync_with_master",
- "sync_slave_with_master",
- "error",
- "send",
- "reap",
- "dirty_close",
- "replace_result",
- "replace_column",
- "ping",
- "eval",
- "eval_result",
- /* Enable/disable that the _query_ is logged to result file */
- "enable_query_log",
- "disable_query_log",
- /* Enable/disable that the _result_ from a query is logged to result file */
- "enable_result_log",
- "disable_result_log",
- "enable_connect_log",
- "disable_connect_log",
- "wait_for_slave_to_stop",
- "enable_warnings",
- "disable_warnings",
- "enable_info",
- "disable_info",
- "enable_metadata",
- "disable_metadata",
- "exec",
- "delimiter",
- "disable_abort_on_error",
- "enable_abort_on_error",
- "vertical_results",
- "horizontal_results",
- "query_vertical",
- "query_horizontal",
- "sorted_result",
- "lowercase_result",
- "start_timer",
- "end_timer",
- "character_set",
- "disable_ps_protocol",
- "enable_ps_protocol",
- "disable_reconnect",
- "enable_reconnect",
- "if",
- "disable_parsing",
- "enable_parsing",
- "replace_regex",
- "remove_file",
- "file_exists",
- "write_file",
- "copy_file",
- "perl",
- "die",
- /* Don't execute any more commands, compare result */
- "exit",
- "skip",
- "chmod",
- "append_file",
- "cat_file",
- "diff_files",
- "send_quit",
- "change_user",
- "mkdir",
- "rmdir",
- "list_files",
- "list_files_write_file",
- "list_files_append_file",
- "send_shutdown",
- "shutdown_server",
- "result_format",
- "move_file",
- "remove_files_wildcard",
- "send_eval",
- 0
- };
註釋也作爲一種特殊的command保存在這個地方。
- struct st_command
- {
- char *query, *query_buf,*first_argument,*last_argument,*end;
- DYNAMIC_STRING content;
- int first_word_len, query_len;
- my_bool abort_on_error, used_replace;
- struct st_expected_errors expected_errors;
- char require_file[FN_REFLEN];
- enum enum_commands type;
- };
- struct st_command *curr_command= 0;
對test文件中的command的描述全部保存在st_command結構體。
to do
二. 主要函數
to do