特性介紹 | MySQL測試框架 MTR 系列教學(四):語法篇

2023-07-07 06:00:36

作者:盧文雙 資深資料庫核心研發

序言

以前對 MySQL 測試框架 MTR 的使用,主要集中於 SQL 正確性驗證。近期由於工作需要,深入瞭解了 MTR 的方方面面,發現 MTR 的能力不僅限於此,還支援單元測試、壓力測試、程式碼覆蓋率測試、記憶體錯誤檢測、執行緒競爭與死鎖等功能,因此,本著分享的精神,將其總結成一個系列。

主要內容如下:

  • 入門篇:工作機制、編譯安裝、引數、指令範例、推薦用法、新增 case、常見問題、異常偵錯
  • 進階篇:高階用法,包括單元測試、壓力測試、程式碼覆蓋率測試、記憶體錯誤檢測、執行緒競爭與死鎖
  • 原始碼篇:分析 MTR 的原始碼
  • 語法篇:單元測試、壓力測試、mysqltest 語法、異常偵錯

由於個人水平有限,所述難免有錯誤之處,望雅正。

本文是第四篇語法篇。

本文首發於 2023-07-05 21:53:21


MTR 系列基於 MySQL 8.0.29 版本,如有例外,會特別說明。

單元測試

簡介

前文「MySQL 測試框架 MTR 系列教學(二):進階篇 - 記憶體/執行緒/程式碼覆蓋率/單元/壓力測試」已介紹了單元測試的概念及使用方法,簡單回顧一下:

  • MySQL 使用 TAP(Test Anything Protocol) 和 Google Test Framework 來實現單元測試。
    • TAP 是 Perl 與測試模組之間所使用的簡單的基於文字的介面。
    • 為了實現 C/C++ 的單元測試,MySQL 開發了一個用於生成 TAP 文字的庫libmytap.a,原始碼路徑位於unittest/mytap/
  • 使用方法:在執行 cmake 的目錄執行 make testmake test-unit 指令(內容詳細,更推薦)。
  • 注意事項:在執行單元測試時,不建議啟用 ASAN,否則會因 ASAN 檢測到單元測試程式碼有記憶體漏失而導致 case 失敗。

unittest/ 目錄介紹:

CMakeLists.txt
examples # 存放單元測試範例
gunit # 存放所有單元測試用例的程式碼
mytap # 存放 MyTAP 協定程式碼

如果新加的測試用例與儲存引擎或外掛有關,則分別存放在unittest/engine_nameunittest/plugin_name目錄或它們的子目錄中。

單元測試程式碼都位於原始碼目錄/unittest/gunit/ 下,其中有檔案也有子目錄,無論是當前目錄還是子目錄下的檔案,都以xxxxx-t.cc 格式命名,每個xxxxx-t.cc檔案都是一個測試 case,編譯後都會生成一個二進位制檔案 bin/xxxxx-t

下面舉例說明如何新增單元測試 case 。

範例

比如在 原始碼目錄/unittest/gunit/binlogevents/ 目錄下建立一個新的測試用例 myprint

一、建立檔案unittest/gunit/binlogevents/myprint-t.cc,內容如下:

#include <gtest/gtest.h>


namespace binary_log {
namespace unittests {

class MyPrintTest : public ::testing::Test {
 public:
  MyPrintTest() {}

  void TestBody() { // 必須實現該虛擬函式
      std::cout << "print_test ====>" << std::endl;
      ASSERT_TRUE(true);
  }
};

// 第二個引數是測試用例名字
TEST_F(MyPrintTest, PrintTest) {
  MyPrintTest t;
  t.TestBody();
}

}  // namespace unittests
}  // namespace codecsog

二、修改 unittest/gunit/binlogevents/CMakeLists.txt 檔案,新增myprint用例:

......

# Add tests SET(TESTS transaction_payload_codec
  transaction_compression
  transaction_payload_iterator
  gtids
  gno_intervals
  myprint ####### 新加的行
  heartbeat_codec)

......

三、重新執行 cmake(需要設定-DWITH_DEBUG=1 -DWITH_UNIT_TESTS=1)、編譯,會生成二進位制檔案bin/myprint-t

四、執行make testmake test-unit ,或者直接執行bin/myprint-t ,測試用例 passed :

wslu@ubuntu:/data/work/mysql/mysql-server/console-build-debug$ ./bin/myprint-t
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from MyPrintTest
[ RUN      ] MyPrintTest.PrintTest
print_test ====>
[       OK ] MyPrintTest.PrintTest (0 ms)
[----------] 1 test from MyPrintTest (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (8 ms total)
[  PASSED  ] 1 test.

參考:

程式碼覆蓋率測試

目前涉及 gcov 的程式檔案只有 mysys/dbug.cc 檔案以及對應的單元測試檔案unittest/gunit/dbug-t.cc

gcov 的用法就是在編譯時新增選項來實現的:

wslu@ubuntu:/data/work/mysql/mysql-server/console-build-debug/mysql-test$ grep "coverage" ../../CMakeLists.txt -nr
1128:  STRING_APPEND(CMAKE_C_FLAGS   " -fprofile-arcs -ftest-coverage -DHAVE_GCOV")
1129:  STRING_APPEND(CMAKE_CXX_FLAGS " -fprofile-arcs -ftest-coverage -DHAVE_GCOV")
1130:  STRING_APPEND(CMAKE_EXE_LINKER_FLAGS " -fprofile-arcs -ftest-coverage -lgcov")

綜上,無需自行編寫程式碼覆蓋率測試程式碼。

壓力測試

有兩個地方涉及壓力測試:

一、壓力測試 suite 只有兩個:

  • stress
  • innodb_stress

如需要新增新 case,參考對應 suite 已有 case 照貓畫虎即可,語法可參考下一章節。

二、mysql-stress-test.pl :被 mysql-test-run.pl 呼叫,引數是--stress

  stress=ARGS           Run stress test, providing options to
                        mysql-stress-test.pl. Options are separated by comma.

對於 mysql-stress-test.pl ,更便於自定義測試內容,主要包括:

  • --stress-init-file[=path]

    file_name is the location of the file that contains the list of tests to be run once to initialize the database for the testing. If missing, the default file is stress_init.txt in the test suite directory.

  • --stress-tests-file[=file_name]

    Use this option to run the stress tests. file_name is the location of the file that contains the list of tests. If file_name is omitted, the default file is stress-test.txt in the stress suite directory. (See --stress-suite-basedir).

這部分暫未嘗試,不做贅述。

SQL 測試 - mtr/mysqltest 語法

之間文章介紹過 mtr 會將 *.test*.inc等測試 case 的內容傳給 mysqltest 來執行。

mysqltest 是 mysql 自帶的測試引擎, 它實現了一種小語言,用來描述測試過程,並將測試結果與預期對比。

本節要講解 mysqltest 語法格式,你可能會好奇學習這個語法有什麼用,為了更直觀的說明,首先我們看一下如何編寫 mtr 的測試用例。

語法格式

mysqltest 解釋的是以.test為字尾的檔案(包括其參照的.inc檔案)。

mysqltest 小語言按照語法大致分為三類:

  • mysql command :用來控制執行時的行為。一般有兩種寫法:
command; # 這是後面帶;的
--command # 前面帶--,不需要;
  • SQL :就是普通的 SQL 語句,測試 case 裡大部分是 SQL 語句。
  • comment :註釋一般用於描述測試過程,用 # 開頭。

範例:借鑑「MySQL 測試框架 MTR 系列教學(一):入門篇」一文中的測試 case(路徑是 mysql-test/t/mytest.test ),內容如下:

--echo #
--echo # some comments
--echo #

--disable_warnings
DROP TABLE IF EXISTS t1;
SET @@sql_mode='NO_ENGINE_SUBSTITUTION';
--enable_warnings

SET SQL_WARNINGS=1;

CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2);
SELECT * FROM t1;
DROP TABLE t1;

command 列表

mysqltest 提供了幾十個 command,本文只介紹最常用的,更多內容請查閱官方手冊:MySQL: mysqltest Language Reference

error 處理預期錯誤

語法:

error error_code [, error_code] ...
sql_statements

有些 CASE 就是要驗證 sql 失敗的情況,在 sql 語句前面加上--error 錯誤碼就可以了。

  • 如果 sql 報錯且錯誤碼等於 --error 指定的錯誤碼,mysqltest 不會 abort,而是繼續執行。
  • 反之,如果 sql 報錯且錯誤碼不等於--error 指定的錯誤碼,mysqltest 會 abort 並報錯退出。

--error後面可以跟兩種值:一種是error no,另外一種是sqlstate,如果是後者需要加上 S 做字首。 他們分別是 C API 函數 mysql_errno()mysql_sqlstate() 的返回值。

範例一:使用錯誤碼

--error 1050
create table t1(pk createtime primary key, a int);

等價於

--error ER_TABLE_EXISTS_ERROR
create table t1(pk createtime primary key, a int);

其中數位 1050 對應錯誤碼,ER_TABLE_EXISTS_ERROR 對應錯誤的邏輯名。

這樣在 mysqltest 執行後,會將返回的錯誤資訊一起寫入結果檔案,這些錯誤資訊就作為期望結果的一部分了。

範例二:使用 SQLSTATE

也可以使用 SQLSTATE 來指示期望有錯誤返回,例如與 MySQL 錯誤碼 1050 對應的 SQLSTATE 值是 42S01,使用下面的方式,注意編碼增加了 S 字首:

--error S42S01
create table t1(pk createtime primary key, a int);

範例三:指定多個錯誤碼,滿足其一則通過

在指令 error 後面是可以加入多個錯誤碼作為引數的,使用逗號分隔即可:

--error 1050,1052
create table t1(pk createtime primary key, a int);

如果該 SQL 報錯,若錯誤碼是 1050 或 1051,則符合預期,測試繼續。

錯誤碼參考 MySQL 安裝包 include 子目錄下的 mysqld_error.h

disable_abort_on_error / enable_abort_on_error

預設情況下(enable_abort_on_error),sql 執行失敗後 mysqltest 就退出了,後面的內容就不會執行,也不會生成 .reject檔案。

顯示執行disable_abort_on_error命令可以在 sql 失敗後繼續執行後面的內容,並生成 .reject檔案。

--disable_abort_on_error
sql_statements
--enable_abort_on_error

disable_query_log / enable_query_log

預設情況下(enable_query_log),所有的 sql 語句都會記錄輸出結果。

在一些情況下(比如,使用了迴圈,query 特別多)不想記錄某些 sql 語句及結果,顯示呼叫 disable_query_log 既可。

--disable_query_log
--enable_query_log

其他形如enable_xx/disable_xx的命令還有很多,用法都類似

connect

建立一個到 mysql server 的新連線並作為當前連線。

語法格式:

connect (name, host_name, user_name, password, db_name [,port_num [,socket [,options [,default_auth [,compression algorithm, [,compression level]]]]]])
  • name is the name for the connection (for use with the connection, disconnect, and dirty_close commands). This name must not already be in use by an open connection.
  • host_name indicates the host where the server is running.
  • user_name and password are the user name and password of the MySQL account to use.
  • db_name is the default database to use. As a special case, NO-ONE means that no default database should be selected. You can also leave db_name blank to select no database.
  • port_num, if given, is the TCP/IP port number to use for the connection. This parameter can be given by using a variable.
  • socket, if given, is the socket file to use for connections to localhost. This parameter can be given by using a variable.
  • options can be one or more of the following words, separated by spaces:
    • CLEARTEXT: Enable use of the cleartext authentication plugin.
    • COMPRESS: Use the compressed client/server protocol, if available.
    • PIPE: Use the named-pipe connection protocol, if available.
    • SHM: Use the shared-memory connection protocol, if available.
    • SOCKET: Use the socket-file connection protocol.
    • SSL:Use SSL network protocol to have encrypted connection.
    • TCP: Use the TCP/IP connection protocol.
      Passing PIPE or SHM on non-Windows systems causes an error, and, similarly, passing SOCKET on Windows systems causes an error.
  • default_auth is the name of an authentication plugin. It is passed to the mysql_options() C API function using the MYSQL_DEFAULT_AUTH option. If mysqltest does not find the plugin, use the –plugin-dir option to specify the directory where the plugin is located.
  • compression algorithm is the name of compression algorithm to be used to compress data transferred between client server. It is passed to the mysql_options() C API function using the MYSQL_OPT_COMPRESSION_ALGORITHMS option.
  • zstd compression level is the extent of compression to be applied when zstd compression algorithm is used. It is passed to the mysql_options() C API function using the MYSQL_OPT_COMPRESSION_ALGORITHMS option.
  • compression level is the extent of compression to be applied based on the compression algorithm used. It is passed to the mysql_options() C API function using the MYSQL_OPT_COMPRESSION_ALGORITHMS option.

範例:

connect (conn1,localhost,root,,);
connect (conn2,localhost,root,mypass,test);
connect (conn1,127.0.0.1,root,,test,$MASTER_MYPORT);

connection

語法:

connection connection_name

選擇 connection_name作為當前連線。

範例:

connection master;
connection conn2;
connection default;

disconnect

語法:

disconnect connection_name

關閉連線connection_name

範例:

disconnect conn2;
disconnect slave;

測試 session 的時候會用到上述三個命令,以在多個 connection 之間切換。比如:

connect (conn3,127.0.0.1,root,,test,25042);
connection conn3;
create table t1(a int primary key);
drop table t1;
disconnect conn3;

exec

執行 shell 命令。語法:

exec command [arg] ...

範例:

--exec $MYSQL_DUMP --xml --skip-create test
--exec rm $MYSQLTEST_VARDIR/tmp/t1
exec $MYSQL_SHOW test -v -v;

On Cygwin, the command is executed from cmd.exe, so commands such as rm cannot be executed with exec. Use system instead.

perl [terminator]

嵌入 perl 程式碼,以 EOF 為結束符,也可以自定義結束符。

受限於 mtr 語法,很多操作無法完成,嵌入 perl 指令碼可以簡化問題。

perl;
  // your perl script
EOF

範例:

perl;
print "This is a test\n";
EOF
perl END_OF_FILE;
print "This is another test\n";
END_OF_FILE

perl 內外的變數互動:

1、可以使用 let 設定環境變數

如果使用 let 時變數名不加 $ 即為設定為環境變數,在 perl 中可以通過 $ENV{'name'} 獲取和設定

--let name = "env value"

--perl
  print "name: $ENV{'name'}";
  $ENV{'name'} = 'new env value';
EOF

--echo name: $name

2、在 perl 中拼接 mtr 指令碼,然後在 mtr 指令碼中執行

perl;
  my $dir = $ENV{'MYSQLTEST_VARDIR'};
  open ( OUTPUT, ">$dir/tmp/name.inc") ;
  print OUTPUT "let \$name = abc;\n";
  close (OUTPUT)
EOF

--source  $MYSQLTEST_VARDIR/tmp/name.inc
--echo $name

vertical_results/horizontal_results

設定 SQL 語句結果的預設顯示方式(vertical_results 表示縱向,horizontal_results 表示橫向,預設是橫向),功能跟 sql 語句的'\G'類似。

範例:

--vertical_results

exit

退出當前測試 case,後續指令不再執行。

let

變數賦值,可支援整數、字串。

語法:

let $var_name = value
let $var_name = query_get_value(query, col_name, row_num)

範例:

--let $1= 0 # 加 -- 字首,就不用以分號結尾
let $count= 10;

# 將查詢結果賦給變數 q
let $q= `SELECT VERSION()`;

inc/dec

為整數加 1/減 1 。

語法:

inc $var_name/dec $var_name

範例:

--inc $i;
inc $3;

eval

語法:

eval statement

執行sql 語句,支援變數的傳遞。範例:

eval USE $DB;
eval CHANGE MASTER TO MASTER_PORT=$SLAVE_MYPORT;
eval PREPARE STMT1 FROM "$my_stmt";

query

語法:

query [statement]

顯示指定當前語句是 SQL 語句,而不是 command。即使 query 之後是 command(比如sleep),也會當成 statement 來解析。

send

語法:

send [statement]

向 server 傳送一條 query,但並不等待結果,而是立即返回,該 query 的結果必須由 reap 指令來接收。

在上一條 query 結果被 reap 指令接收之前,不能向當前 session 傳送新的 SQL 語句。

如果 statement 省略了,則執行下一行的 SQL 語句。

範例:

send SELECT 1;

等效於

send;
SELECT 1;

send_eval

語法:

send_eval [statement]

等效於 send + evalsend不同在於支援變數傳遞

如果 statement 省略了,則執行下一行的 SQL 語句。

範例:

--send_eval $my_stmt

等效於

--send_eval
$my_stmt;

reap

如果當前 session 之前有通過 send 指令向 server 傳送 SQL 語句,reap 指令用來接收該 SQL 語句的執行結果。

如果之前沒有通過 send 向 server 傳送 SQL,則不要執行 reap 指令。

範例:在同一個 session 中用 send 後臺執行,用 reap 恢復等待。

--connection 1
--send select sleep(20)

--connection 2
--send select 1

--connection 1
--reap

echo

語法:

echo text

text 文字輸出到測試 result 中。

範例:

--echo Another sql_mode test
echo should return only 1 row;

query_get_value

語法:

query_get_value(query, col_name, row_num)

獲得 query 返回的結果中某行某列的值

範例:

假如 .test 檔案內容如下:

CREATE TABLE t1(a INT, b VARCHAR(255), c DATETIME);
SHOW COLUMNS FROM t1;
let $value= query_get_value(SHOW COLUMNS FROM t1, Type, 1);
echo $value;

輸出結果為:

CREATE TABLE t1(a INT, b VARCHAR(255), c DATETIME);
SHOW COLUMNS FROM t1;
Field   Type    Null    Key     Default Extra
a       int(11) YES             NULL
b       varchar(255)    YES             NULL
c       datetime        YES             NULL
int(11)

int(11) 就是 Type 列第一行的值。

source

語法:

source file_name

多個 case 可能共用一塊程式碼,這塊程式碼可以單獨放到一個.inc檔案,再通過 source 匯入。

範例:

--source path/to/script.inc

sleep

語法:

sleep num

Sleep num seconds.

範例:

--sleep 10
sleep 0.5;

replace_column

語法:

replace_column col_num value [col_num value] ...

將下一條語句的結果中的某些列的值進行替換,可以指定多組替換規則,列序號從 1 開始。

範例:

--replace_column 9 #
replace_column 1 b 2 d;

expr 命令 (MySQL 8 之後可用)

語法:

expr $var_name= operand1 operator operand2

對數值變數進行運算,支援 +, -, *, /, %, &&, ||, &, |, ^, <<, >>

--let $val1= 10
--let $var2= 20
--expr $res= $var1 + $var2
--echo $res

在 5.7 版本中用 SQL 語句替代

--let $val1= 10
--let $var2= 20
--expr $res= `select $var1 + $var2`

if

語法:

if (expr)

與其他語言的 if 語句含義相同。

範例:

let $counter= 0;
if ($counter)
{
  echo Counter is not 0;
}

if (!$counter)
{
  echo Counter is 0;
}

while

語法:

while (expr)

與其他語言的 while 語句含義相同。

範例:

let $i=5;
while ($i)
{
  echo $i;
  dec $i;
}

其他命令

其他的命令還有:

assert (expr)

change_user [user_name], [password], [db_name]
character_set charset_name

delimiter str

die [message]
skip [message]

disable_async_client, enable_async_client
disable_connect_log, enable_connect_log
disable_info, enable_info
disable_metadata, enable_metadata
disable_ps_protocol, enable_ps_protocol
disable_query_log, enable_query_log
disable_reconnect, enable_reconnect
disable_result_log, enable_result_log
disable_rpl_parse, enable_rpl_parse
disable_session_track_info, enable_session_track_info
disable_testcase bug_number, enable_testcase
disable_warnings, enable_warnings

end
start_timer
end_timer

# exec command
exec_in_background command [arg] ...
execw command [arg] ...


# 目錄相關
force-cpdir src_dir_name dst_dir_name
force-rmdir dir_name
mkdir dir_name
rmdir dir_name
list_files dir_name [pattern]
list_files_append_file file_name dir_name [pattern]
list_files_write_file file_name dir_name [pattern]
# 檔案相關
diff_files file_name1 file_name2
remove_files_wildcard dir_name pattern [retry]
write_file file_name [terminator]
append_file file_name [terminator]
cat_file file_name
chmod octal_mode file_name
copy_file from_file to_file [retry]
copy_files_wildcard src_dir_name dst_dir_name pattern [retry]
file_exists file_name [retry]
move_file from_name to_name [retry]
output file_name
remove_file file_name [retry]

# 結果集
lowercase_result
result_format version
sorted_result
partially_sorted_result start_column
query_horizontal statement
query_vertical statement
replace_numeric_round precision
replace_regex /pattern/replacement/[i] ...
replace_result from_val to_val [from_val to_val] ...

# 連線
ping
reset_connection
dirty_close connection_name
send_quit connection
send_shutdown
shutdown_server [timeout]
sync_slave_with_master [connection_name]

# 複製
save_master_pos
sync_with_master offset
wait_for_slave_to_stop

詳見官方手冊:MySQL: mysqltest Commands

編寫規範

  1. 儘可能避免每行超過 80 個字元;
  2. #開頭,作為註釋;
  3. 縮排使用空格,避免使用 tab;
  4. SQL 語句使用相同的風格,包括關鍵字大寫,其它變數、表名、列名等小寫;
  5. 增加合適的註釋。特別是檔案的開頭,註釋出測試的目的、可能的參照或者修復的 bug 編號;
  6. 為了避免可能的衝突,習慣上表命名使用 t1、t2...,檢視命名使用 v1、v2...;

異常偵錯

本小節已新增到《MySQL 測試框架 MTR 系列教學(一):入門篇》,看過前文的可跳過本節。

分析紀錄檔

預設情況下,在目錄 mysql-test/var/log/中有紀錄檔生成(若指定 --vardir 引數,則以該引數路徑為準),分析該紀錄檔也能得到一些有用資訊。

比如 啟動失敗,則可以檢視 bootstrap.log 檔案,去掉命令中的 --bootstrap 並執行即可啟動對應的 MySQL 服務來驗證、偵錯。

verbose 引數

啟動 mtr 時加 --verbose 引數,定位到參照的指令碼位置後可以設定 --echo 命令修改偵錯。

如果加上 --verbose 列印的內容還不夠詳細,可以再加一個,即 --verbose --verbose,能列印出 mtr perl 指令碼中的紀錄檔資訊。

範例:

wslu@ubuntu:/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test$ perl mysql-test-run.pl --timer  --force --parallel=1 --vardir=var-rpl --suite=rpl --verbose
Logging: mysql-test-run.pl  --timer --force --parallel=1 --vardir=var-rpl --suite=rpl --verbose
> exe_name: mysqld
MySQL Version 8.0.29
Checking supported features
 - Binaries are debug compiled
> Testing FIPS: --test-ssl-fips-mode 0 error:0F06D065:common libcrypto routines:FIPS_mode_set:fips mode not supported

Using suite(s): rpl
Collecting tests
> Collecting: rpl
> suitedir: /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/suite/rpl
> testdir: /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/suite/rpl/t
> resdir: /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/suite/rpl/r
> Read combinations file /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/suite/rpl/combinations.
 - Adding combinations for rpl
> Collecting: i_rpl
Removing old var directory
> opt_vardir: /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl
> Removing /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var
> Removing /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/
> Removing /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/tmp/
Creating var directory '/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl'
> Creating /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl
Installing system database
### safe_path: /data/work/mysql/mysql80-install.bak_asan_ubsan/bin//mysqltest_safe_process --verbose -- /data/work/mysql/mysql80-install.bak_asan_ubsan/bin/mysqld --no-defaults --initialize-insecure --loose-skip-ndbcluster --tmpdir=/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/tmp/ --core-file --datadir=/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/data/ --secure-file-priv=/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl --innodb_buffer_pool_size=24M --innodb-log-file-size=5M --innodb_autoextend_increment=8 --character-sets-dir=/data/work/mysql/mysql80-install.bak_asan_ubsan/share/charsets --loose-auto_generate_certs=OFF --loose-sha256_password_auto_generate_rsa_keys=OFF --loose-caching_sha2_password_auto_generate_rsa_keys=OFF --init-file=/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/tmp/bootstrap.sql
Using parallel: 1

==============================================================================
                  TEST NAME                       RESULT  TIME (ms) COMMENT
------------------------------------------------------------------------------
> Client connected
worker[1] > mtr_ping_port: 13000
worker[1] > FREE
worker[1] > mtr_ping_port: 13001
worker[1] > FREE
worker[1] > mtr_ping_port: 13002
worker[1] > FREE
worker[1] > mtr_ping_port: 13003
worker[1] > FREE
......
worker[1] > mtr_ping_port: 13029
worker[1] > FREE
worker[1] > Using MTR_BUILD_THREAD 300, with reserved ports 13000..13029
worker[1] Creating var directory '/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl'
worker[1] > result: , file_mode: 0
[  0%] rpl.rpl_atomic_ddl                        [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_atomic_ddl_no_binlog              [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_binlog_cache_encryption           [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_filters_error_cases_on_startup    [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_group_commit_deadlock             [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_group_commit_deadlock_myisam      [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_innodb_auto_increment             [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_killed_ddl                        [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_log_info_repository_persistence_assign_gtids_to_anonymous_transactions  [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_log_info_repository_persistence_require_row  [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_log_info_repository_persistence_require_table_primary_key_check  [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_row_crash_safe                    [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_row_mts_rec_crash_safe            [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_stm_mixed_crash_safe              [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_stm_mixed_mts_rec_crash_safe      [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_stm_mixed_mts_rec_crash_safe_checksum  [ skipped ]  Test needs 'big-test' or 'only-big-test' option.
[  0%] rpl.rpl_io_thd_wait_for_disk_space_stress  [ disabled ]   BUG#23581287 Disabled until bug is fixed.
[  0%] rpl.rpl_writeset_add_unique_key           [ disabled ]   Bug#33134835 RPL_WRITESET_ADD_UNIQUE_KEY FAILS SPORADICALLY
worker[1] > Running test: rpl.rpl_plugin_load
worker[1] > Setting timezone: GMT-3
worker[1] > Cleaning datadirs...
worker[1] > clean_dir: /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/tmp
worker[1] > unlink: '/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/tmp/bootstrap.sql'
worker[1] > Generating my.cnf from '/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/suite/rpl/my.cnf'
worker[1] > MASTER_MYPORT = 13000
worker[1] > MASTER_MYSOCK = /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/tmp/mysqld.1.sock
worker[1] > MASTER_X_MYSOCK = /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/tmp/mysqlx.1.sock
worker[1] > SLAVE_MYPORT = 13002
worker[1] > SLAVE_MYSOCK = /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/tmp/mysqld.2.sock
worker[1] > SLAVE_X_MYSOCK = /data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/tmp/mysqlx.2.sock
worker[1] > mysqld_start:  [' --plugin-dir=/data/work/mysql/mysql80-install.bak_asan_ubsan/lib/plugin', '--binlog-format=mixed ']

### safe_path: /data/work/mysql/mysql80-install.bak_asan_ubsan/bin//mysqltest_safe_process --verbose -- /data/work/mysql/mysql80-install.bak_asan_ubsan/bin/mysqld --defaults-group-suffix=.1 --defaults-file=/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test/var-rpl/my.cnf --log-output=file --loose-debug-sync-timeout=600 --plugin-dir=/data/work/mysql/mysql80-install.bak_asan_ubsan/lib/plugin --binlog-format=mixed --core-file
worker[1] > Started [mysqld.1 - pid: 61921, winpid: 61921]
worker[1] > mysqld_start:  [' --plugin-dir=/data/work/mysql/mysql80-install.bak_asan_ubsan/lib/plugin', '--binlog-format=mixed ']

......

指令碼自身支援 debug 引數

如果參照(source)的指令碼支援 debug 引數,比如常用的 $rpl_debug,則可以修改相應的 .inc 檔案以獲得更多的 debug 資訊。

perl 的偵錯模式

新增-d 引數可進入 perl 語言的 debug 模式。範例:

wslu@ubuntu:/data/work/mysql/mysql80-install.bak_asan_ubsan/mysql-test$ perl -d mysql-test-run.pl --timer  --force --parallel=1 --vardir=var-rpl --suite=rpl

Loading DB routines from perl5db.pl version 1.60
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(mysql-test-run.pl:54):  push @INC, ".";
  DB<1> l
54==>  push @INC, ".";
55
56:  use My::ConfigFactory;
57:  use My::CoreDump;
58:  use My::File::Path;    # Patched version of File::Path
59:  use My::Find;
60:  use My::Options;
61:  use My::Platform;
62:  use My::SafeProcess;
63:  use My::SysInfo;
  DB<1> n
main::(mysql-test-run.pl:72):  require "lib/mtr_gcov.pl";
  DB<1> l
72==>  require "lib/mtr_gcov.pl";
73:  require "lib/mtr_gprof.pl";
74:  require "lib/mtr_io.pl";
75:  require "lib/mtr_lock_order.pl";
76:  require "lib/mtr_misc.pl";
77:  require "lib/mtr_process.pl";
78
79:  our $secondary_engine_support = eval 'use mtr_secondary_engine; 1';
80
81   # Global variable to keep track of completed test cases
  DB<1>

偵錯模式常用命令:

h       檢視幫助檔案
c line  執行到指定行
n       執行到下一行
s       跳到函數內部執行
l       檢視程式碼
q       退出

參考

MySQL: The MySQL Test Framework

MySQL: Writing Test Cases

MySQL: mysqltest Language Reference

MySQL: Creating and Executing Unit Tests

mysqltest 語法整理 - 葉落 kiss - 部落格園 (cnblogs.com)


歡迎關注我的微信公眾號【資料庫核心】:分享主流開源資料庫和儲存引擎相關技術。

歡迎關注公眾號資料庫核心
標題 網址
GitHub https://dbkernel.github.io
知乎 https://www.zhihu.com/people/dbkernel/posts
思否(SegmentFault) https://segmentfault.com/u/dbkernel
掘金 https://juejin.im/user/5e9d3ed251882538083fed1f/posts
CSDN https://blog.csdn.net/dbkernel
部落格園(cnblogs) https://www.cnblogs.com/dbkernel