国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

特性介紹 | MySQL 測(cè)試框架 MTR 系列教程(一):入門(mén)篇

這篇具有很好參考價(jià)值的文章主要介紹了特性介紹 | MySQL 測(cè)試框架 MTR 系列教程(一):入門(mén)篇。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

作者:盧文雙 資深數(shù)據(jù)庫(kù)內(nèi)核研發(fā)

去年年底通過(guò)微信公眾號(hào)【數(shù)據(jù)庫(kù)內(nèi)核】設(shè)定了一個(gè)目標(biāo)——2023 年要寫(xiě)一系列 特性介紹+內(nèi)核解析 的文章(現(xiàn)階段還是以 MySQL 為主)。
雖然關(guān)注者很少,但本著“說(shuō)到就要做到”的原則,從這篇就開(kāi)始了。

序言:

以前對(duì) MySQL 測(cè)試框架 MTR 的使用,主要集中于 SQL 正確性驗(yàn)證。近期由于工作需要,深入了解了 MTR 的方方面面,發(fā)現(xiàn) MTR 的能力不僅限于此,還支持單元測(cè)試、壓力測(cè)試、代碼覆蓋率測(cè)試、內(nèi)存錯(cuò)誤檢測(cè)、線程競(jìng)爭(zhēng)與死鎖等功能,因此,本著分享的精神,將其總結(jié)成一個(gè)系列。

主要內(nèi)容如下:

  • 入門(mén)篇:工作機(jī)制、編譯安裝、參數(shù)、指令示例、推薦用法、添加 case、常見(jiàn)問(wèn)題、異常調(diào)試
  • 進(jìn)階篇:高階用法,包括單元測(cè)試、壓力測(cè)試、代碼覆蓋率測(cè)試、內(nèi)存錯(cuò)誤檢測(cè)、線程競(jìng)爭(zhēng)與死鎖
  • 源碼篇:分析 MTR 的源碼
  • 語(yǔ)法篇:?jiǎn)卧獪y(cè)試、壓力測(cè)試、mysqltest 語(yǔ)法、異常調(diào)試

由于個(gè)人水平有限,所述難免有錯(cuò)誤之處,望雅正。

本文是第一篇入門(mén)篇

本文首發(fā)于 2023-03-18 21:58:52


本系列基于 MySQL 8.0.29 版本,且主要在 Ubuntu 22.04 X86_64 驗(yàn)證(部分指令也在 Ubuntu 20.04 X86_64、Ubuntu 22.04 ARM64、MacOS M1 做了驗(yàn)證),如有例外,會(huì)特別說(shuō)明。

簡(jiǎn)介

在修改內(nèi)核代碼后,不僅需要測(cè)試新增功能,同時(shí)也要對(duì)原有功能做回歸測(cè)試,以保證新加代碼對(duì)原有功能沒(méi)有影響,這就需要用到 MySQL 源碼自帶的測(cè)試框架 mtr。

MySQL 測(cè)試框架是一個(gè)以 MySQL 框架和內(nèi)部引擎為測(cè)試對(duì)象的工具,主要執(zhí)行腳本在安裝路徑(make install后的路徑)下的mysql-test目錄,基本覆蓋了所有 MySQL 的特性和異常情況。

MySQL 測(cè)試框架 mtr 主要包含如下幾個(gè)組件:

  • mysql-test-run.pl :perl 腳本,簡(jiǎn)稱(chēng) mtr,是 MySQL 最常用的測(cè)試工具,負(fù)責(zé)控制流程,包括啟停、識(shí)別執(zhí)行哪些用例、創(chuàng)建文件夾、收集結(jié)果等等,主要作用是驗(yàn)證 SQL 語(yǔ)句在各種場(chǎng)景下是否返回正確的結(jié)果。
  • mysqltest :C++二進(jìn)制程序,負(fù)責(zé)執(zhí)行測(cè)試用例,包括讀文件、解析特定語(yǔ)法、執(zhí)行用例。
    • 用例的特殊語(yǔ)法(比如,--source,--replace_column等)都在command_namesenum_commands兩個(gè)枚舉結(jié)構(gòu)體中。
  • mysql_client_test :C++二進(jìn)制程序,用于測(cè)試 MySQL 客戶(hù)端 API(mysqltest 無(wú)法用于測(cè)試 API)。
    • 從代碼看,只有啟用--valgrind--valgrind-mysqltest 選項(xiàng),才會(huì)用到 mysql_client_test
  • mysql-stress-test.pl :perl 腳本,用于 MySQL Server 的壓力測(cè)試。
  • 支持 gcov/gprof 代碼覆蓋率測(cè)試工具。

除此之外,還提供了單元測(cè)試工具(嚴(yán)格來(lái)說(shuō)不屬于 mtr ),以便為存儲(chǔ)引擎和插件創(chuàng)建單獨(dú)的單元測(cè)試程序。

由于 MySQL 測(cè)試框架的入口是 mysql-test-run.pl(它會(huì)調(diào)用上述其他組件),因此,一般將 MySQL 測(cè)試框架簡(jiǎn)稱(chēng)為 mtr。

mtr 工作原理

概述

mtr 采用t/r模式(t目錄中存儲(chǔ)具體的測(cè)試 case,文件以.test結(jié)尾;r目錄中存儲(chǔ)了對(duì)應(yīng) case 的期望結(jié)果,文件以.result結(jié)尾),主要測(cè)試步驟是“通過(guò)執(zhí)行一個(gè) case,將該 case 的輸出結(jié)果,與標(biāo)準(zhǔn)的輸出結(jié)果(期望結(jié)果)作 diff”:

  • 如果完全一樣,則說(shuō)明該 case 通過(guò);
  • 反之,則說(shuō)明該 case 失敗。
    • 可能原因:case 本身寫(xiě)的有問(wèn)題;MySQL 服務(wù)有問(wèn)題。

如果t目錄中的某個(gè) case 在r目錄中沒(méi)有對(duì)應(yīng).result文件:

  • 那么,只要該 case 能正常執(zhí)行完,mtr 就會(huì)判定該 case 通過(guò);
  • 反之,若執(zhí)行過(guò)程中出現(xiàn) mysql server crash 等異常問(wèn)題,mtr 就會(huì)判定該 case 失敗。

上文說(shuō)的 case 是指一系列的語(yǔ)句,包括 SQL 語(yǔ)句和一些必要的 mysqltest command。

所有 case 可分為三部分,分別為:

  • main:測(cè)試 case 位于 mysql-test/t 目錄,期望結(jié)果(如果有的話)位于mysql-test/r 目錄,二者中的文件是一一對(duì)應(yīng)的,比如:mysql-test/t/alter_debug.testmysql-test/r/alter_debug.result。
  • suite :路徑位于mysql-test/suite 目錄,其中包含很多測(cè)試 case 的集合,每個(gè)集合都是一個(gè)單獨(dú)的子目錄(比如 mysql-test/suite/binlog),在子目錄中又分別包含 r、t 兩個(gè)目錄。
  • extra :應(yīng)該是對(duì)上述兩種 case 的補(bǔ)充,位于mysql-test/extra/ 目錄,在 8.0.29 版本中只包含binlog_tests、rpl_tests 兩個(gè)集合。

框架流程

mysql-test-run.pl框架運(yùn)行流程如下:

1、初始化(Initialization)

  • 確定用例執(zhí)行范圍,包括運(yùn)行哪些 suite,skip 哪些用例,在本階段根據(jù)disabled.def文件、--skip-xxx命令(比如skip-rpl)等確定執(zhí)行用例。
  • 同時(shí),初始化數(shù)據(jù)庫(kù)。后面運(yùn)行用例啟動(dòng)數(shù)據(jù)庫(kù)時(shí),不需要每次初始化,只需從這里的目錄中拷貝啟動(dòng)。

2、運(yùn)行用例(run test)

主線程根據(jù)參數(shù)--parallel(默認(rèn)是 1)啟動(dòng)一個(gè)或者多個(gè)用例執(zhí)行線程(worker),各線程有自己獨(dú)立的 client port,data dir 等。

啟動(dòng)的 worker 與主線程之間是 server-client 模式,主線程是 server,worker 是 client。

  • 主線程與 worker 是一問(wèn)一答模式,主線程向 worker 發(fā)送運(yùn)行用例的文件路徑、配置文件參數(shù)等各種參數(shù)信息,worker 向主線程返回運(yùn)行結(jié)果,直到所有在 collection 中的用例都運(yùn)行完畢,主線程 close 各 worker,進(jìn)行收尾工作。
  • 主線程先讀取各 worker 返回值,對(duì)上一個(gè)用例進(jìn)行收尾工作。之后,讀取 collection 中的用例,通過(guò)本地 socket 發(fā)送到 worker 線程,worker 線程接收到主線程命令,運(yùn)行本次用例測(cè)試的核心邏輯,主要包括 3 件事:啟動(dòng) mysqld、啟動(dòng)并監(jiān)控 mysqltest,處理執(zhí)行結(jié)果。
    • 啟動(dòng) mysqld根據(jù)參數(shù)啟動(dòng)一個(gè)或者多個(gè) mysqld server 進(jìn)程,大多數(shù)情況下會(huì)拷貝主線程初始化后的目錄到 worker 的數(shù)據(jù)目錄,作為新實(shí)例的啟動(dòng)目錄,用 shell 命令啟動(dòng)數(shù)據(jù)庫(kù)。
    • 啟動(dòng)并監(jiān)控 mysqltest:用例在 mysqltest 中執(zhí)行(會(huì)逐行掃描 *.test 文件中的 SQL 或指令并于 MySQL 中執(zhí)行),worker 線程會(huì)監(jiān)控 mysqltest 的運(yùn)行狀態(tài),監(jiān)測(cè)其是否運(yùn)行超時(shí)或者運(yùn)行結(jié)束。
    • 處理執(zhí)行結(jié)果:mysqltest 執(zhí)行結(jié)束會(huì)留下執(zhí)行日志,框架根據(jù)執(zhí)行日志判斷執(zhí)行是否通過(guò),如果沒(méi)通過(guò)是否需要重試等。

rpl.rpl_multi_source_basic(對(duì)應(yīng)于文件 mysql-test/suite/rpl/t/rpl_multi_source_basic.test)測(cè)試 case 為例來(lái)說(shuō)明執(zhí)行過(guò)程,用例內(nèi)容如下(開(kāi)頭注釋部分為測(cè)試過(guò)程):

# This is the basic test required in for multisource replication
# The aim of this file is to test the basic usecases of msr.
# 0. Create two masters and a slave and setup a multisource replication
#    between them.
# 1. create a different databases on each master and test if they are replicated
#    to the slave.
# 2. create a different table on each master and test if they are replicated to
#    the to the slave.
# 3. Create a table with the same name on both masters and update non conflicting
#    data on that table. Test if the replication is done properly.
# 4. Check if updates happen on different master such that the resulting
#    data on slave is conflicting, check that one of the channels the slave
#    SQL thread is stopped.
#
#
# Note: Out of convention, server 2 is always made a slave for multisource testing.
#

#Skip on group replication runs
--source include/not_group_replication_plugin.inc
# Test requires master-info-repository=TABLE, relay-log-info-repository=TABLE
--source include/have_slave_repository_type_table.inc

--echo #
--echo # set up masters server_1 and server_3 with server_2 being a slave.
--echo #.
--let $rpl_topology= 1->2,3->2
--let $rpl_multi_source= 1
--source include/rpl_init.inc

--echo #
--echo # Test case 1: 1.a) create a database and table db1.t1 on server_1
--echo #                   and insert values in the table.
--let $rpl_connection_name= server_1
--source include/rpl_connection.inc
CREATE DATABASE db1;
CREATE TABLE db1.t1 ( a int);
......

啟動(dòng)測(cè)試指令 perl mysql-test-run.pl --do-test=rpl_multi_source 后,會(huì)啟動(dòng) 3 個(gè) mysqld 進(jìn)程,其中 2 個(gè) master 節(jié)點(diǎn),1 個(gè) slave 節(jié)點(diǎn):

?  rpl ps -xf | grep mysql
   6982 pts/2    S+     0:00      \_ perl mysql-test-run.pl rpl_multi_source_basic
   7125 pts/2    S+     0:00          \_ perl mysql-test-run.pl rpl_multi_source_basic
   7130 pts/2    S+     0:00              \_ /data/work/mysql/mysql80-install.bak_valgrind/bin//mysqltest_safe_process -- /data/work/mysql/mysql80-install.bak_valgrind/bin/mysqld --defaults-group-suffix=.1 --defaults-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/my.cnf --log-output=file --loose-debug-sync-timeout=600 --binlog-format=mixed --core-file
   7131 pts/2    Sl     0:04              |   \_ /data/work/mysql/mysql80-install.bak_valgrind/bin/mysqld --defaults-group-suffix=.1 --defaults-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/my.cnf --log-output=file --loose-debug-sync-timeout=600 --binlog-format=mixed --core-file
   7132 pts/2    S+     0:00              \_ /data/work/mysql/mysql80-install.bak_valgrind/bin//mysqltest_safe_process -- /data/work/mysql/mysql80-install.bak_valgrind/bin/mysqld --defaults-group-suffix=.2 --defaults-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/my.cnf --log-output=file --loose-debug-sync-timeout=600 --binlog-format=mixed --core-file
   7133 pts/2    Sl     0:06              |   \_ /data/work/mysql/mysql80-install.bak_valgrind/bin/mysqld --defaults-group-suffix=.2 --defaults-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/my.cnf --log-output=file --loose-debug-sync-timeout=600 --binlog-format=mixed --core-file
   7134 pts/2    S+     0:00              \_ /data/work/mysql/mysql80-install.bak_valgrind/bin//mysqltest_safe_process -- /data/work/mysql/mysql80-install.bak_valgrind/bin/mysqld --defaults-group-suffix=.3 --defaults-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/my.cnf --log-output=file --loose-debug-sync-timeout=600 --binlog-format=mixed --core-file
   7135 pts/2    Sl     0:04              |   \_ /data/work/mysql/mysql80-install.bak_valgrind/bin/mysqld --defaults-group-suffix=.3 --defaults-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/my.cnf --log-output=file --loose-debug-sync-timeout=600 --binlog-format=mixed --core-file
   7283 pts/2    S+     0:00              \_ /data/work/mysql/mysql80-install.bak_valgrind/bin//mysqltest_safe_process -- /data/work/mysql/mysql80-install.bak_valgrind/bin/mysqltest --defaults-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/my.cnf --silent --tmpdir=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/tmp --character-sets-dir=/data/work/mysql/mysql80-install.bak_valgrind/share/charsets --logdir=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/log --database=test --plugin_dir=/data/work/mysql/mysql80-install.bak_valgrind/lib/plugin --timer-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/log/timer --test-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/suite/rpl/t/rpl_multi_source_basic.test --tail-lines=20 --result-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/suite/rpl/r/rpl_multi_source_basic.result
   7284 pts/2    R      0:00                  \_ /data/work/mysql/mysql80-install.bak_valgrind/bin/mysqltest --defaults-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/my.cnf --silent --tmpdir=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/tmp --character-sets-dir=/data/work/mysql/mysql80-install.bak_valgrind/share/charsets --logdir=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/log --database=test --plugin_dir=/data/work/mysql/mysql80-install.bak_valgrind/lib/plugin --timer-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/var/log/timer --test-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/suite/rpl/t/rpl_multi_source_basic.test --tail-lines=20 --result-file=/data/work/mysql/mysql80-install.bak_valgrind/mysql-test/suite/rpl/r/rpl_multi_source_basic.result

可見(jiàn):

  1. 無(wú)論是 mysqldtest 還是 mysqld,都是由 mysqltest_safe_process 程序啟動(dòng)的。
  2. --defaults-group-suffix=.1 到 3 分別對(duì)應(yīng) 3 個(gè) mysqld 進(jìn)程,說(shuō)明 mtr 不是靠 mock 的形式來(lái)測(cè)試的,而是啟動(dòng)真 mysqld 進(jìn)程來(lái)測(cè)試

編譯安裝

安裝依賴(lài)

mysql-server 編譯需要:

# for mysql 8.0

sudo apt install gdb gcc g++ cmake -y
sudo apt install openssl libssl-dev -y
sudo apt install libncurses-dev libudev-dev -y
sudo apt install bison flex libaio-dev libreadline-dev libjemalloc-dev -y
sudo apt install libevent-dev zlib1g-dev libmecab-dev libgcrypt20-dev -y
sudo apt install libsasl2-dev libldap2-dev libtirpc-dev
sudo apt-get install libsasl2-dev # SASL
sudo apt-get install slapd ldap-utils # LDAP
sudo apt install valgrind doxygen libcurl4-gnutls-dev -y # extra

# centos 7.6
sudo yum install cmake gcc g++ # 由于 cmake、gcc 版本偏低,需要自行通過(guò)源碼編譯安裝
sudo yum install readline-devel bison flex libarchive openssl-devel
sudo yum install rpcgen libudev-devel ncurses-devel libtirpc libtirpc-devel
sudo yum install cyrus-sasl-devel # SASL
sudo yum install openldap openldap-devel # LDAP
sudo yum install valgrind # extra

# centos stream 9
sudo yum install cmake gcc g++ gcc-toolset-12-gcc gcc-toolset-12-gcc-c++ gcc-toolset-12-binutils
sudo yum install readline-devel bison flex libarchive openssl-devel # libtirpc-devel
sudo yum install rpcgen libudev-devel ncurses-devel libtirpc libtirpc-devel
sudo yum install cyrus-sasl-devel # SASL
sudo yum install openldap openldap-devel # LDAP
sudo yum install valgrind # extra

# macos
brew install lz4
brew install zlib
brew install clang

由于系統(tǒng)及版本差異,這里羅列的軟件包可能會(huì)有所缺失,版本也可能會(huì)有所不同。

對(duì)于 mtr 來(lái)說(shuō),也需要額外安裝一些依賴(lài):

# centos
yum -y install perl -y
sudo yum install perl-JSON -y
sudo yum install perl-Test-use-ok.noarch -y

# ubuntu
sudo apt install perl -y
sudo perl -MCPAN -e 'install JSON'

編譯

Debug 版本編譯選項(xiàng)示例:

# for MacOS and Ubuntu
CURDIR=`pwd`
INSTALLDIR=$CURDIR/../../mysql80-install
DATADIR=$CURDIR/../../mysql80-default-data
BOOSTDIR=$CURDIR/../../boost_1_77_0

rm CMakeCache.txt -f
cmake .. \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_INSTALL_PREFIX=$INSTALLDIR \
-DSYSCONFDIR=/etc \
-DMYSQL_DATADIR=$DATADIR \
-DMYSQL_UNIX_ADDR=/tmp/mysqld.sock \
-DMYSQL_TCP_PORT=3306 \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_DEBUG=1 \ # 必須是 debug 版本
-DWITH_BOOST=$BOOSTDIR \
-DWITH_SSL=/usr/local/openssl-1.1.1 \
-DFORCE_INSOURCE_BUILD=1

# -DWITH_ASAN=ON -DWITH_ASAN_SCOPE=ON -DWITH_UBSAN=ON \ # 選擇啟用哪些組件
# -DWITH_VALGRIND=ON \
# -DENABLE_GCOV=1 -DENABLE_GPROF=1 \

if [ $? != 0 ]; then
  exit 1
fi

# for MacOS, only need make
make -j4
make install

Release 版本編譯選項(xiàng)示例:

#!/bin/bash
# for MacOS and Ubuntu
CURDIR=`pwd`

# for 8.0.29
INSTALLDIR=$CURDIR/../../mysql80-install
#INSTALLDIR=/usr
DATADIR=$CURDIR/../../mysql80-default-data
BOOSTDIR=$CURDIR/../../boost_1_77_0

rm CMakeCache.txt -f
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_CONFIG=mysql_release \
-DFEATURE_SET=community \
-DWITH_EMBEDDED_SERVER=OFF \
-DWITHOUT_ROCKSDB=ON \
-DWITH_UNIT_TESTS=OFF \
-DWITH_BOOST=$BOOSTDIR \
-DFORCE_INSOURCE_BUILD=1 \
-DCOMPILATION_COMMENT="MySQL build $(date +%Y%m%d.%H%M%S.$(git rev-parse --short HEAD))"

#-DCMAKE_INSTALL_PREFIX=$INSTALLDIR \
#-DSYSCONFDIR=/etc \
#-DMYSQL_DATADIR=$DATADIR \
#-DWITH_MYISAM_STORAGE_ENGINE=1 \
#-DWITH_INNOBASE_STORAGE_ENGINE=1 \
#-DWITH_MEMORY_STORAGE_ENGINE=1 \
#-DWITH_PARTITION_STORAGE_ENGINE=1 \

if [ $? != 0 ]; then
        exit 1
fi
# for MacOS, only need make
make -j4
make install

-DCMAKE_BUILD_TYPE=type 選項(xiàng)說(shuō)明:

The type of build to produce:

  • RelWithDebInfo: default value。Enable optimizations and generate debugging information. This is the default MySQL build type.
  • Release: Enable optimizations but omit debugging information to reduce the build size. This build type was added in MySQL 8.0.13 (MySQL 5.7 is not supported).
  • Debug: Disable optimizations and generate debugging information. This build type is also used if the WITH_DEBUG option is enabled. That is, -DWITH_DEBUG=1 has the same effect as -DCMAKE_BUILD_TYPE=Debug.

目錄結(jié)構(gòu)

編譯安裝后,mysql-test 目錄樹(shù)結(jié)構(gòu)如下:

mysql-test
├── README
├── README.gcov # 代碼覆蓋率測(cè)試說(shuō)明,最后更新于2006年
├── README.stress # 壓力測(cè)試說(shuō)明,針對(duì) mysql-stress-test.pl ,最后更新于2006年

├── collections # 該目錄下的文件是官方推薦的回歸測(cè)試指令集
│   ├── README # 說(shuō)明文檔
│   ├── coverage.ignore # 指定需要忽略代碼覆蓋率測(cè)試的目錄
│   ├── disabled.def # 列出需要臨時(shí)禁用的測(cè)試用例,在運(yùn)行測(cè)試時(shí)會(huì)跳過(guò)
│   ├── disabled-asan.list # 除 disabled.def 文件所列用例之外,還需要臨時(shí)禁用的測(cè)試用例
│   ├── disabled-ubsan.list # 同上
│   ├── disabled-valgrind.list # 同上
│   ├── disabled_ndb.def # 僅在運(yùn)行 MySQL Cluster 時(shí)才需要臨時(shí)禁用的測(cè)試用例

        # 適合每天都運(yùn)行的回歸測(cè)試指令集
        # 涵蓋 default suites、非 default suites、針對(duì)復(fù)制和binlog的擴(kuò)展測(cè)試(區(qū)分不同的復(fù)制參數(shù))、InnoDB 擴(kuò)展測(cè)試(區(qū)分不同頁(yè)面大小)
│   ├── default.daily
        # 由于 valgrind 運(yùn)行比較耗時(shí),因此,該指令集只能涵蓋除 big-test 之外的所有 suites 。
        # 需要編譯時(shí)添加選項(xiàng) -DWITH_DEBUG=1 -DWITH_VALGRIND=1 的情況下,才能執(zhí)行 valgrind 測(cè)試。
        # 注意:通過(guò)實(shí)測(cè)、分析代碼,運(yùn)行 mtr 時(shí)必須添加 --valgrind 選項(xiàng)才能用到 valgrind 組件。
│   ├── default.daily-valgrind


        # 適合每周運(yùn)行一次的指令集,運(yùn)行耗時(shí)能達(dá)到48小時(shí)。
        # 是 default.daily 的超集,同時(shí),還指定了 --debug-server 。
        # 覆蓋 default suites + 非 default suites + 復(fù)制和binlog的擴(kuò)展 + InnoDB擴(kuò)展 + 其他按周運(yùn)行的指令集。
│   ├── default.weekly
│   ├── default.weekly-ndbcluster # 覆蓋 default.daily + ndbcluster + 部分非默認(rèn)指令集
│   ├── default.weekly-protocol # 編譯時(shí)需要設(shè)置 DWITH_TEST_TRACE_PLUGIN=1,只覆蓋 main suite。
        # 在啟用 --big-test 和 --debug-server 選項(xiàng)的前提下,運(yùn)行所有的指令集。
        # 需要編譯時(shí)添加選項(xiàng) -DWITH_DEBUG=1 -DWITH_VALGRIND=1 的情況下,才能執(zhí)行 valgrind 測(cè)試。
        # 注意:通過(guò)實(shí)測(cè)、分析代碼,運(yùn)行 mtr 時(shí)必須添加 --valgrind 選項(xiàng)才能用到 valgrind 組件。
│   ├── default.weekly-valgrind
│   ├── default.weekly.basic # 在禁用 --big-test 選項(xiàng)的前提下,運(yùn)行所有的指令集,即包含 default suites + 非 default suites。

        # 適用于每次push代碼時(shí)運(yùn)行的指令集,能控制在一個(gè)小時(shí)內(nèi)。
        # 更適用于 mysql 5.7 版本。
│   ├── default.push
│   ├── default.push-ndbcluster # 分為 default suites + 與 ndbcluster 相關(guān)的指令集
│   ├── default.push-valgrind # 分為 default suites(排除 rpl)+ ndb 相關(guān) suites + group_replication suite
│   ├── mysql-8.0-stage.push # 在 default.push 基礎(chǔ)上,為 mysql-8.0-stage 擴(kuò)展的測(cè)試用例,在merge到main分支前使用
│   ├── mysql-8.0-stage.push.basic # mysql-8.0-stage.push 的子集

│   ├── mysql-trunk-meb-itch.push # 文件為空
        # default.push 的超集,目的是在 push 到 main 分支前,提前發(fā)現(xiàn)問(wèn)題。
│   ├── mysql-trunk-stage.push # 內(nèi)容與 mysql-8.0-stage.push 一樣,在merge到main分支前使用
│   ├── mysql-trunk-stage.push.basic # mysql-trunk-stage.push 的子集
│   └── mysql-trunk-tsan.push # 由于 ThreadSanitizer 非常慢,因此,只測(cè)試 main suite

├── extra # 不屬于 main 和 其他 suites 的測(cè)試 case
│   ├── binlog_tests
│   │   ├── binlog.test
│   │   ├── binlog_cache_stat.test
│   │   ├── binlog_crash_safe_ddl.inc
│   │   ├── binlog_ddl.inc
        ......
│   │   └── tmp_table.test
│   └── rpl_tests
│       ├── binlog_transaction_compression.inc
│       ├── check_slave_delay.inc
        ......
│       └── type_conversions.test



├── lib # 測(cè)試框架相關(guān)依賴(lài)文件,里面主要是一些用perl實(shí)現(xiàn)的邏輯。
│   ├── My
│   │   ├── Config.pm
│   │   ├── ConfigFactory.pm
        ......
│   │   └── Test.pm
│   ├── mtr_cases.pm
    ......

├── lock_order_dependencies.txt # mysql-test-run.pl 讀取該文件來(lái)控制加鎖順序,與 --lock-order 選項(xiàng)有關(guān)。該文件非空。

# 在 mtr 運(yùn)行對(duì)應(yīng)工具期間,比如 asan,對(duì)應(yīng)的 .supp 文件用于指定需要跳過(guò)的測(cè)試用例。
#
# ASAN、LSAN、TSAN 出自谷歌的 Sanitizer 項(xiàng)目,包含了 ASAN、LSAN、MSAN、TSAN等內(nèi)存、線程錯(cuò)誤的檢測(cè)工具。
├── asan.supp # ASAN(Address-Sanitizier),內(nèi)存錯(cuò)誤檢測(cè)工具。早期是LLVM中的特性,后被加入GCC 4.8。
├── lsan.supp # LSAN(LeakSanitizer),內(nèi)存泄漏檢測(cè)工具,已集成在 ASAN(AddressSanitizer)中。
├── tsan.supp # TSAN(ThreadSanitizer),線程間數(shù)據(jù)競(jìng)爭(zhēng)的檢測(cè)工具。
├── valgrind.supp # Valgrind 是一個(gè)工具集。集成了:
                  # Memcheck 內(nèi)存錯(cuò)誤檢測(cè)器。
                  # Cachegrind 緩存和分支預(yù)測(cè)分析器。
                  # Callgrind 可生成緩存分析器的調(diào)用圖。
                  # Helgrind 線程錯(cuò)誤檢測(cè)器。
                  # DRD 也是線程錯(cuò)誤檢測(cè)器。
                  # Massif 堆分析器,它可以幫助程序使用更少的內(nèi)存。
                  # DHAT 一種不同類(lèi)型的堆分析器。使用它可以了解塊壽命,塊利用率和布局效率低下的問(wèn)題。

├── mtr -> ./mysql-test-run.pl # mysql-test-run.pl 腳本別名
├── mysql-stress-test.pl
├── mysql-test-run -> ./mysql-test-run.pl
├── mysql-test-run.dox
├── mysql-test-run.pl # mtr 入口文件,測(cè)試框架核心邏輯

# include/ 目錄包含.inc 文件,在測(cè)試用例中通過(guò) source 命令引入,就像 C/C++ 的頭文件。建議將多次重復(fù)使用的測(cè)試語(yǔ)句整合到 .inc 文件中。
├── include # include 下所有 *.inc 都會(huì)被 t/ 目錄下的 *.test 引用
│   ├── Load_data.inc
    ......
│   ├── json_lookup.inc
│   ├── keyring_tests
│   │   ├── binlog
│   │   │   ├── rpl_binlog_cache_encryption.inc
        ......
│   ├── keyring_udf_keyring_plugin_loaded.inc
    ......
│   └── year-engine.test
# t/ 和 r/ 目錄分別對(duì)應(yīng)于 main suite 的測(cè)試 case 和 期望結(jié)果。
# 測(cè)試 case 以 .test 后綴結(jié)尾。
# 另外還有 .opt 后綴文件,它里面指定了MySQL的參數(shù)。某些測(cè)試用例會(huì)涉及重啟,在重啟時(shí)可能會(huì)變更 mysql 參數(shù),可能會(huì)用 .opt 文件中指定的參數(shù)。
├── t # 該目錄下的每個(gè) *.test 都對(duì)應(yīng)一個(gè)測(cè)試 case 。
│   ├── 1st.test
│   ├── admin_interface.test
    ......
├── r # 路徑和命名 與 t/ 目錄一一對(duì)應(yīng),表示對(duì)應(yīng)測(cè)試用例的期望輸出。
│   ├── 1st.result
│   ├── admin_interface.result
    ......
│   └── year-myisam.result

├── std_data # 測(cè)試所用的數(shù)據(jù)文件,某些測(cè)試 case 需要使用到。
│   ├── 14897.frm
│   ├── 256kb.json
│   ├── 41_decimal.frm
│   ├── 57import.zip
    ......
│   └── x_y_data.csv

# 測(cè)試框架有 suite 的概念,每個(gè) suite 為一個(gè)測(cè)試用例集合,默認(rèn)的 suite 為 main,它的測(cè)試集合位于當(dāng)前目錄下的 t/ 目錄。
# 除了 main suite 之外,其他的 suite 基本都以子目錄的形式存放于當(dāng)前文件夾,比如 json、binlog 等。
├── suite # 本目錄下每個(gè)子目錄都包含 include/r/t 三個(gè)子目錄,其中:
          # include/*.inc 會(huì)被 t/*.test 引用
          # t/*.test 是各個(gè)測(cè)試case的主文件
          # r/*.result 是期望的測(cè)試輸出
          # 另外,t/ 與 r/ 路徑中的文件是一一對(duì)應(yīng)的。
│   ├── audit_null
    ......
│   ├── innodb
│   │   ├── include
│   │   │   ├── alter_table_pk_no_sort.inc
            ......
│   │   ├── r
│   │   │   ├── add_foreign_key.result
│   │   │   ├── alter_crash.result
            ......
│   │   └── t
│   │       ├── add_foreign_key.test
│   │       ├── alter_crash.test
            ......
│   │       └── zlob_update_purge.test
│   ├── innodb_fts
    ......

└── var # 測(cè)試開(kāi)啟后 mtr 創(chuàng)建的目錄,用于存放測(cè)試過(guò)程產(chǎn)生的數(shù)據(jù)目錄、日志等。
    ├── data
    │   ├── #ib_16384_0.dblwr
        ......
    ......
    ├── my.cnf
    ├── run
    ├── std_data
    │   ├── 14897.frm
    ......
    └── tmp
        └── mysqld.1

參數(shù)

參考:

  • MySQL: MySQL Test Programs
  • MySQL: mysql-test-run.pl — Run MySQL Test Suite

常用參數(shù)

  • --force
    • 默認(rèn)情況下,只要遇到一個(gè) case 出錯(cuò),測(cè)試程序就會(huì)退出。
    • 加入該參數(shù)后,mtr 會(huì)忽略錯(cuò)誤并繼續(xù)執(zhí)行下一個(gè) case 直到所有 case 執(zhí)行結(jié)束再退出。
    • 但如果腳本存在太多錯(cuò)誤還是會(huì)退出,可設(shè)置--max-test-fail=0 忽略計(jì)數(shù)。
  • --max-test-fail
    • 測(cè)試過(guò)程中失敗 case 數(shù)達(dá)到一定值會(huì)退出,默認(rèn)值是 10,設(shè)置為 0 則會(huì)忽略計(jì)數(shù)。
  • --record
    • 是否記錄 results 結(jié)果,首次執(zhí)行建議帶上,讓其自動(dòng)生成 .results 文件,再基于該文件修改成我們預(yù)期的結(jié)果
    • 若一個(gè)執(zhí)行輸出結(jié)果和 testname.result 文件不同,會(huì)生成一個(gè) testname.reject 文件,該文件在下次執(zhí)行成功之后被刪除;
    • 檢查.reject文件的內(nèi)容,如果里面是期望的輸出,則將內(nèi)容拷貝到 .result 文件中,作為以后判斷運(yùn)行結(jié)果是否通過(guò)的依據(jù);
  • --parallel
    • 指定運(yùn)行測(cè)試 case 的并行線程數(shù)。
  • —-nowarnings
    • 忽略 warnings 錯(cuò)誤。
    • 設(shè)置該參數(shù)后,當(dāng)出現(xiàn) warnings 錯(cuò)誤,不再累加 --max-test-fail 。
  • --big-test
    • 執(zhí)行標(biāo)記為 big 的 test cases,也就是同時(shí)覆蓋 非 big + big。這是因?yàn)闃?biāo)記為 big 的 case 較大、耗時(shí)較長(zhǎng),默認(rèn)不會(huì)執(zhí)行。
  • --only-big-test :只啟用帶 big 標(biāo)記的 test cases,也就是會(huì)跳過(guò)普通的非 big 標(biāo)記的 cases。
  • --suite=[suitename1,...]
    • 默認(rèn)情況下 mtr 會(huì)執(zhí)行所有測(cè)試 case,但有時(shí)候我們要執(zhí)行一個(gè)測(cè)試集,就可用該參數(shù)來(lái)指定,比如./mtr --suite=rpl 只執(zhí)行 rpl 測(cè)試集。
  • --do-test=events
    • 執(zhí)行所有以 events為前綴的 case(搜索范圍為 t/和所有的 suite)。
    • --do-test 的參數(shù)支持正則表達(dá)式,上述命令等效于 ./mtr --do-test=events.*
    • 所以如果想測(cè)試所有的包括 innodb 的 case,可以用 ./mtr --do-test=.*innodb.*
  • 連接遠(yuǎn)程的數(shù)據(jù)庫(kù)進(jìn)行 mtr 執(zhí)行:
# --extern  一般情況下mtr是啟動(dòng)自己的MySQL服務(wù)來(lái)進(jìn)行測(cè)試,如果在啟動(dòng)時(shí)指定參數(shù) --extern,則可以使用指定的 MySQL 服務(wù)進(jìn)行測(cè)試
./mtr --extern host=192.168.6.1 --extern port=3306 --extern user=root --extern password='123456'  --record --force example.1
./mtr --extern host=127.0.0.1 --extern port=3306 --extern user=root --extern password= --force --max-test-fail=0 --suite=main
./mtr --extern host=127.0.0.1 --extern port=3306 --extern user=root --extern password= --force --max-test-fail=0 --fast --suite=main
  • --debug-server :Use debug version of server, but without turning on tracing.
  • --platform--exclude-platform :用于指定或排除平臺(tái)的選項(xiàng)。
    • 如果 MTR 不是運(yùn)行在 pushbuild test 環(huán)境中(存在環(huán)境變量PB2WORKDIR,即export PB2WORKDIR=),這兩個(gè)選項(xiàng)是不生效的。
  • comment=STR :添加該選項(xiàng)后,mtr 會(huì)將注釋信息打印到 stdout 。比如 --comment=all-default-big
##############################################################################
# all-default-big
##############################################################################
  • --vardir=DIR :指定測(cè)試過(guò)程中生成的文件存放的目錄,默認(rèn)是當(dāng)前路徑下的var/ 。
  • --report-features :指定該選項(xiàng)后,mtr 首先運(yùn)行名為 report_features 的 case,該 case 沒(méi)有任何輸出(設(shè)置了--disable_query_log) 。
  • --unit-tests-report :加上該參數(shù)后,如果在編譯后的源碼目錄執(zhí)行 mtr,會(huì)在測(cè)試的最后階段加上每個(gè)測(cè)試用例的報(bào)告信息。
......

[----------] 1027 tests from Spec/ReuseConnectionTest (404 ms total)

[----------] Global test environment tear-down
[==========] 1027 tests from 1 test suite ran. (70804 ms total)

Total Test time (real) = 3363.87 sec

......

The following tests FAILED:
        203 - routertest_component_metadata_ttl (Subprocess aborted)
        206 - routertest_component_rest_api_enable (Failed)
        222 - routertest_component_routing_splicer (Failed)
        224 - routertest_integration_routing_reuse (Failed)
Errors while running CTest
  [  FAILED  ] CheckEdgeHttpsPortValues/UseEdgeHttpsPortValues.ensure_bootstrap_works_for_edge_https_port_values/1, where GetParam() = 65535 (1444 ms)
  [  FAILED  ] 1 test, listed below:
  [  FAILED  ] CheckEdgeHttpsPortValues/UseEdgeHttpsPortValues.ensure_bootstrap_works_for_edge_https_port_values/1, where GetParam() = 65535
   1 FAILED TEST
  [  FAILED  ] Spec/SplicerFailParamTest.fails/client_ssl_dh_params_not_exists, where GetParam() = 64-byte object <C8-CE 3D-2F 4D-56 00-00 F0-DA BB-30 4D-56 00-00 B0-DB BB-30 4D-56 00-00 B0-DB BB-30 4D-56 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 3D-D1 F9-2E 4D-56 00-00 AD-D0 F9-2E 4D-56 00-00> (383 ms)
  [  FAILED  ] 1 test, listed below:
  [  FAILED  ] Spec/SplicerFailParamTest.fails/client_ssl_dh_params_not_exists, where GetParam() = 64-byte object <C8-CE 3D-2F 4D-56 00-00 F0-DA BB-30 4D-56 00-00 B0-DB BB-30 4D-56 00-00 B0-DB BB-30 4D-56 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 3D-D1 F9-2E 4D-56 00-00 AD-D0 F9-2E 4D-56 00-00>
   1 FAILED TEST
  [  FAILED  ] 0 tests, listed below:
   0 FAILED TESTS
  [  FAILED  ] Spec/ReuseConnectionTest: SetUpTestSuite or TearDownTestSuite
   1 FAILED TEST SUITE

Unit tests: 98% tests passed, 4 tests failed out of 224
  The following tests FAILED:
        206 - routertest_component_rest_api_enable (Failed)
        222 - routertest_component_routing_splicer (Failed)
        224 - routertest_integration_routing_reuse (Failed)
Report from unit tests in /data/work/mysql/mysql-server/mysql-test/var-all-default-big/ctest.log
------------------------------------------------------------------------------
The servers were restarted 3 times
The servers were reinitialized 0 times
Spent 53.181 of 3579 seconds executing testcases

Completed: Failed 1/6 tests, 83.33% were successful.

Failing test(s): unit_tests
  • --no-skip :指定該選項(xiàng)后,即使 .inc 文件中要求的條件不滿(mǎn)足,也會(huì)運(yùn)行所有的 mtr 測(cè)試 cases 。特別地,在 include/excludenoskip.list 文件中指定的 .inc 文件列表依然會(huì)跳過(guò)。
  • --skip-ndb :與選項(xiàng)--skip-ndbcluster 含義相同,表示跳過(guò)與 ndb 相關(guān)的 suites,默認(rèn)啟用。
    • ndb 引擎也是開(kāi)源的(storage/ndb/),涉及 ndb 引擎的 suites 包括:
- ndb
- ndb_big
- ndb_opt
- ndb_ddl
- ndb_binlog
- ndb_rpl
- rpl_ndb
- ndbcluster
- gcol_ndb
- json_ndb
  • --with-ndb-only :與選項(xiàng)--with-ndbcluster-only 含義相同,只運(yùn)行與 ndb 相關(guān)的 suites 。如果沒(méi)顯示指定--suites 參數(shù),則會(huì)跳過(guò)所有非 ndb 的 suites ;反之,若指定了,也會(huì)額外運(yùn)行指定的 suites 。
  • --ps-protocol :在 client 和 server 端之間使用 prepared-statement 協(xié)議(binary),會(huì)將--ps-protocol 參數(shù)直接傳給 mysqltest 程序。
  • --skip-combinations :忽略組合文件或選項(xiàng),也就是忽略:
# 啟動(dòng) mtr 時(shí)的日志:
Collecting tests
 - Adding combinations for binlog
 - Adding combinations for binlog_gtid
 - Adding combinations for binlog_nogtid
 - Adding combinations for rpl
 - Adding combinations for rpl_gtid
 - Adding combinations for rpl_nogtid

# 對(duì)應(yīng)于
./suite/rpl_nogtid/combinations
./suite/binlog_gtid/combinations
./suite/binlog/combinations
./suite/rpl/combinations
./suite/rpl_gtid/combinations
./suite/binlog_nogtid/combinations

# 除此之外,還有:
./suite/ndb_rpl/t/ndb_rpl_innodb2ndb.combinations
./suite/ndb_rpl/t/ndb_rpl_conflict_epoch.combinations
./suite/ndb_rpl/t/ndb_rpl_basic.combinations

suitename 可選范圍

main,

audit_null,
auth_sec,

binlog,
binlog_gtid,
binlog_nogtid,
clone,

collations,

component_keyring_file,
connection_control,
encryption,

engines,
engines/funcs,
engines/iuds,
engines/rr_trx,
federated,

funcs_1, # 額外功能(包括視圖、存儲(chǔ)過(guò)程、INFORMATION_SCHEMA等)
funcs_2, # 額外功能(字符集等)
gcol, # 虛擬生成列
gis,
group_replication,
information_schema,

innodb,
innodb_fts, # 全文索引
innodb_gis,
innodb_stress,
innodb_undo,
innodb_zip,

interactive_utilities,
jp, # 日語(yǔ)字符集
json,
large_tests,
lock_order,
max_parts,
memcached,
network_namespace,
opt_trace,
parts,parts/special_tests,
perfschema,
query_rewrite_plugins,

rpl,
rpl_gtid,
rpl_nogtid,

secondary_engine,

service_status_var_registration,
service_sys_var_registration,
service_udf_registration,

special,
stress,
sys_vars,
sysschema,

test_service_sql_api,
test_services,

x

suites 分類(lèi)

default suites:

auth_sec,binlog,binlog_gtid,binlog_nogtid,clone,
collations,component_keyring_file,connection_control,encryption,
federated,funcs_2,gcol,gis,information_schema,
innodb,innodb_fts,innodb_gis,innodb_undo,innodb_zip,
interactive_utilities,json,
main,
opt_trace,parts,perfschema,query_rewrite_plugins,rpl,rpl_gtid,rpl_nogtid,secondary_engine,
service_status_var_registration,service_sys_var_registration,service_udf_registration,
sys_vars,sysschema,test_service_sql_api,test_services,x

非 default suites:

funcs_2, stress, jp, nist
engines, memcached, audit_null
group_replication

指令示例

mtr 執(zhí)行路徑:

  • 代碼覆蓋率、單元測(cè)試只能在 編譯的源碼目錄/mysql-test 執(zhí)行。
  • 其他測(cè)試在 編譯的源碼目錄/mysql-test安裝目錄/mysql-test 都可以執(zhí)行。
  • 如無(wú)特殊需求,更建議在安裝目錄執(zhí)行 mtr 測(cè)試(目錄結(jié)構(gòu)更清晰)。

常用指令:

  • 在未編寫(xiě) .result文件的情況下,可先通過(guò)--reocrd選項(xiàng)生成.result文件,再基于該文件修改成期望的結(jié)果:
perl mysql-test-run.pl --record mytest
  • 常態(tài)下執(zhí)行,不加 --reocrd選項(xiàng),這樣才會(huì)比對(duì)實(shí)際結(jié)果與期望結(jié)果是否相同:
perl mysql-test-run.pl mytestcase1
perl mysql-test-run.pl --suites=main,rpl # 指定多個(gè) suites
  • 當(dāng)一些測(cè)試 case 頻繁失敗時(shí),可單獨(dú)運(yùn)行這些 case 以便調(diào)試:
./mtr testcasename --record

# 只運(yùn)行基礎(chǔ)套餐里的 subquery_all 用例( t/subquery_all.test )
# 可選 --charset-for-testdb=utf8mb4
./mtr --force --big-test --nowarnings --max-test-fail=0 main.subquery_all

# 如需執(zhí)行多個(gè) case,可通過(guò)空格分割,比如:
./mtr --force --big-test --nowarnings --max-test-fail=0 main.subquery_all main.myisam_explain_json_non_select_none

  • 如果不指定任何 suite,mtr 默認(rèn)會(huì)執(zhí)行所有 default suites(包括 main)
./mtr --force
  • 執(zhí)行 main suite 中的所有 case(所有mysql-test/t/*.test),忽略中間的 warnings 報(bào)錯(cuò),強(qiáng)制運(yùn)行完所有 case:
./mtr  --suite=main --force --max-test-fail=0 --nowarnings --parallel=8
./mtr  --suite=main --force --max-test-fail=0 --nowarnings --parallel=8 --big-test

  • 執(zhí)行所有以 events 為前綴的 case,搜索范圍為 mysql-test/tmysql-test/suite,注意不包括extra/
# --do-test 參數(shù)支持正則表達(dá)式,該指令等效于./mtr --do-test=events.*
./mtr --do-test=events --force --max-test-fail=0

# 如果想測(cè)試所有包含 innodb 的 case,可以用 ./mtr --do-test=.*innodb.*

特殊用法:

  • 1、準(zhǔn)備數(shù)據(jù)庫(kù): create database test 。

    • a)執(zhí)行 ./mtr --extern host=127.0.0.1 --extern port=3306 --extern user=root --extern password= --force --max-test-fail=0 --suite=main ,第一個(gè)非 skipped case 可以執(zhí)行成功,但之后的 case 全部失敗。

    • b)分析原因,發(fā)現(xiàn)是每執(zhí)行完一個(gè) case ,mtr 就會(huì) shutdown mysqld server,下一個(gè) case 再啟動(dòng),而這里是使用的外部 mysql,則不會(huì)啟動(dòng)。

  • 2、查看手冊(cè),發(fā)現(xiàn)有一個(gè)參數(shù)可以控制是否每個(gè) case 都重啟 mysqld:

--fast

Do not perform controlled shutdown when servers need to be restarted or at the end of the test run. This is equivalent to using --shutdown-timeout=0.
  • 3、添加后,雖然不重啟了,但會(huì)導(dǎo)致一些 case 失敗。 這是因?yàn)橛行?case 需要初始化一些參數(shù)
Note

    If a test case has an .opt file that requires the server to be restarted with specific options, the
    file will not be used. The test case likely will fail as a result.

可見(jiàn),官方對(duì)這種用法的支持尚不完善。

推薦用法

如果需要驗(yàn)證 release 版本穩(wěn)定性(適用于 QA、研發(fā)),可參考 default.daily 中的指令集。

  • 該指令集覆蓋了單元測(cè)試(必須以 DEBUG 編譯)、壓力測(cè)試等。

如何添加測(cè)試用例?

1. 示例一

我們通過(guò)一個(gè)最簡(jiǎn)單的例子來(lái)說(shuō)明這個(gè)框架是怎么使用的。

1.1. 創(chuàng)建測(cè)試用例

mysql-test/t 目錄下創(chuàng)建一個(gè)文件名為 mytest.test 的測(cè)試用例:

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

SET SQL_WARNINGS=1;

--echo #
--echo # test content
--echo #
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2);
SELECT * FROM t1;
DROP TABLE t1;

mysql-test/r 目錄下創(chuàng)建名為mytest.result 的文件:

DROP TABLE IF EXISTS t1;
SET @@sql_mode='NO_ENGINE_SUBSTITUTION';
SET SQL_WARNINGS=1;
#
# test content
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2);
SELECT * FROM t1;
a
1
2
DROP TABLE t1;

可見(jiàn),.result 文件中不僅要記錄 SQL,還要記錄輸出結(jié)果。

1.2. 執(zhí)行測(cè)試,成功

指令:

cd mysql80-debug/mysql-test
./mtr main.mytest

輸出:

Logging: ./mtr  main.mytest
MySQL Version 8.0.29
Checking supported features
 - Binaries are debug compiled
Using 'all' suites
Collecting tests
Checking leftover processes
Removing old var directory
Creating var directory '/Users/wslu/work/mysql/mysql80-debug/mysql-test/var'
Installing system database
Using parallel: 1

==============================================================================
                  TEST NAME                       RESULT  TIME (ms) COMMENT
------------------------------------------------------------------------------
[ 50%] main.mytest                               [ pass ]     63
[100%] shutdown_report                           [ pass ]
------------------------------------------------------------------------------
The servers were restarted 0 times
The servers were reinitialized 0 times
Spent 0.063 of 16 seconds executing testcases

Completed: All 2 tests were successful.

看到 successful 說(shuō)明執(zhí)行成功。

1.3. 修改 result 文件

mytest.result 文件中添加一些字符:

DROP TABLE IF EXISTS t1;
SET @@sql_mode='NO_ENGINE_SUBSTITUTION';
SET SQL_WARNINGS=1;
#
# test content
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2);
SELECT * FROM t1; # new comment
a
1
2
DROP TABLE t1;

1.4. 再次執(zhí)行測(cè)試,失敗

再次執(zhí)行指令./mtr main.mytest ,可見(jiàn)# new comment 那一行報(bào)錯(cuò):

==============================================================================
                  TEST NAME                       RESULT  TIME (ms) COMMENT
------------------------------------------------------------------------------
[ 50%] main.mytest                               [ fail ]
        Test ended at 2023-03-20 15:07:50

CURRENT_TEST: main.mytest
--- /Users/wslu/work/mysql/mysql80-debug.bak_asan_ubsan_gcov/mysql-test/r/mytest.result  2023-03-20 10:07:31.000000000 +0300
+++ /Users/wslu/work/mysql/mysql80-debug.bak_asan_ubsan_gcov/mysql-test/var/log/mytest.reject  2023-03-20 10:07:50.000000000 +0300
@@ -7,7 +7,7 @@
 CREATE TABLE t1 (a INT);
 INSERT INTO t1 VALUES (1);
 INSERT INTO t1 VALUES (2);
-SELECT * FROM t1; # new comment
+SELECT * FROM t1;
 a
 1
 2

mysqltest: Result length mismatch


The result from queries just before the failure was:
DROP TABLE IF EXISTS t1;
SET @@sql_mode='NO_ENGINE_SUBSTITUTION';
SET SQL_WARNINGS=1;
#
# test content
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2);
SELECT * FROM t1;
a
1
2
DROP TABLE t1;
safe_process[19130]: Child process: 19131, exit: 1

 - the logfile can be found in '/Users/wslu/work/mysql/mysql80-debug.bak_asan_ubsan_gcov/mysql-test/var/log/main.mytest/mytest.log'

[100%] shutdown_report                           [ pass ]
------------------------------------------------------------------------------

mtr 會(huì)指出具體是哪行導(dǎo)致的 case 失敗。

常見(jiàn)問(wèn)題 FAQ

test case failed 原因

  1. 產(chǎn)生的測(cè)試結(jié)果文件與預(yù)期輸出文件 diff 結(jié)果不一致:
    1. 期望輸入的 SQL 執(zhí)行成功,實(shí)際執(zhí)行失敗。
    2. 期望輸入的 SQL 執(zhí)行失敗,實(shí)際執(zhí)行成功。
    3. 比如:mysql-test/t/select_all.test 這個(gè)測(cè)試 case,其預(yù)期結(jié)果在mysql-test/r/select_all.result,在實(shí)際執(zhí)行時(shí),會(huì)將執(zhí)行結(jié)果與mysql-test/r/select_all.result作比較,若不一致,則失敗,并在mysql-test/var/log目錄生成一個(gè).reject文件。
  2. 測(cè)試過(guò)程中 mysql server 掛掉。這種情況一般會(huì)報(bào)“丟失連接”的錯(cuò)誤。
  3. 測(cè)試期間 MySQL Server 端寫(xiě)入了未過(guò)濾的 warnings 或 errors 日志。

此外,測(cè)試用例可以執(zhí)行外部程序,因此在某些方面,測(cè)試框架可以擴(kuò)展為測(cè)試 SQL 語(yǔ)句以外的用途。
最后,可以在測(cè)試中嵌入一小段 Perl 代碼。這有時(shí)可用于執(zhí)行超出測(cè)試語(yǔ)言或 SQL 能力的操作或執(zhí)行邏輯。

可使用一些技巧來(lái)定為具體的錯(cuò)誤原因,詳見(jiàn)下節(jié)。

異常調(diào)試

分析日志

默認(rèn)情況下,在目錄 mysql-test/var/log/中有日志生成(若指定 --vardir 參數(shù),則以該參數(shù)路徑為準(zhǔn)),分析該日志也能得到一些有用信息。

比如 啟動(dòng)失敗,則可以查看 bootstrap.log 文件,去掉命令中的 --bootstrap 并運(yùn)行即可啟動(dòng)對(duì)應(yīng)的 MySQL 服務(wù)來(lái)驗(yàn)證、調(diào)試。

verbose 參數(shù)

啟動(dòng) mtr 時(shí)加 --verbose 參數(shù),定位到引用的腳本位置后可以配置 --echo 命令修改調(diào)試。

如果加上 --verbose 打印的內(nèi)容還不夠詳細(xì),可以再加一個(gè),即 --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 參數(shù)和 gdb 參數(shù)

mtr 支持的一些 debug 參數(shù):

  debug                 Dump trace output for all servers and client programs.
  debug-common          Same as debug, but sets 'd' debug flags to
                        "query,info,error,enter,exit"; you need this if you
                        want both to see debug printouts and to use
                        DBUG_EXECUTE_IF.
  debug-server          Use debug version of server, but without turning on
                        tracing.
  debugger=NAME         Start mysqld in the selected debugger.
  gdb                   Start the mysqld(s) in gdb.
  lldb                  Start the mysqld(s) in lldb.

可見(jiàn),要想跟蹤調(diào)用過(guò)程,只有 --debug--gdb 參數(shù)滿(mǎn)足要求,會(huì)生成 trace 信息。

示例:

# 這幾條指令很耗費(fèi)內(nèi)存
./mtr --debug --suite=rpl
./mtr --gdb --suite=rpl
./mtr --debug --gdb --suite=rpl

指令執(zhí)行后,生成 trace 文件,比如 var/log/bootstrap.trace

腳本自身支持 debug 參數(shù)

如果引用(source)的腳本支持 debug 參數(shù),比如常用的 $rpl_debug,則可以修改相應(yīng)的 .inc 文件以獲得更多的 debug 信息。

perl 的調(diào)試模式

添加-d 參數(shù)可進(jìn)入 perl 語(yǔ)言的 debug 模式,便于調(diào)試 mysql-test-run.pl 及其調(diào)用。示例:

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>

調(diào)試模式常用命令:

h       查看幫助文檔
c line  運(yùn)行到指定行
n       運(yùn)行到下一行
s       跳到函數(shù)內(nèi)部運(yùn)行
l       查看代碼
q       退出

歡迎關(guān)注我的微信公眾號(hào)【數(shù)據(jù)庫(kù)內(nèi)核】:分享主流開(kāi)源數(shù)據(jù)庫(kù)和存儲(chǔ)引擎相關(guān)技術(shù)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-415684.html

標(biāo)題 網(wǎng)址
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

到了這里,關(guān)于特性介紹 | MySQL 測(cè)試框架 MTR 系列教程(一):入門(mén)篇的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包