TH3
TH3
1.概述
1.1.历史
2.操作
3.生成测试程序
3.1.测试自动化脚本
4.测试覆盖率
5.突变测试
6. TH3许可证
1.概述
SQLite Test Harness#3(以下简称“TH3”)是用于测试SQLite的三个测试工具之一。TH3符合以下目标:
- TH3能够在缺乏工作站支持基础设施的嵌入式平台上运行。
TH3最初只用于验证测试,但后来也被用于开发测试和调试,并已证明在这些角色中非常有用。全面覆盖测试在工作站上不到五分钟,因此在SQLite代码库的日常维护期间可用作快速回归测试。
1.1.历史
TH3起源于在SymbianOS上测试SQLite的努力。在TH3之前,所有的SQLite测试都是使用TCL脚本语言来运行的,但是TCL在SymbianOS上不会(很容易)编译,这使得测试变得困难。解决这个问题的第一个尝试是“TH1”(测试用例#1)脚本语言 - 以可移植的形式重新实现TCL语言的一部分,可以在SymbianOS上编译和运行,这足以运行SQLite试验。TH1没有成为SQLite的标准测试工具,但它确实发现了继续服务作为用于定制化石的脚本语言版本控制系统。还有一个“Test Harness#2”,它试图用运算符前缀符号创建一个简单的脚本语言来驱动测试。TH3是第三次尝试。
与此同时,一些航空电子设备制造商对SQLite表示了兴趣,这促使SQLite开发人员设计TH3以支持DO-178B的严格测试标准。
The first code for TH3 was laid down on 2008-09-25. An intense effort over the next 10 months resulted in TH3 achieving 100% MC/DC on 2009-07-25. The TH3 code continues to be improved and expanded.
截至2016年8月29日,TH3源码树在1582个独立文件中包含超过500,000行源代码。
2.操作
TH3是一个测试程序生成器。TH3的输出是一个用C代码实现的程序,旨在与被测试的SQLite库链接。生成的测试程序在目标平台上编译并运行,以验证该平台上SQLite的正确运行。
TH3的输入是用C或SQL编写的测试模块以及确定如何初始化SQLite的小配置文件。TH3套件包含1300多个测试模块和40多个配置(截至2016-08-29)。可以添加新的模块和配置来为特定应用程序定制TH3。每次TH3运行时,它都会读取可用测试模块和配置文件的一个子集,以生成自定义C程序,该程序可在所有指定配置下执行所有指定的测试。对SQLite的完整测试通常包括多次运行TH3以生成覆盖SQLite操作各个方面的多个测试程序,然后将所有测试程序与普通SQLite库链接起来,并在目标平台上单独运行它们。
TH3没有任何限制。可以生成包含所有测试模块和所有配置文件的单个测试程序。但是,这样的测试程序可能太大而无法在嵌入式平台上部署。(截至2016年8月29日,完整的TH3测试超过820,000行和55MB的C代码。)TH3提供了将测试模块库分成更小,更容易消化的部分的功能。
每个单独的测试模块可能包含数十,数百或数千个单独的测试。测试模块可以用C语言编写,也可以作为SQL脚本或两者的混合文件。大约三分之二的现有测试模块都是用SQL编写的,剩下的则是纯C或C和SQL的组合。
每个测试模块文件都包含一个描述测试有效的情况的头文件。对于特定的配置,只有那些与配置兼容的模块才能运行。
3.生成测试程序
TH3程序生成器是名为“ mkth3.tcl
” 的TCL脚本。要生成测试程序,只需运行此脚本并在命令行中提供包含测试模块和配置的文件的名称。测试模块是使用“ .test
”后缀的文件,配置是使用.cfg
后缀的文件。“ 典型的mkth3.tcl
调用可能如下所示:
tclsh mkth3.tcl *.test *.cfg >testprog1.c
mkth3.tcl脚本的输出是一个C程序,其中包含运行测试所需的所有内容 - 除了SQLite库本身之外的所有内容。生成的测试程序包含测试模块使用的所有支持接口的实现,并包含main()
驱动测试的例程。要将测试程序转换为可执行的工作文件,只需按照SQLite进行编译即可:
cc -o testprog1 testprog1.c sqlite3.c
上面显示的汇编步骤仅仅是代表性的。在工作安装中,通常需要在编译器命令行上指定优化参数和编译时开关。
为了在嵌入式系统上进行测试,上面显示的mkth3.tcl脚本和编译器步骤在使用交叉编译器的普通工作站上执行,然后将生成的测试程序传输到要运行的设备上。
一旦生成测试程序,它将在没有参数的情况下运行以执行测试。标准输出中会显示进度信息和错误诊断信息。(对于缺乏标准输出通道的嵌入式设备,可以使用编译时选项进行替代输出安排。)如果没有错误,程序返回零,如果发现任何问题,则返回非零值。
单个TH3测试程序运行的典型输出如下所示:
With SQLite 3.8.11 2015-05-15 04:13:15 56ef98a04765c34c1c2f3ed7a6f03a732f3b886e
-DSQLITE_COVERAGE_TEST
-DSQLITE_NO_SYNC
-DSQLITE_SYSTEM_MALLOC
-DSQLITE_THREADSAFE=1
Config-begin c1.
Begin c1.pager08
End c1.pager08
Begin c1.build33
End c1.build33
Begin c1.orderby01
End c1.orderby01
... 15014 lines of output omitted ....
Begin 64k.syscall01
End 64k.syscall01
Begin 64k.build01
End 64k.build01
Begin 64k.auth01
End 64k.auth01
Config-end 64k. TH3 memory used: 6373738
Config-begin wal1.
Begin wal1.wal37
End wal1.wal37
Config-end wal1. TH3 memory used: 100961
All 226 VDBE coverage points reached
th3: 0 errors out of 1442264 tests in 213.741 seconds. 64-bit little-endian
th3: SQLite 3.8.11 2015-05-15 04:13:15 56ef98a04765c34c1c2f3ed7a6f03a732f3b886e
输出以SQLITE_SOURCE_ID报告开始(对sqlite3_sourceid()再次进行交叉检查),以及sqlite3_compileoption_get()报告的编译时选项。输出以测试结果摘要和SQLITE_SOURCE_ID的重复结束。如果检测到任何错误,则附加行会详细说明问题。错误报告行始终以单个空格字符开头,以便可以使用以下命令从大型输出文件中快速提取它们:
grep "^ "
默认输出显示每个配置和测试模块组合的开始和结束。在上面的例子中,“c1”和“64k”是配置,“pager08”,“build33”,“orderby01”等是测试模块。编译时和运行时选项可用于增加或减少输出量。通过显示每个测试模块中的每个测试用例可以增加输出。输出可以逐步降低:省略测试模块启动和停止,省略配置启动和停止,最后省略所有输出。
3.1.测试自动化脚本
TH3附带了额外的TCL脚本,可帮助自动化工作站上的测试过程。“th3make”脚本自动运行“mkth3.tcl”和“gcc”,然后运行生成的测试程序并检查结果。th3make的参数包括所有要包含在测试中的“* .test”测试模块和“* .cfg”配置。th3make的其他选项可以使用不同的编译器(GCC,Clang,MSVC)编译测试程序,使用不同的输出详细级别,在valgrind下运行测试程序,使用gcov检查输出是否覆盖等等。th3make脚本还接受“* .rc”文件名作为参数。这些* .rc文件只是为了一个目的而共同使用的其他参数的集合。例如,“quick.rc”文件包含th3make的一组八个参数,它们运行一个快速(3分钟)的全覆盖测试。这允许操作员键入“./th3make quick.rc”作为输入所有必需的命令行选项的捷径。以下是超过40个可用的* .rc文件中的一部分:
alignment
N
.rc
- 这些文件包含由各种值得注意的下游使用的编译器的-D选项。
TH3存储库还包含“multitest.tcl”脚本,这是另一个用于在工作站上自动执行TH3测试的TCL脚本。Multitest.tcl会自动编译SQLite,然后用各种路线反复运行./th3make,并在简洁的摘要屏幕中捕获输出。典型的multitest.tcl运行生成如下所示的输出:
file mkdir sqlite3bld
cd sqlite3bld
exec sh /home/drh/sqlite/sqlite/configure
file copy -force config.h ../config.h
exec make clean sqlite3.c
file rename sqlite3.c ../sqlite3.c
aa4f0f90c9c77424943e026a2ecee4a6c7f9e0d3 ../sqlite3.c
file rename sqlite3.h ../sqlite3.h
exec make clean sqlite3.c OPTS=-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
file rename sqlite3.c ../sqlite3udl.c
0d3bbc92c433f940253bb2c7c19de7783133929d ../sqlite3udl.c
exec make clean sqlite3.c OPTS=-DSQLITE_SMALL_STACK=1
file rename sqlite3.c ../sqlite3ss.c
fcf6963e94096324461076d3b9e9dc1888e066e1 ../sqlite3ss.c
cd ..
*******************************************************************************
t03: demo.rc................................................... Ok (00:00:05)
t01: quick.rc.................................................. Ok (00:03:44)
t02: cov.rc.................................................... Ok (00:03:58)
t04: quick.rc extensions.rc -D_HAVE_SQLITE_CONFIG_H............ Ok (00:05:25)
t08: vfs-cov.rc................................................ Ok (00:03:35)
t05: cov.rc -DSQLITE_ENABLE_STAT4 -D_HAVE_SQLITE_CONFIG_H...... Ok (00:04:40)
t09: quick.rc -DSQLITE_TEST_REALLOC_STRESS -funsigned-char..... Ok (00:04:25)
t10: quick.rc -DSQLITE_THREADSAFE=0 -DLONGDOUBLE_TYPE=double... Ok (00:03:00)
t11: quick.rc sqlite3ss.c -DSQLITE_MAX_ATTACHED=125............ Ok (00:03:45)
t14: quick.rc -DSQLITE_TRACE_SIZE_LIMIT=15 cov1/main16.test.... Ok (00:00:17)
t12: quick.rc -DSQLITE_RUNTIME_BYTEORDER -fsigned-char......... Ok (00:03:46)
t13: quick.rc -DSQLITE_DIRECT_OVERFLOW_READ.................... Ok (00:03:42)
t16: test.rc alignment2.rc sqlite3udl.c........................ Ok (00:35:25)
t15: test.rc alignment1.rc..................................... Ok (00:48:20)
t19: valgrind1.rc -O3 extensions.rc............................ Ok (00:33:14)
t17: memdebug1.rc extensions.rc................................ Ok (01:23:44)
t18: memdebug2.rc extensions.rc................................ Ok (01:23:13)
t20: valgrind2.rc -O3 extensions.rc............................ Ok (00:40:21)
t21: test-ex1.rc............................................... Ok (00:40:37)
t23: test-ex3.rc............................................... Ok (00:29:04)
t22: test-ex2.rc............................................... Ok (00:53:28)
t24: test-ex4.rc............................................... Ok (00:47:59)
t26: test.rc alignment4.rc -m32 CC=clang....................... Ok (00:37:38)
t25: test.rc alignment3.rc sqlite3udl.c........................ Ok (01:04:01)
t27: test.rc alignment5.rc extensions.rc....................... Ok (00:44:58)
t28: test.rc alignment6.rc..................................... Ok (00:28:49)
t32: fast.rc alignment1.rc extensions.rc -m32.................. Ok (00:30:05)
t29: test.rc alignment7.rc..................................... Ok (00:34:17)
t33: fast.rc alignment2.rc sqlite3udl.c........................ Ok (00:13:51)
t35: fast.rc alignment4.rc..................................... Ok (00:11:08)
t36: fast.rc alignment5.rc..................................... Ok (00:12:31)
t37: fast.rc alignment6.rc..................................... Ok (00:11:15)
t34: fast.rc alignment3.rc sqlite3udl.c........................ Ok (00:23:05)
t38: fast.rc alignment7.rc..................................... Ok (00:12:26)
t39: fast.rc -fsanitize=undefined.............................. Ok (00:24:15)
*******************************************************************************
0 failures on 35 th3makes and 171555634 tests in (05:08:31) 3 cores on bella
SQLite 3.14.1 2016-08-11 13:08:14 34aed3a318a413fd180604365546c1f530d1c60c
从上面可以看出,一次multitest.tcl运行会调用th3几十次或几次,并且需要12到24个CPU小时。输出的中间部分显示每个th3make运行的参数以及该th3make的结果和经过时间。所有为单独的th3make运行构建产品和输出都在子目录中进行捕获,以便进行后期测试分析。底部的两行总结显示了所有th3make运行的错误和测试总数,以及总测试时间,以及经过测试的SQLite版本的SQLITE_SOURCE_ID信息。在最终测试期间,此摘要信息记录在发布核对表中。
4.测试覆盖率
使用可用TH3测试模块的特定子集(“cov1”测试),SQLite 在Linux x86和x86_64硬件上通过gcov测量得到100%分支测试覆盖率和100%MC / DC 。从版本3.6.17(2009-08-10)开始,所有SQLite 版本都已经过测试。SQLite开发人员致力于为所有未来版本的SQLite维护100%分支机构覆盖率和MC / DC。
用于获得100%分支测试覆盖率的cov1测试集只是当前使用TH3实施的测试的一个子集。定期添加新的测试模块。
5.突变测试
TH3源代码树包含一个脚本名称“mutation-test.tcl”,用于自动化变异测试过程。
mutation-test.tcl脚本负责运行突变测试的所有细节:
- 如果需要,该脚本将TH3测试工具编译为机器代码(“th3.o”)。
突变测试可能会很慢,因为每个测试在快速工作站上最多需要5分钟,并且每个分支指令有两个测试,并且有超过20,000个分支指令。努力加快运作。例如,TH3的编译方式是一找到第一个错误就立即存在,而且很容易检测到许多突变,很多循环在几秒钟内就会发生。然而,mutation-test.tcl脚本包含命令行选项,以限制测试代码行的范围,以便只需对最近更改的代码块执行变异测试。
6. TH3许可证
SQLite本身处于公有领域,可用于任何目的。但TH3是专有的,需要许可证。
尽管开源用户没有直接访问TH3的能力,但SQLite的所有用户都会间接受益于TH3,因为每个版本的SQLite都经过验证,在发布之前在多个平台(Linux,Windows,WinRT,Mac,OpenBSD)上运行TH3。因此,任何使用SQLite正式版本的人都可以在知道已经使用TH3进行测试的情况下部署其应用程序。如果不购买TH3许可证,他们根本无法重新运行这些测试。
SQLite在公共领域。