Small. Fast. Reliable.
Choose any three.
TH3

1.概述

SQLite测试工具#3(以下称“ TH3”)是用于测试SQLite的三个测试工具之一 。TH3满足以下目标:

TH3最初仅用于验证测试,但后来也用于开发测试和调试,并被证明在这些角色中非常有帮助。全覆盖测试在工作站上花费的时间不到5分钟,因此可以在SQLite代码库的日常维护过程中用作快速回归测试。

1.1。历史

TH3源于在SymbianOS上测试SQLite的努力 。在TH3之前,所有SQLite测试都是使用TCL脚本语言运行的 ,但是TCL无法(轻松地)在SymbianOS上编译,这使测试变得困难。解决此问题的第一个尝试是使用“ TH1”(测试线束#1)脚本语言-以更可移植的形式重新实现TCL语言的某些部分,这些部分将在SymbianOS上编译并运行,并且足以运行SQLite。测试。TH1不能作为SQLite的标准测试工具幸免于难,但它确实找到了持续服务作为用于自定义Fossil的脚本语言。 版本控制系统。还有一个“ Test Harness#2”,它试图使用运算符前缀表示法来创建一种简单的脚本语言来进行测试。TH3是第三次尝试。

大约在同一时间,一些航空电子制造商表达了对SQLite的兴趣,这促使SQLite开发人员设计TH3以支持严格的DO-178B测试标准 。

TH3的第一个代码制定于2008-09-25。在接下来的10个月中,经过不懈的努力,TH3于2009-07-25达到了100%的MC / DC。TH3代码将继续得到改进和扩展。

截至2018年5月19日,TH3源代码树由1709个单独的文件中的500,000多行源代码组成。

2.操作

TH3是一个测试程序生成器。TH3的输出是一个用C代码实现的程序,旨在与要测试的SQLite库链接。生成的测试程序将在目标平台上编译并运行,以验证SQLite在该平台上的正确操作。

TH3的输入是用C或SQL编写的测试模块以及确定如何初始化SQLite的小型配置文件。TH3软件包包括1,444个测试模块和超过47种配置(截至2018-05-19)。可以添加新的模块和配置,以针对专业应用定制TH3。每次运行TH3时,它都会读取可用测试模块和配置文件的子集,以生成一个自定义C程序,该程序在所有指定配置下执行所有指定测试。完整的SQLite测试通常涉及多次运行TH3,以生成涵盖SQLite操作不同方面的多个测试程序,然后将所有测试程序链接到通用SQLite库,然后在目标平台上单独运行它们。

TH3中没有任意限制。可以生成一个包含所有测试模块和所有配置文件的测试程序。但是,这样的测试程序可能太大,无法部署在嵌入式平台上。(截至2018-05-19,完整的TH3测试超过850,000行和58MB的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测试程序运行的典型输出如下所示:

使用SQLite 3.8.11 2015-05-15 04:13:15 56ef98a04765c34c1c2f3ed7a6f03a732f3b886e
-DSQLITE_COVERAGE_TEST
-DSQLITE_NO_SYNC
-DSQLITE_SYSTEM_MALLOC
-DSQLITE_THREADSAFE = 1
配置开始c1。
开始c1.pager08
结束c1.pager08
开始c1.build33
结束c1.build33
开始c1.orderby01
结束c1.orderby01
...省略了15014行输出....
开始64k.syscall01
结束64k.syscall01
开始64k.build01
结束64k.build01
开始64k.auth01
结束64k.auth01
配置端64k。使用的TH3内存:6373738
配置开始于wal1。
开始wal1.wal37
结束wal1.wal37
配置结束wal1。使用的TH3内存:100961
达到所有226个VDBE覆盖点
th3:在213.741秒内1442264测试中有0个错误。64位小端
th3:SQLite 3.8.11 2015-05-15 04:13:15 56ef98a04765c34c1c2f3ed7a6f03a732f3b886e

输出以针对测试中的SQLite的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文件中的一些:

TH3存储库还包括“ multitest.tcl”脚本,这是另一个用于在工作站上自动进行TH3测试的TCL脚本。Multitest.tcl自动编译SQLite,然后以各种对齐方式重复运行./th3make,并在简洁的摘要屏幕中捕获输出。典型的multitest.tcl运行会生成如下所示的输出:

./multitest.tcl -q-职位3
开始时间:2018-05-19 03:17:12 UTC
文件mkdir sqlite3bld
cd sqlite3bld
exec sh / ramdisk / sqlite / configure
文件复制-force config.h ../config.h
exec制作干净的sqlite3.c
文件重命名sqlite3.c ../sqlite3.c
文件重命名sqlite3.h ../sqlite3.h
exec make clean sqlite3.c OPTS = -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT = 1
文件重命名sqlite3.c ../sqlite3udl.c
exec制作干净的sqlite3.c OPTS = -DSQLITE_SMALL_STACK = 1
文件重命名sqlite3.c ../sqlite3ss.c
光盘..
****************************************************** *****************************
t01:cov.rc ............................................. .......好(00:03:42)
t02:cov.rc ++ STAT4 ++ DESERIALIZE -D_HAVE_SQLITE_CONFIG_H ......确定(00:04:45)
t03:vfs-cov.rc .......................................... .....好的(00:03:59)
t04:demo.rc ............................................. ......好(00:00:05)
t07:test.rc ../ th3private / *。test ..............................好的(00:00:21 )
t08:test.rc ../th3private/*.test ++ STAT4 ......................确定(00:01:41)
t05:quick.rc .................................... .....好的(00:04:26)
t09:quick.rc〜TEST_REALLOC_STRESS -funsigned-char .............确定(00:05:39)
t10:quick.rc〜THREADSAFE = 0 -DLONGDOUBLE_TYPE = double ...........确定(00:03:24)
t06:quick.rc extensions.rc -D_HAVE_SQLITE_CONFIG_H ............好(00:09:03)
t11:quick.rc sqlite3ss.c〜MAX_ATTACHED = 125 ...........确定(00:04:39)
t12:quick.rc〜BYTEORDER = 0 ++ RTREE .............................确定(00:07:28)
t13:quick.rc〜DISABLE_INTRINSIC ++ RTREE .......................确定(00:07:31)
t16:quick.rc〜TRACE_SIZE_LIMIT = 15 cov1 / main16.test ............好(00:00:22)
t14:quick.rc〜DIRECT_OVERFLOW_READ -fsigned-char ..............确定(00:04:35)
t15:quick.rc〜UNTESTABLE〜EXTRA_IFNULLROW ............好(00:01:44)
t17:quick.rc〜MAX_MMAP_SIZE = 0 ........................确定(00:04:46)
t18:quick.rc ++ NULL_TRIM ++ OFFSET_SQL_FUNC ...........确定(00:04:47)
t19:quick.rc ++ BATCH_ATOMIC_WRITE ++ DESERIALIZE ......确定(00:05:41)
t20:lean1.rc quick.rc .........................................好(00:03:09)
t22:test.rcalignment2.rc sqlite3udl.c .........好(00:44:22)
t21:test.rcalignment1.rc ............................确定(01:02 :32)
t23:memdebug1.rc extensions.rc ................................好(01:49:58)
t25:valgrind1.rc -O3 extensions.rc ............................确定(00:56:08)
t24:memdebug2.rc extensions.rc ................................好(01:43:34)
t27:test-ex1.rc .......................................... ....好的(00:45:00)
t26:valgrind2.rc -O3 extensions.rc ............................确定(01:02:52)
t29:test-ex3.rc .................................................... ....好的(00:31:48)
t28:test-ex2.rc .......................................... ....好的(01:12:03)
t30:test-ex4.rc ..................................... ....好的(01:09:47)
t32:test.rcalignment4.rc -m32 CC = clang .......................确定(00:48:31)
t31:test.rcalignment3.rc sqlite3udl.c ........................好(01:22:29)
t34:test.rcalignment6.rc ............................确定(00:35 :31)
t33:test.rcalignment5.rc extensions.rc .......................好(00:59:33)
t35:test.rcalignment7.rc .....................................确定(00:44 :10)
t40:fast.rc alignment2.rc sqlite3udl.c ........................好(00:15:46)
t39:fast.rcalignment1.rc extensions.rc -m32 .........好(00:33:19)
t36:test.rc〜MUTATION_TEST ....................................好的(00:35:45 )
t42:fast.rcalignment4.rc .....................................确定(00:13 :03)
t43:fast.rcalignment5.rc .....................................确定(00:13 :32)
t44:fast.rcalignment6.rc .....................................确定(00:11 :41)
t41:fast.rc alignment3.rc sqlite3udl.c ........................好(00:26:31)
t45:fast.rcalignment7.rc .....................................确定(00:12 :57)
t46:fast.rc -fsanitize = undefined .....................好的(00:38:18)
****************************************************** *****************************
0次失败(44:3thmakes)和198583082测试在(07:16:01)bella中的3个核心上
SQLite 3.24.0 2018-05-18 17:58:33 c6071ac99cfa4b6272ac4d739fc61a85acb544f6c1c2a

从上面可以看出,单次运行multitest.tcl会调用th3make数十次,并且需要12到24个CPU小时。输出的中间部分显示每个th3make运行的参数以及该th3make的结果和运行时间。单独的th3make运行的所有构建产品和输出均捕获在子目录中,以进行测试后分析。底部的两行摘要显示了所有th3make运行中的错误和测试总数,总运行时间,以及所测试SQLite版本的 SQLITE_SOURCE_ID信息。在最终测试期间,此摘要信息记录在 发布清单中。

在multitest.tcl输出中应用了缩写,以便每个th3make调用都可以放在一条80列的输出行上。初始的“ th3make”动词被省略。“〜”是“ -DSQLITE_”的简写,而“ ++”是“ -DSQLITE_ENABLE”的缩写。因此,multitest.tcl输出行

quick.rc〜DISABLE_INTRINSIC ++ RTREE

真正意思

th3make quick.rc -DSQLITE_DISABLE_INTRINSIC -DSQLITE_ENABLE_RTREE

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”,该名称可以自动执行变异测试过程 。

variant-test.tcl脚本负责运行突变测试的所有详细信息:

  1. 如有必要,脚本会将TH3测试工具编译为机器代码(“ th3.o”)。
  2. 如有必要,脚本会将sqlite3.c源文件编译为汇编语言(“ sqlite3.s”)。
  3. 该脚本循环浏览汇编语言文件中的指令以查找分支操作。
    1. 该脚本将复制原始sqlite3.s文件。
    2. 编辑副本可将分支指令更改为无操作或无条件跳转。
    3. 将sqlite3.s的副本组装到sqlite3.o中,然后再次链接th3.o以生成“ th3”可执行文件。
    4. 运行“ th3”二进制文件,并检查输出是否有错误。
  4. 该脚本显示上一步每个周期的进度,然后最后显示“幸存者”的摘要。“幸存者”是TH3未检测到的突变。

变异测试的速度可能很慢,因为在快速工作站上每次测试最多可能需要5分钟,并且每个分支指令都有两个测试,而超过20,000条分支指令则需要进行两次测试。努力加快操作速度。例如,TH3的编译方式是,一旦发现第一个错误,它就会立即退出,并且很容易检测到许多突变,许多周期仅在几秒钟内发生。但是,mutation-test.tcl脚本包含命令行选项,以限制测试的代码行的范围,因此仅需要对最近更改的代码块执行突变测试。

6. TH3许可证

SQLite本身在公共领域,可以用于任何目的。但是TH3是专有的,需要许可证。

即使开源用户没有直接访问TH3的权限,SQLite的所有用户也间接受益于TH3,因为在发布之前,每个版本的SQLite都已在多个平台(Linux,Windows,WinRT,Mac,OpenBSD)上运行TH3并经过验证。因此,使用SQLite正式版的任何人都可以放心部署其应用程序,因为它知道它已经使用TH3进行了测试。如果没有购买TH3许可证,他们根本无法自己重新运行这些测试。