作者:卢文双 资深数据库内核研发
去年年底通过微信公众号【数据库内核】设定了一个目标——2023 年要写一系列 特性介绍+内核解析 的文章(现阶段还是以 MySQL 为主)。
虽然关注者很少,但本着“说到就要做到”的原则,从这篇就开始了。
序言:
以前对 MySQL 测试框架 MTR 的使用,主要集中于 SQL 正确性验证。近期由于工作需要,深入了解了 MTR 的方方面面,发现 MTR 的能力不仅限于此,还支持单元测试、压力测试、代码覆盖率测试、内存错误检测、线程竞争与死锁等功能,因此,本着分享的精神,将其总结成一个系列。
主要内容如下:
- 入门篇:工作机制、编译安装、参数、指令示例、推荐用法、添加 case、常见问题、异常调试
- 进阶篇:高阶用法,包括单元测试、压力测试、代码覆盖率测试、内存错误检测、线程竞争与死锁
- 源码篇:分析 MTR 的源码
- 语法篇:单元测试、压力测试、mysqltest 语法、异常调试
由于个人水平有限,所述难免有错误之处,望雅正。
本文是第一篇入门篇。
本文首发于 2023-03-18 21:58:52
本系列基于 MySQL 8.0.29 版本,且主要在 Ubuntu 22.04 X86_64 验证(部分指令也在 Ubuntu 20.04 X86_64、Ubuntu 22.04 ARM64、MacOS M1 做了验证),如有例外,会特别说明。
简介
在修改内核代码后,不仅需要测试新增功能,同时也要对原有功能做回归测试,以保证新加代码对原有功能没有影响,这就需要用到 MySQL 源码自带的测试框架 mtr。
MySQL 测试框架是一个以 MySQL 框架和内部引擎为测试对象的工具,主要执行脚本在安装路径(make install后的路径)下的mysql-test目录,基本覆盖了所有 MySQL 的特性和异常情况。
MySQL 测试框架 mtr 主要包含如下几个组件:
- mysql-test-run.pl :perl 脚本,简称 mtr,是 MySQL 最常用的测试工具,负责控制流程,包括启停、识别执行哪些用例、创建文件夹、收集结果等等,主要作用是验证 SQL 语句在各种场景下是否返回正确的结果。
- mysqltest :C++二进制程序,负责执行测试用例,包括读文件、解析特定语法、执行用例。
- 用例的特殊语法(比如,
--source,--replace_column等)都在command_names和enum_commands两个枚举结构体中。
- 用例的特殊语法(比如,
- mysql_client_test :C++二进制程序,用于测试 MySQL 客户端 API(mysqltest 无法用于测试 API)。
- 从代码看,只有启用
--valgrind或--valgrind-mysqltest选项,才会用到mysql_client_test。
- 从代码看,只有启用
- mysql-stress-test.pl :perl 脚本,用于 MySQL Server 的压力测试。
- 支持 gcov/gprof 代码覆盖率测试工具。
除此之外,还提供了单元测试工具(严格来说不属于 mtr ),以便为存储引擎和插件创建单独的单元测试程序。
由于 MySQL 测试框架的入口是 mysql-test-run.pl(它会调用上述其他组件),因此,一般将 MySQL 测试框架简称为 mtr。
mtr 工作原理
概述
mtr 采用t/r模式(t目录中存储具体的测试 case,文件以.test结尾;r目录中存储了对应 case 的期望结果,文件以.result结尾),主要测试步骤是“通过执行一个 case,将该 case 的输出结果,与标准的输出结果(期望结果)作 diff”:
- 如果完全一样,则说明该 case 通过;
- 反之,则说明该 case 失败。
- 可能原因:case 本身写的有问题;MySQL 服务有问题。
如果t目录中的某个 case 在r目录中没有对应.result文件:
- 那么,只要该 case 能正常执行完,mtr 就会判定该 case 通过;
- 反之,若执行过程中出现 mysql server crash 等异常问题,mtr 就会判定该 case 失败。
上文说的 case 是指一系列的语句,包括 SQL 语句和一些必要的 mysqltest command。
所有 case 可分为三部分,分别为:
- main:测试 case 位于
mysql-test/t目录,期望结果(如果有的话)位于mysql-test/r目录,二者中的文件是一一对应的,比如:mysql-test/t/alter_debug.test、mysql-test/r/alter_debug.result。 - suite :路径位于
mysql-test/suite目录,其中包含很多测试 case 的集合,每个集合都是一个单独的子目录(比如mysql-test/suite/binlog),在子目录中又分别包含 r、t 两个目录。 - extra :应该是对上述两种 case 的补充,位于
mysql-test/extra/目录,在 8.0.29 版本中只包含binlog_tests、rpl_tests两个集合。
框架流程
mysql-test-run.pl框架运行流程如下:
1、初始化(Initialization)。
- 确定用例执行范围,包括运行哪些 suite,skip 哪些用例,在本阶段根据
disabled.def文件、--skip-xxx命令(比如skip-rpl)等确定执行用例。 - 同时,初始化数据库。后面运行用例启动数据库时,不需要每次初始化,只需从这里的目录中拷贝启动。
2、运行用例(run test)。
主线程根据参数--parallel(默认是 1)启动一个或者多个用例执行线程(worker),各线程有自己独立的 client port,data dir 等。
启动的 worker 与主线程之间是 server-client 模式,主线程是 server,worker 是 client。
- 主线程与 worker 是一问一答模式,主线程向 worker 发送运行用例的文件路径、配置文件参数等各种参数信息,worker 向主线程返回运行结果,直到所有在 collection 中的用例都运行完毕,主线程 close 各 worker,进行收尾工作。
- 主线程先读取各 worker 返回值,对上一个用例进行收尾工作。之后,读取 collection 中的用例,通过本地 socket 发送到 worker 线程,worker 线程接收到主线程命令,运行本次用例测试的核心逻辑,主要包括 3 件事:启动 mysqld、启动并监控 mysqltest,处理执行结果。
- 启动 mysqld: 根据参数启动一个或者多个 mysqld server 进程,大多数情况下会拷贝主线程初始化后的目录到 worker 的数据目录,作为新实例的启动目录,用 shell 命令启动数据库。
- 启动并监控 mysqltest:用例在 mysqltest 中执行,worker 线程会监控 mysqltest 的运行状态,监测其是否运行超时或者运行结束。
- 处理执行结果:mysqltest 执行结束会留下执行日志,框架根据执行日志判断执行是否通过,如果没通过是否需要重试等。
以 rpl.rpl_multi_source_basic 测试 case 为例来说明执行过程。
# 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.
启动测试指令 perl mysql-test-run.pl --do-test=rpl_multi_source 后,会启动 3 个 mysqld 进程,其中 2 个 master 节点,1 个 slave 节点:
➜ 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
可见:
- 无论是 mysqldtest 还是 mysqld,都是由 mysqltest_safe_process 程序启动的。
--defaults-group-suffix=.1 到 3分别对应 3 个 mysqld 进程,说明 mtr 不是靠 mock 的形式来测试的,而是启动真 mysqld 进程来测试。
编译安装
安装依赖
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 版本偏低,需要自行通过源码编译安装 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
由于系统及版本差异,这里罗列的软件包可能会有所缺失,版本也可能会有所不同。
对于 mtr 来说,也需要额外安装一些依赖:
# 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 版本编译选项示例:
# 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 版本编译选项示例:
#!/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 选项说明:
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 theWITH_DEBUGoption is enabled. That is,-DWITH_DEBUG=1has the same effect as-DCMAKE_BUILD_TYPE=Debug.
目录结构
编译安装后,mysql-test 目录树结构如下:
mysql-test ├── README ├── README.gcov # 代码覆盖率测试说明,最后更新于2006年 ├── README.stress # 压力测试说明,针对 mysql-stress-test.pl ,最后更新于2006年 ├── collections # 该目录下的文件是官方推荐的回归测试指令集 │ ├── README # 说明文档 │ ├── coverage.ignore # 指定需要忽略代码覆盖率测试的目录 │ ├── disabled.def # 列出需要临时禁用的测试用例,在运行测试时会跳过 │ ├── disabled-asan.list # 除 disabled.def 文件所列用例之外,还需要临时禁用的测试用例 │ ├── disabled-ubsan.list # 同上 │ ├── disabled-valgrind.list # 同上 │ ├── disabled_ndb.def # 仅在运行 MySQL Cluster 时才需要临时禁用的测试用例 # 适合每天都运行的回归测试指令集 # 涵盖 default suites、非 default suites、针对复制和binlog的扩展测试(区分不同的复制参数)、InnoDB 扩展测试(区分不同页面大小) │ ├── default.daily # 由于 valgrind 运行比较耗时,因此,该指令集只能涵盖除 big-test 之外的所有 suites 。 # 需要编译时添加选项 -DWITH_DEBUG=1 -DWITH_VALGRIND=1 的情况下,才能执行 valgrind 测试。 # 注意:通过实测、分析代码,运行 mtr 时必须添加 --valgrind 选项才能用到 valgrind 组件。 │ ├── default.daily-valgrind # 适合每周运行一次的指令集,运行耗时能达到48小时。 # 是 default.daily 的超集,同时,还指定了 --debug-server 。 # 覆盖 default suites + 非 default suites + 复制和binlog的扩展 + InnoDB扩展 + 其他按周运行的指令集。 │ ├── default.weekly │ ├── default.weekly-ndbcluster # 覆盖 default.daily + ndbcluster + 部分非默认指令集 │ ├── default.weekly-protocol # 编译时需要设置 DWITH_TEST_TRACE_PLUGIN=1,只覆盖 main suite。 # 在启用 --big-test 和 --debug-server 选项的前提下,运行所有的指令集。 # 需要编译时添加选项 -DWITH_DEBUG=1 -DWITH_VALGRIND=1 的情况下,才能执行 valgrind 测试。 # 注意:通过实测、分析代码,运行 mtr 时必须添加 --valgrind 选项才能用到 valgrind 组件。 │ ├── default.weekly-valgrind │ ├── default.weekly.basic # 在禁用 --big-test 选项的前提下,运行所有的指令集,即包含 default suites + 非 default suites。 # 适用于每次push代码时运行的指令集,能控制在一个小时内。 # 更适用于 mysql 5.7 版本。 │ ├── default.push │ ├── default.push-ndbcluster # 分为 default suites + 与 ndbcluster 相关的指令集 │ ├── default.push-valgrind # 分为 default suites(排除 rpl)+ ndb 相关 suites + group_replication suite │ ├── mysql-8.0-stage.push # 在 default.push 基础上,为 mysql-8.0-stage 扩展的测试用例,在merge到main分支前使用 │ ├── mysql-8.0-stage.push.basic # mysql-8.0-stage.push 的子集 │ ├── mysql-trunk-meb-itch.push # 文件为空 # default.push 的超集,目的是在 push 到 main 分支前,提前发现问题。 │ ├── mysql-trunk-stage.push # 内容与 mysql-8.0-stage.push 一样,在merge到main分支前使用 │ ├── mysql-trunk-stage.push.basic # mysql-trunk-stage.push 的子集 │ └── mysql-trunk-tsan.push # 由于 ThreadSanitizer 非常慢,因此,只测试 main suite ├── extra # 不属于 main 和 其他 suites 的测试 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 # 测试框架相关依赖文件,里面主要是一些用perl实现的逻辑。 │ ├── My │ │ ├── Config.pm │ │ ├── ConfigFactory.pm ...... │ │ └── Test.pm │ ├── mtr_cases.pm ...... ├── lock_order_dependencies.txt # mysql-test-run.pl 读取该文件来控制加锁顺序,与 --lock-order 选项有关。该文件非空。 # 在 mtr 运行对应工具期间,比如 asan,对应的 .supp 文件用于指定需要跳过的测试用例。 # # ASAN、LSAN、TSAN 出自谷歌的 Sanitizer 项目,包含了 ASAN、LSAN、MSAN、TSAN等内存、线程错误的检测工具。 ├── asan.supp # ASAN(Address-Sanitizier),内存错误检测工具。早期是LLVM中的特性,后被加入GCC 4.8。 ├── lsan.supp # LSAN(LeakSanitizer),内存泄漏检测工具,已集成在 ASAN(AddressSanitizer)中。 ├── tsan.supp # TSAN(ThreadSanitizer),线程间数据竞争的检测工具。 ├── valgrind.supp # Valgrind 是一个工具集。集成了: # Memcheck 内存错误检测器。 # Cachegrind 缓存和分支预测分析器。 # Callgrind 可生成缓存分析器的调用图。 # Helgrind 线程错误检测器。 # DRD 也是线程错误检测器。 # Massif 堆分析器,它可以帮助程序使用更少的内存。 # DHAT 一种不同类型的堆分析器。使用它可以了解块寿命,块利用率和布局效率低下的问题。 ├── 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 入口文件,测试框架核心逻辑 # include/ 目录包含.inc 文件,在测试用例中通过 source 命令引入,就像 C/C++ 的头文件。建议将多次重复使用的测试语句整合到 .inc 文件中。 ├── include # include 下所有 *.inc 都会被 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/ 目录分别对应于 main suite 的测试 case 和 期望结果。 # 测试 case 以 .test 后缀结尾。 # 另外还有 .opt 后缀文件,它里面指定了MySQL的参数。某些测试用例会涉及重启,在重启时可能会变更 mysql 参数,可能会用 .opt 文件中指定的参数。 ├── t # 该目录下的每个 *.test 都对应一个测试 case 。 │ ├── 1st.test │ ├── admin_interface.test ...... ├── r # 路径和命名 与 t/ 目录一一对应,表示对应测试用例的期望输出。 │ ├── 1st.result │ ├── admin_interface.result ...... │ └── year-myisam.result ├── std_data # 测试所用的数据文件,某些测试 case 需要使用到。 │ ├── 14897.frm │ ├── 256kb.json │ ├── 41_decimal.frm │ ├── 57import.zip ...... │ └── x_y_data.csv # 测试框架有 suite 的概念,每个 suite 为一个测试用例集合,默认的 suite 为 main,它的测试集合位于当前目录下的 t/ 目录。 # 除了 main suite 之外,其他的 suite 基本都以子目录的形式存放于当前文件夹,比如 json、binlog 等。 ├── suite # 本目录下每个子目录都包含 include/r/t 三个子目录,其中: # include/*.inc 会被 t/*.test 引用 # t/*.test 是各个测试case的主文件 # r/*.result 是期望的测试输出 # 另外,t/ 与 r/ 路径中的文件是一一对应的。 │ ├── 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 # 测试开启后 mtr 创建的目录,用于存放测试过程产生的数据目录、日志等。 ├── data │ ├── #ib_16384_0.dblwr ...... ...... ├── my.cnf ├── run ├── std_data │ ├── 14897.frm ...... └── tmp └── mysqld.1
参数
参考:
常用参数
--force- 默认情况下,只要遇到一个 case 出错,测试程序就会退出。
- 加入该参数后,mtr 会忽略错误并继续执行下一个 case 直到所有 case 执行结束再退出。
- 但如果脚本存在太多错误还是会退出,可设置
--max-test-fail=0忽略计数。
--max-test-fail- 测试过程中失败 case 数达到一定值会退出,默认值是 10,设置为 0 则会忽略计数。
--record- 是否记录 results 结果,首次执行建议带上,让其自动生成
.results文件,再基于该文件修改成我们预期的结果。 - 若一个执行输出结果和
testname.result文件不同,会生成一个testname.reject文件,该文件在下次执行成功之后被删除; - 检查
.reject文件的内容,如果里面是期望的输出,则将内容拷贝到.result文件中,作为以后判断运行结果是否通过的依据;
- 是否记录 results 结果,首次执行建议带上,让其自动生成
--parallel- 指定运行测试 case 的并行线程数。
—-nowarnings- 忽略 warnings 错误。
- 设置该参数后,当出现 warnings 错误,不再累加
--max-test-fail。
--big-test- 执行标记为
big的 test cases,也就是同时覆盖 非 big + big。这是因为标记为 big 的 case 较大、耗时较长,默认不会执行。
- 执行标记为
--only-big-test:只启用带 big 标记的 test cases,也就是会跳过普通的非 big 标记的 cases。--suite=[suitename1,...]- 默认情况下 mtr 会执行所有测试 case,但有时候我们要执行一个测试集,就可用该参数来指定,比如
./mtr --suite=rpl只执行 rpl 测试集。
- 默认情况下 mtr 会执行所有测试 case,但有时候我们要执行一个测试集,就可用该参数来指定,比如
--do-test=events- 执行所有以
events为前缀的 case(搜索范围为 t/和所有的 suite)。 --do-test的参数支持正则表达式,上述命令等效于./mtr --do-test=events.*- 所以如果想测试所有的包括 innodb 的 case,可以用
./mtr --do-test=.*innodb.*
- 执行所有以
- 连接远程的数据库进行 mtr 执行:
# --extern 一般情况下mtr是启动自己的MySQL服务来进行测试,如果在启动时指定参数 --extern,则可以使用指定的 MySQL 服务进行测试 ./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:用于指定或排除平台的选项。- 如果 MTR 不是运行在 pushbuild test 环境中(存在环境变量
PB2WORKDIR,即export PB2WORKDIR=),这两个选项是不生效的。
- 如果 MTR 不是运行在 pushbuild test 环境中(存在环境变量
comment=STR:添加该选项后,mtr 会将注释信息打印到 stdout 。比如--comment=all-default-big:
############################################################################## # all-default-big ##############################################################################
--vardir=DIR:指定测试过程中生成的文件存放的目录,默认是当前路径下的var/。--report-features:指定该选项后,mtr 首先运行名为report_features的 case,该 case 没有任何输出(设置了--disable_query_log) 。--unit-tests-report:加上该参数后,如果在编译后的源码目录执行 mtr,会在测试的最后阶段加上每个测试用例的报告信息。
...... [----------] 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:指定该选项后,即使.inc文件中要求的条件不满足,也会运行所有的 mtr 测试 cases 。特别地,在include/excludenoskip.list文件中指定的.inc文件列表依然会跳过。--skip-ndb:与选项--skip-ndbcluster含义相同,表示跳过与 ndb 相关的 suites,默认启用。- ndb 引擎也是开源的(
storage/ndb/),涉及 ndb 引擎的 suites 包括:
- ndb 引擎也是开源的(
- ndb - ndb_big - ndb_opt - ndb_ddl - ndb_binlog - ndb_rpl - rpl_ndb - ndbcluster - gcol_ndb - json_ndb
--with-ndb-only:与选项--with-ndbcluster-only含义相同,只运行与 ndb 相关的 suites 。如果没显示指定--suites参数,则会跳过所有非 ndb 的 suites ;反之,若指定了,也会额外运行指定的 suites 。--ps-protocol:在 client 和 server 端之间使用 prepared-statement 协议(binary),会将--ps-protocol参数直接传给 mysqltest 程序。--skip-combinations:忽略组合文件或选项,也就是忽略:
# 启动 mtr 时的日志: 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 # 对应于 ./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, # 额外功能(包括视图、存储过程、INFORMATION_SCHEMA等) funcs_2, # 额外功能(字符集等) gcol, # 虚拟生成列 gis, group_replication, information_schema, innodb, innodb_fts, # 全文索引 innodb_gis, innodb_stress, innodb_undo, innodb_zip, interactive_utilities, jp, # 日语字符集 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 分类
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 执行路径:
- 代码覆盖率、单元测试只能在
编译的源码目录/mysql-test执行。 - 其他测试在
编译的源码目录/mysql-test和安装目录/mysql-test都可以执行。 - 如无特殊需求,更建议在安装目录执行 mtr 测试(目录结构更清晰)。
常用指令:
- 在未编写
.result文件的情况下,可先通过--reocrd选项生成.result文件,再基于该文件修改成期望的结果:
perl mysql-test-run.pl --record mytest
- 常态下执行,不加
--reocrd选项,这样才会比对实际结果与期望结果是否相同:
perl mysql-test-run.pl mytestcase1 perl mysql-test-run.pl --suites=main,rpl # 指定多个 suites
- 当一些测试 case 频繁失败时,可单独运行这些 case 以便调试:
./mtr testcasename --record # 只运行基础套餐里的 subquery_all 用例( t/subquery_all.test ) # 可选 --charset-for-testdb=utf8mb4 ./mtr --force --big-test --nowarnings --max-test-fail=0 main.subquery_all # 如需执行多个 case,可通过空格分割,比如: ./mtr --force --big-test --nowarnings --max-test-fail=0 main.subquery_all main.myisam_explain_json_non_select_none
- 如果不指定任何 suite,mtr 默认会执行所有 default suites(包括 main):
./mtr --force
- 执行 main suite 中的所有 case(所有
mysql-test/t/*.test),忽略中间的 warnings 报错,强制运行完所有 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
- 执行所有以
events为前缀的 case,搜索范围为mysql-test/t、mysql-test/suite,注意不包括extra/:
# --do-test 参数支持正则表达式,该指令等效于./mtr --do-test=events.* ./mtr --do-test=events --force --max-test-fail=0 # 如果想测试所有包含 innodb 的 case,可以用 ./mtr --do-test=.*innodb.*
特殊用法:
-
1、准备数据库:
create database test。-
a)执行
./mtr --extern host=127.0.0.1 --extern port=3306 --extern user=root --extern password= --force --max-test-fail=0 --suite=main,第一个非 skipped case 可以执行成功,但之后的 case 全部失败。 -
b)分析原因,发现是每执行完一个 case ,mtr 就会 shutdown mysqld server,下一个 case 再启动,而这里是使用的外部 mysql,则不会启动。
-
-
2、查看手册,发现有一个参数可以控制是否每个 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、添加后,虽然不重启了,但会导致一些 case 失败。 这是因为有些 case 需要初始化一些参数:
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.
可见,官方对这种用法的支持尚不完善。
推荐用法
如果需要验证 release 版本稳定性(适用于 QA、研发),可参考 default.daily 中的指令集。
- 该指令集覆盖了单元测试(必须以 DEBUG 编译)、压力测试等。
如何添加测试用例?
1. 示例一
我们通过一个最简单的例子来说明这个框架是怎么使用的。
1.1. 创建测试用例
在 mysql-test/t 目录下创建一个文件名为 mytest.test 的测试用例:
--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 目录下创建名为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;
可见,.result 文件中不仅要记录 SQL,还要记录输出结果。
1.2. 执行测试,成功
指令:
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 说明执行成功。
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. 再次执行测试,失败
再次执行指令./mtr main.mytest ,可见# new comment 那一行报错:
============================================================================== 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 会指出具体是哪行导致的 case 失败。
常见问题 FAQ
test case failed 原因
- 产生的测试结果文件与预期输出文件 diff 结果不一致:
- 期望输入的 SQL 执行成功,实际执行失败。
- 期望输入的 SQL 执行失败,实际执行成功。
- 比如:
mysql-test/t/select_all.test这个测试 case,其预期结果在mysql-test/r/select_all.result,在实际执行时,会将执行结果与mysql-test/r/select_all.result作比较,若不一致,则失败,并在mysql-test/var/log目录生成一个.reject文件。
- 测试过程中 mysql server 挂掉。这种情况一般会报“丢失连接”的错误。
- 测试期间 MySQL Server 端写入了未过滤的 warnings 或 errors 日志。
此外,测试用例可以执行外部程序,因此在某些方面,测试框架可以扩展为测试 SQL 语句以外的用途。
最后,可以在测试中嵌入一小段 Perl 代码。这有时可用于执行超出测试语言或 SQL 能力的操作或执行逻辑。
可使用一些技巧来定为具体的错误原因,详见下节。
异常调试
分析日志
默认情况下,在目录 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 参数和 gdb 参数
mtr 支持的一些 debug 参数:
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.
可见,要想跟踪调用过程,只有 --debug 和 --gdb 参数满足要求,会生成 trace 信息。
示例:
# 这几条指令很耗费内存 ./mtr --debug --suite=rpl ./mtr --gdb --suite=rpl ./mtr --debug --gdb --suite=rpl
指令执行后,生成 trace 文件,比如 var/log/bootstrap.trace 。
脚本自身支持 debug 参数
如果引用(source)的脚本支持 debug 参数,比如常用的 $rpl_debug,则可以修改相应的 .inc 文件以获得更多的 debug 信息。
perl 的调试模式
添加-d 参数可进入 perl 语言的 debug 模式,便于调试 mysql-test-run.pl 及其调用。示例:
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 退出
欢迎关注我的微信公众号【数据库内核】:分享主流开源数据库和存储引擎相关技术。
| 标题 | 网址 |
|---|---|
| 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 |