暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

海山数据库(He3DB)源码详解:海山Mysql 自动测试框架MTR

cxp 2025-01-23
18

海山数据库(He3DB)源码详解:海山Mysql 自动测试框架MTR

一、MySQL自动测试框架原理

1、简介

在修改内核代码后,不仅需要测试新增功能,同时也要对原有功能做回归测试,以保证新加代码对原有功能没有影响,这就需要用到MySQL源码自带的测试框架MySQL Test Framework,简称MTR

Test Framework主要应用于MySQL等相关数据库项目开发测试,对单个功能点或者模块进行正确性和功能性测试,该工具在SQL级别对MySQL进行单元测试。Test Framework不仅仅能测试SQL语句,也能根据实际需要测试不同启动参数配置的MySQL服务器和客户端从而验证指定的功能逻辑。

2、原理实现

  • 操作步骤:
    (1)初始化参数
    (2)收集测试用例
    (3)初始化服务器
    (4)运行工作子进程
    (5)结果信息的输出保存

在这里插入图片描述

Test Framework需要初始化参数、收集测试用例、初始化服务器、运行工作子进程、结果信息的输出保存等步骤。接下来重点分析:
1)初始化服务器(initialize_servers()
 在设置读取到的命令行的选项参数(command_line_setup())以及收集完本次所需的测试用例文件(collect_test_cases())后,需要初始化mysqld服务器。
 首先创建var目录,var目录保存MySQL数据文件、日志信息、临时文件,运行期间产生的临时文件会在成功执行后删除。之后运行mysql_install_db()进行服务器的初始化。
2)运行工作子进程(run_worker()
 通过_safe_fork()创建子进程,主进程在初始化套接字后,根据并行数parallel(默认为1)启动一个或多个子进程用于执行测试用例。在子进程run_worker()中循环监听主进程发送的消息,如果接收到‘TESTCASE’类型消息,则执行测试用例run_testcase()
 在执行真正的测试用例文件之前,Test Framework会进行第一次check_testcase(),mode=”before”,并在结束后再执行一次check_testcase(),mode=”after”,每次执行都是调用mysqltest执行一遍check_testcase.test测试用例文件,并将结果保存。执行两次的目的是,检查对比前后执行的结果,防止执行真正的测试用例改变服务器中的数据,保证前后数据的一致性。
check_warnings()检查服务器的输出日志是否存在可疑的日志消息。Test Framework明确100多种通用的需要抑制的警告或者错误信息,其他的输出信息会被当做可疑日志信息,保存在后缀为.warnings的文件中。
3)主进程接收子进程的执行结果(run_test_server()
 启动的run_worker与主线程之间是server-client模式,主线程是serverrun_worker()client
 主线程与run_worker是一问一答模式,主线程向run_worker发送运行用例的文件路径、配置文件参数等各种参数信息,run_worker向主线程返回运行结果,直到所有在collection中的用例都运行完毕,主线程closerun_worker,进行收尾工作。
 主线程先读取各run_worker返回值,对上一个用例进行收尾工作。之后,读取collection中的用例,通过本地socket发送到run_worker线程,run_worker线程接收到主线程命令,运行本次用例执行函数run_testcase(),而run_testcase()主要负责3件事:启动mysqld、启动并监控mysqltest,处理执行结果。

  • 整体流程

-启动mysqld:根据参数启动一个或者多个mysqldstart_servers()),在start_servers大多数情况下会拷贝主线程初始化后的目录到run_worker的目录,作为新实例的启动目录,用shell 命令启动数据库。
-启动并监控mysqltest:用例在mysqltest中执行(会逐行扫描*.test文件中的 SQL 或指令并于MySQL中执行),run_worker线程会监控mysqltest的运行状态,监测其是否运行超时或者运行结束。
-处理执行结果:mysqltest执行结束会留下执行日志,框架根据执行日志判断执行是否通过,如果没通过是否需要重试等。

3、MySQLNCNDB自动测试框架区别

在这里插入图片描述

MySQL自动测试框架

在这里插入图片描述

NCNDB自动测试框架

两者的区别见图中红色框处。

二、使用MTR

1、mtr相关文件

MySQL测试框架是一个以MySQL框架和内部引擎为测试对象的工具,主要执行脚本在安装路径下的mysql-test目录,基本覆盖了所有MySQL的特性和异常情况。
在这里插入图片描述

它的位置在MySQL源码同级的目录./mysql-test下,使用perl脚本编写。
mysql-test-run.pl:perl脚本,是MySQL最常用的测试工具,负责控制流程,包括启停、识别执行哪些用例、创建文件夹、收集结果等等,主要作用是验证SQL语句在各种场景下是否返回正确的结果。
mysql-stress-test.pl:perl脚本,用于MySQL Server的压力测试。
mysql-test/目录下还有其他目录,列出其中几个常用的目录:
collections:包含在集成和发布测试期间运行的测试运行的集合
include目录:一些头文件,这些文件在*.test文件中调用,使用source命令引入;
lib目录:是一些库函数,主要被perl脚本调用;
std_data目录:一些标准数据,某些测试用例可以直接拷贝使用即可。
suite目录:保存套装组件的测试用例,方便测试同一类测试用例。
extra目录:一些binlogreplication测试相关的文件。
t目录:默认main套件测试用例
r目录:默认main套件测试用例结果文件\

2、测试用例与预期结果文件

Test Framework通过执行一个测试用例文件,将该测试用例的实际测试结果,与预期结果文件作对比。如果一致,则认为测试通过,无问题;否则,不一致,则测试失败,可以根据输出结果查找问题。
 测试用例的输入存储在一个文件中,运行测试的预期结果存储在另一个文件中。测试用例文件主要由SQL语句和命令组成,也可以使用测试语言结构来控制如何运行测试和验证它们的结果。测试用例文件统一放在t/文件夹下,文件名以.test为后缀。测试用例文件支持脚本语言函数。预期结果文件与测试用例文件的大部分代码几乎一致,只是在文件中增加了输出结果。在有输出结果的语句后面(如查询语句select),还将输出结果写在预期结果文件中。预期结果文件统一放在r/文件夹下,文件名以.result为后缀。
 测试用例文件应与预期结果文件同名,仅以后缀区分是测试用例文件还是预期结果文件,使用时加不加.test后缀执行都可以。

3、mysqltest编写语法

MySQL:mysqltest 命令

语法 功能
–echo xxxxx 输出信息xxxxx
–source xxx.inc 等效于将目标文件的内容拷贝到当前位置
–error N 测试出错语句。N为错误号或者宏,指定下一个命令预期返回的一个或多个逗号分隔的error 值。
–send 向server发送一条query,但并不等待结果,而是立即返回,该query的结果必须由 reap 指令来接收。
–require 条件要求,需要满足某个条件
connect (name, host_name, user_name, password, db_name [,port_num [,socket [,options [,default_auth [,compression algorithm, [,compression level]]]]]]) 创建一个到mysql server的新连接并作为当前连接
connection connection_name 选择 connection_name作为当前连接。
disconnect connection_name 关闭连接connection_name
–enable_query_log 记录sql语句以及输出结果
–disable_query_log 不想记录某些sql语句及结果
–exec command [arg] 执行shell命令
–shutdown_server [timeout] 停止服务器。如果服务器的进程 ID 文件在超时秒后仍未消失,则该进程将被终止。
dec $var_name 递减数值变量
inc $var_name 递增数值变量
–exit 终止测试用例
–expr 计算表达式并将结果分配给变量(不支持非整数计算)
–let 为变量赋值;设置环境变量
–lowercase_result 将SQL语句的输出转换为小写
output file_name 将下一个SQL语句的输出直接输出到命名文件
perl [terminator] 使用Perl执行测试文件的以下行。当遇到包含终止符的行时,这些行结束。默认终止符为 EOF,但可以提供不同的终止符。
query [statement] 将语句发送到服务器执行。
query_get_value(query, col_name, row_num) 只能在 let 语句中变量分配的右侧使用。第一个参数指示要执行的查询。第二个和第三个参数指示列名和行号,用于指定要从结果集中提取的值。
–send_eval 评估命令,然后将其发送到服务器。
–sleep num 睡眠 (sleep num seconds)
if (expr) { command list} /
while (expr) { command list} /
call mtr.add_suppression(“xxxxx”);
call mtr.add_suppression_for_se(“xxxxx”);
抑制规则,抑制错误和警告,用于在测试输出中忽略特定的错误或失败情况。
add_suppression: 用于屏蔽计算节点错误信息
add_suppression_for_se:用于屏蔽存储节点日志中可能出现的预期内报错信息

3.1 关闭和重启服务器

(1)在启动或停止服务器的操作之前,测试用例应将 restart 或 wait 写入.expect文件。

测试用例 语法解析
–exec echo “wait” > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
–shutdown_server 10
–source include/wait_until_disconnected.inc
# Do something while server is down
–exec echo “restart” > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
–source include/wait_until_connected_again.inc
restart:服务器将立即重新启动
wait:服务器将保持关闭状态,在以后通过将 restart 写入文件来重新启动。

(2)关闭和重启的文件

  • restart_mysqld.inc : 重启服务器,可以使用$shutdown_server_timeout设置关闭超时值
测试用例
# Restart server with extra parameters
–let $shutdown_server_timeout= 10
–let $restart_parameters= “restart: --innodb_autoinc_lock_mode=1”
–source include/restart_mysqld.inc
  • kill_and_restart_mysqld.inc: 关闭后立即重启服务器
测试用例
# Restart server with extra parameters
–let $restart_paramters= “restart: --innodb_autoinc_lock_mode=0”
–source include/kill_and_restart_mysqld.inc
  • shutdown_mysqld.inc and start_mysqld.inc: 分别用于关闭和启动服务器
测试用例
# Timeout of 10 seconds
–let $shutdown_server_timeout= 10
–source include/shutdown_mysqld.inc
# Do something while the server is down
–source include/start_mysqld.inc
  • kill_mysqld.inc:设置 shutdown timeout的值将不起作用
  • wait_until_disconnected.inc:断开与服务器的所有连接
  • wait_until_connected_again.inc:在服务器再次启动后使用,以确保恢复客户端连接。它会尝试建立连接,直到发生超时。
    (3)NCNDB新增有关重启服务器的文件
  • c.inc:重启第一个se
  • kill_first_se:关闭第一个se
  • restart_ce_mysqld.inc:重启ce

4、mtr执行命令

mysql-test-runmysql-test-run.plmtr三个文件一模一样,选择任一文件来执行即可,如./mtrmtr实际上是调用的mysqltest来进行测试的。
MySQL: mysqltest — 运行测试用例的程序
MySQL: mysql-test-run.pl — 运行 MySQL 测试套件

参数名称 描述
[什么参数都不加] 执行t/目录和suits/目录下所有以.test为后缀的测试用例文件(测试时间较长),并且,任何一个测试用例执行失败都导致整个执行计划推出。
–do-test=events 执行所有以events为前缀的测试用例文件(搜索范围为t/和所有的suite)
如果想测试所有的包括innodb的case,可以用 ./mtr –do-test=.innodb.
–skip-test=events 将以events开头的所有测试用例跳过,支持正则表达式。
–vardir mtr允许并行执行,需要特别指定不同的日志目录。
–suite=suite_name suits目录下有多个目录,是一些测试的套餐。此命令单独执行suits/suite_name目录下的所有测试用例文件(其他的目录不执行)。
t/目录下的所有文件组成了默认的套餐main。 因此 ./mtr --suite=main则只执行t/*.test
–force 忽略错误并继续执行直到所有的测试用例执行结束。
–parallel=auto 以多线程执行测试用例
–record 生成.result文件。将.test的实际测试结果.reject作为预期结果.result
–result-file=file_name 此选项指定测试用例预期结果的文件。-- result-file与-- record一起决定了mysqltest如何处理测试用例的测试实际结果和预期结果。
–manual-gdb 以debug模式启动mysqld,适合单个用例。这样的好处是,如果挂了,gdb中会存在相应的堆栈。

5、执行结果

5.1 测试执行成功

在这里插入图片描述

5.2 测试执行失败

在这里插入图片描述

5.3 失败原因

(1)产生的测试结果文件与预期输出文件结果不一致:期望输入的 SQL 执行成功,实际执行失败;期望输入的 SQL 执行失败,实际执行成功。在实际执行时,会将执行结果与.result文件作比较,若不一致,则失败,并在mysql-test/var/log目录生成一个.reject文件。
(2)测试过程中mysql server挂掉。这种情况一般会报“丢失连接”的错误。
(3)测试期间MySQL Server端写入了未过滤的warningserrors日志。

5.4 异常调试

(1)分析日志
 测试过程生成的所有数据都保存在var/目录下,其中var/install.db/目录在首次初始化后生成,后续直接拷贝给后续服务器的启动使用。var/log/目录下保存本次执行的日志文件,包括错误信息、警告信息、初始化过程的参数、执行的测试用例名以及执行时间文件。var/tmp/目录保存执行SQL语句的通过情况,包括两次check-testcasecheck-warnings过程。var/mysqld.1/目录保存本次执行生成的数据文件。var/my.cnf是执行测试用例的配置文件。
(2)verbose参数
启动 mtr 时加 --verbose 参数,打印脚本执行信息
(3)--debug 参数和 --gdb参数
(4)perl的调试
 添加-d 参数可进入 perl 语言的 debug 模式

  • 调试模式常用命令:
命令 功能
h 查看帮助文档
c line 运行到指定行
n 运行到下一行
s 跳到函数内部运行
l 查看代码
q 查看代码

命令 功能
h 查看帮助文档
c line 运行到指定行
n 运行到下一行
s 跳到函数内部运行
l 查看代码
q 查看代码
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论