Translate-CS 板


LINE

庆贺开版,尝试翻译一篇许愿文,有建议或修改的话 欢迎直接在 github 上发 pull request 给我 :-) https://github.com/yangacer/translation/blob/master/sqlite-test.md ==== SQLite 是如何测试的 1.0 介绍 通透且谨慎的测试,是SQLite 的可靠性与强固性的一环。以 3.7.14 版来说,SQLite 函 式库内含近 8.13 万行的原始码(不含空白与注解). 相较来说,这个专案对应的测试码与 指令稿高达 1124 倍─相当於 914.211 万行的程式。 1.1 执行总论 - 三个各自开发的自动化测试框架 - 倚照布署设定前提下,百分百的测试涵盖度 - 近百万个测试案例 - 记忆体不足测试 - 系统崩溃与跳电测试 - 模糊测试 - 边界值测试 - 关闭最佳化测试 - 回归测试 - 崎异(malformed)资料库测试 - 大量使用断言 (assert) 与执行期检验 - Valgrind (堆积分析工具) 分析 - 有号数溢位检验 2.0 自动化测式框架 有三个独立开发的自动化测式框架被使用於 SQLite 的核心函式库。各自被分开来设计、 维护,与管理。 TCL 是最早期的测试;他附带在 SQLite 的原码树之中,并使用跟 SQLite 一样的公开授 权。他是在开发 SQLite 的过程中主要的测试工具。TCL 自动化测试框架是以 TCL 指令 语言写成,大约由 2.51 万行的 C 原码构成 TCL 介面。这些测试指令码分布在 711 个 档案中,大小共约 10.0 MB。其中有 29,226 个不同的测试案例,不过许多参数化的测试 ,会以不同参数进行多次的测试,因此一次完整的测试会执行约 3 百万个不同的案例。 TH3 是一个有专利的框架,以 C 写成,提供对 SQLite 核心函式库百分百的测试涵盖度( 与百分白的 MC/DC 测试涵盖度)。此框架是为了嵌入式系统、特化平台,这些无法轻易获 得 TCL 支援的环境,以及工作站所设计。TH3 只使用公开的 SQLite 介面。TH3 对 SQLite 加盟会员是免费的,同时也可透过授权方式供他人使用。TH3 由近 50.1 mb 或 66.69 万行 C 程式码实作朱 34,229 个不同的测试案例。然而 TH3 是重度参数化的, 因此,完全涵盖的测试会执行约 80 万个不同的测试实例。该提供 100% 分支测试涵盖度 构成一个 TH3 测试套件的子集。一个发布前的浸入式测试会进行数亿个测试。额外的 TH3 资讯另外提供於此。 SQL Logic Test 或 SLT 框架用来对 SQLite 与数个其他 SQL 资料库执行大量的 SQL 语 句,并验证结果是否相同。SLT 目前将 SQLite 与 PostgreSQL, MySQL, Microsoft SQL Server 与 Oracle 10g 进行比对。 SLT 执行逾 7 百万个查询,相当於 1.12 GB 的测资 。 在 SQLite 发布前,在多个平台、多个编译选项的状况下,以上的所有测试都必须成功。 在提交程式码到 SQLite 的原码树之前,开发者通常得通过一个快速的 TCL 测试,约 12.91 万个测试案例。这个快速测试不包含异常、模糊与浸入式测试。快速测试足以捕 捉常见的错误,同时也只需要几分钟的时间而不是几小时。 3.0 异常测试 异常测试设计用来验证当事情出错时行为是否正确。在功能正常的电脑上建立一个 SQL 资料库引擎相对地容易。而在有问题的系统上建立一个资料库;可以正常地回绝无效输入 并维持运作就较为困难了。异常测试乃为後者而设计。 3.1 记忆体不足(Out-Of-Memory, OOM) 测试 跟所有的 SQL 资料库相同,SQLite 使用大量的 malloc() (详见关於SQLite 的动态记忆 体配置文件。在伺服器或工作站上,malloc() 实务上从不失败,因此 OOM 错误的处理并 不特别重要。然而在嵌入式系统上,OOM 错误常见地惊人,而 SQLite 又常用於嵌入式系 统上。为此,SQLite 要能够优雅地处理 OOM 错误是很重要的。 记忆体不足测试以模拟记忆体错误的方式完成。透过 sqlite3_config(SQLITE_CONFIG_MALLOC, ...) 介面 SQLite 允许用户端以不同方案置 换 malloc() 的实作。TCL 及 TH3 框架都允许置入一个修改过的 malloc() ,让记忆体 配置在一定数量後失败。这个修改过的 malloc() 可以仅失败一次後就恢复正常,又或者 不断地配置失败。OOM 测试以一个回圈完成。当第一次佚代回圈时,该修改过的 malloc() 会使第一次配置失败,接着会进行一些 SQLite 操作并检验结果以确认 SQLite 正确处理 OOM 错误。之後便递增该 malloc 中的计数器并重复回圈。此回圈会 持续到所有 SQLite 操作都没有遇到 OOM 错误时。像这样的测式会进行两次,第一次让 该 malloc() 只会失败一次,第二次则让 malloc() 连续失败。 3.2 I/O 错误测试 I/O 错误测试旨在验证 SQLite 能正常处理 I/O 操作的失败。I/O 错误可能肇因於磁碟 满载、磁碟硬体损坏、使用网路档案系统时断线、在 SQL运作中变更系统设定或权限,或 其他硬体与作业系统的异常。不论原因,重要的是SQLite 能够正确处理这些错误,而 I/O 错误测试希冀能验证这一点。 I/O 错误测试概念上与 MMO 测试类似:I/O 错误以模拟的方式产生,用来验证 SQLite 能正确回应这些模拟的错误。I/O 错误在 TCL 与 TH3 框架中皆以插入虚拟档案系统物件 被模拟,此物件会在一定数量的 I/O 操作後失败。与 MMO 相同,I/O 错误模拟也能设定 为失败一次或连续失败。测试在回圈中执行,渐进式地增加失败直到测试案例能正常执行 完毕。回圈会执行两次,第一次让 I/O 只错误一次,第二次则会连续失败。 在 I/O 错误测试中,会在关闭错误模拟之後, PRAGMA integrity_check会被用来验证资 料库,以确保 I/O 错误并未损毁资料。 3.3 崩溃测试 崩溃测试目的在於展现 SQLite 即使面临客户端崩溃、系统崩溃或者是更新资料库时断电 等悲剧,都能避免资料库损毁。另一篇名为SQLte 单步递交的文件描述 SQLite 采取了哪 些防御性措施,防止资料库因崩溃而损毁。崩溃测试将验证这些防御工事是否正常运作。 当然,使用真正的断电进行崩溃测试不太实际,所以这项测试也是以模拟的方式进行。透 过增添一个修改过的虚拟档案系统 ,崩溃测试得以模拟崩溃後的资料库档案。 TCL 测试框架中,崩溃测试在另外的行程执行。主行程会产生一个子行程来执行某些 SQLite 操作并於写入动作中随机产生崩毁。一个特殊的虚拟档案系统会随机重排并损毁 未同步的写入动作,此举意在模拟有缓冲机制的档案系统发生崩溃时连带产生的影响。该 子行程结束後,主行程会读取同一个资料库,并检验子行程尝试进行的修改要麽是成功完 成,要麽是被完整的回溯。PRAGMA integrity_check会被用来验证资料库,以确保资料完 整性。 3.4 综合失败测试 这个测试套件会检视多种以上提到的失败一起发生时造成的结果。举例来说,测试会被用 来确认一个 I/O 错误或 MMO 错误发生在回复崩溃後的资料库时,SQLite 的行为是否正 常。 4.0 模糊测试 模糊测试旨在建立 SQLite 对无效、越界、或崎异的输入正确回应的能力。 4.1 模糊 SQL SQL 模糊测试会把文法正确,但广泛来说没有意义的 SQL 语句输入 SQLite 来观察它会 如何应对。通常会传回某些错误(像是“没有这个表“)。某些时候,这些 SQL 语句偶 然是语意正确的,这种状况下预先准备好的语句会被执行,以确认得到合理的结果。 模糊 SQL 产生器是 TCL 测试套件的一部分。在完整的测试执行过程中,将近 12.63 万 模糊 SQL 语句会被产生并被测试。 4.2 崎异资料库档案 无数个测试案例用来验证 SQLite 处理崎异资料库档案的能力。这些测试首先建立一个正 常的资料库档案,接着藉由改变一些档案中的位元组来产生一些扭曲,再以 SQLite 读取 这个档案。在某些状况,被改变的位元组可能在栏位资料中间,这会让资料库档案的内容 发生改变,但不影响资料库档案本身的格式正确:在其他状况,未被使用的位元组被修改 则不会影响资料库的完整性。有趣的情况是修改到定义资料库结构的资料时。崎异资料库 测试会验证 SQLite 能找到这些档案格式的错误并以 SQLITE_CORRUPT 错误码回报给客户 端,而不绘影发任何缓冲溢位、对空指标解参照或执行其他不当行为。 4.3 边界值测试 SQLite 定义了 一些操作的限制,像是资料表的行数上限、SQL 语句长度上限或是整数的 上限。TCL 与 TH3 套件都含有许多测试能将 SQLite 塞满到这些定义内的上限值并验证 他能正确地处理所有允许的值。额外的测试会以超过定义上限的方式来验证 SQLite 会正 常回报错误。原始码中含有测试案例巨集来验证边界值得两端都能被测试。 5.0 回归测试 当一个臭虫被回报时,直到新的测试案例加入 TCL 测试套件,并在一个未修改的 SQLite 版本重现该臭虫,此臭虫才算是被修正。数年来,这导致数百万个新的测试案例 被加入 TCL 测试套件。这些回归能保证被修复的臭虫不会出现在未来的 SQLite 版本。 6.0 自动资源泄漏侦测 资源泄漏会在系统资源被配置了却从未被释放时发生,许多应用程式理,最恼人的资源泄 漏莫过於记忆体泄漏─以 malloc() 配置记忆体後未以 free() 释放。不过其他种类的资 源也可能泄漏,像是档案记述子、执行绪、互斥器等。 TCL 与 TH3 在每次进行测试时会自动追踪系统资源并回报资源泄漏,不需要特殊的设定 。这些测试框架对记忆体泄漏尤其关注;如果一个更动引起了记忆体泄漏,测试框架会快 速地发现这个状况。SQLite 被设计为从不泄漏记忆体,即使发生了 OOM 错误或磁碟错误 这样的例外情境─测试框架勤於强化这个特点。 7.0 测试涵盖度 在 2009-07-25 版本的 TH3,使用预设设定在 SuSE Linux 10.1 的 x86 平台上以 GCC 4.0.1 编译产生的SQLite ,以 gcov 检测,分支测试涵盖度达到 100%。 7.1 语句 v.s. 分支涵盖度 有许多方法测量测试的涵盖度。最普遍的方法是"语句涵盖度"。当你听到有人说他们的程 式有多少百分比的涵盖度而缺少进一步的解说时,他门通常指的是与具涵盖度。语句涵盖 度量测的是程式码中至少被测试一次的百分比。 分支涵盖度就严苛多了,他会量测机器码中的分支指令,其两条支线是否至少被执行过一 次。考虑以下 C 程式码: if( a>b && c!=25 ){ d++; } 这样的一行可能会产生一打机器语言。〈译:以分支涵盖度来看〉如果其中的任一个指令 都被运算过,我们才能说这个语句被测试过。那麽举例来说,可能这个条件句总是为假, 而 d 变数从未被递增。这时,语句涵盖度仍会将这一行程式码列入已测试的计算。 分支涵盖度是更严谨的,有了它,每个测试与语句的子区段都会被独立考虑。为了达到 100% 的分支涵盖度,上面的范例必须要有至少三个测试案例: a <= b a > b && c == 25 a> b && c!= 25 以上任何一个测试案例都能提供 100% 的语句涵盖度,但是分支涵盖度则是三个都需要。 一般来说,100% 分支涵盖度可引申为 100% 的语句涵盖度,但反之则不然。再强调一次 ,TH3 测式框架有 100% 分支涵盖度,我超强˙。 7.2 防卫性程式码的涵盖度测试 写作良好的 C 程式通常含有一些防卫性的测试,测试结果实务上是永远为真或为假。这 会导致一个程式设计的两难:有人为了 100% 的分支测试移除防卫性测试吗? 在 SQLite ,这个答案是否定的。为了测试需求,SQLite 定义了 ALWAYS() 与 NEVER 两 个巨集。ALWAYS() 巨集包裹预期为真的条件而 NEVER() 则相反。这两个巨集可视为防卫 性测试的注解。以标准建置的环境来说,这些巨集是被略过的: #define ALWAYS(X) (X) #define NEVER(X) (X) 不过在大多数测试,如果参数与预期结果不同,这两个巨集会丢出一个断言失败。这会快 速地警告开发者使用了不正确的设计假设。 #define ALWAYS(X) ((X)?1:assert(0),)) #define NEVER(X) ((X)?assert(0), 1:0) 当量测涵盖度时,这两个巨集会被定义为常数,因此不会产生分支指令,也就不会影响分 支涵盖度的计算。 #define ALWAYS(X) (1) #define NEVER(X) (0) 此测试套件被设计为执行三次,每次使用一种上面列出的巨集定义。三次执行都应该产出 完全一样的结果。执行期可透过 sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, ...) 介面来验证巨集被正确设定为布署用的设定(略过断言)。 7.3 强制涵盖边界值与布林向量(布林遮罩)测试 另一个巨集,与涵盖量测共同使用的是 testcase() 巨集。参数是我们希望真、假两种结 果都被评估的的条件句。在非涵盖型建置时〈发布型建置〉,此巨集为无作用操作。 不过在涵盖度量测模式时,此巨集会运算它的参数。然後在分析阶段检查对真假两种状态 都有进行测试。举例来说 testcase() 会被用来验证边界值已被测试: testcase( a == b ); testcase( a == b+1); if( a>b && c!=25 ){ d++; } 该巨集也会被用在有多个条件落入相同区段的 switch 语句,来确认所有条件都有被(测 试)执行过: switch( op ){ case OP_Add: case OP_Subtract: { testcase( op == OP_Add ); testcase( op == OP_Substract ); break; } } 对位元遮罩的测试,testcase() 巨集可验证所有遮罩中的位元都有影响到测试。例如下 面的程式码,若遮罩中 MAIN_DB 或 TEMP_DB 任一位元被打开,则条件为真,前置的 testcase() 巨集会验证两种状况都被测试过: testcase( mask & SQLITE_OPEN_MAIN_DB ); testcase( mask & SQLITE_OPTN_TEMP_DB); if( (mask & (SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_TEMP_DB)) !=0 ) { ... } SQLite 的原始码中使用了 667 个 testcase() 巨集。 7.5 关於完全涵盖测试的经验 SQLite 的开发者发现完全涵盖测试是个极具生产力的方式,它能避免在系统进化时引入 新的臭虫。由於每一个分支指令都被测试实例涵盖,开发者能自信其修改不会让其他程式 码发生预期外的影响。没有这个保险措施,SQLite 的品质将难以维护。 8.0 动态分析 动态分析意指 SQLite 执行期的内部与外部检验。这项分析已证明对 SQLite 品质的维护 有很大帮助。 8.1 断言 SQLite 核心包含 3531 个 assert() 语句,用以验证函式的前置条件、後置条件与回圈 的不变性。assert() 是一个 ANSI-C 标准中的巨集。其参数为一个预期为真的布林值。 若这个断言失败,程式会印出错误讯息并终止。 此巨集在定义了 NDBUG 巨集的编译状况下会被忽略。在大部分系统,断言预设是开启的 。不过在 SQLite,断言数量极多且在校能瓶颈区段,造成资料库引擎在断言开启的状况 下速度降低了三倍。因此,预设的〈产品级〉SQLite 建置会关闭断言。断言语句只有在 SQLite 建置过程中,SQLITE_DEBUG 预处理巨集被定义的状况下才会开启。 8.2 Valgrind Valgrind 可能是世上最令人惊艳、最有用的开发者工具。Valgrind 是一个模拟器─模拟 一个执行 Linux 的 x86 〈移植 Valgrind 到不同系统的开发正在进行,然而在写这篇文 章的当下,只有 Linux 上的 Valgrind 是可靠的,对 SQLite 的开发者来说,这代表 Linux 会是一个偏好的软体开发平台〉。当 Valgrind 执行时 ,它会监看所有有趣的错 误,像是阵列逾界存取、读取未初始化的记忆体、堆叠溢位、记忆体泄漏等。Valgrind 能找出逃过其他 SQLite 测试的错误,而且,当 Valgrind 发现错误时,它能将确切的出 错位置倾印至一个符号除错器,得以快速进行修复。 由於它是一个模拟器,在 Valgrind 中执行的速度会较原生硬体上〈应用程式跑在工作站 上的 Valgrind 时,速度大约等於在智慧型手机原生执行的速度〉。因此用 Valgrind 来 执行所有 SQLite 的测试是不切实际的。然而,在每一次发布新版前,快速测试与 TH3 的涵盖度测试会在 Valgrind 上进行。 8.3 Memsys2 SQLite 内建一个可插拔的记忆体配置子系统。预设的实作使用系统函式 malloc() 与 free()。然而,若 SQLite 以 SQLITE_MEMDEBUG 选项编译时,一个替代的记忆体配置包 装器(memsys2)会被用来监看执行期的记忆体配置错误。memsys2 包装器除了检查记忆 体泄漏外也会追踪缓冲区逾界存取、存取未初始化的记忆体, 以及操作已被释放的记忆体。同样的测试也会以 Valgrind 进行(而的确, Valgrind 做 得比较好),不过 memsys2 拥有速度较快的优势,这代表可以常常进行检验或执行较久 的测试。 8.4 互斥器断言 SQLite 内建一个可插拔的互斥器子系统。依编译选项,预设的互制器系统有两个介面 sqlite3_mutex_held()与 sqlite3_mutex_notheld()用於侦测某个互斥器是否被呼叫的 执行序所持有。在 SQLite 中,为了双重检验在多序环境运作的正确性,这两个介面被大 量地与 assert() 一起使用,藉以验证互斥器在对的时机被持有与释放。 8.5 旅记测试 SQLite 会在开始变更资料库前,将所有修改预先写入一个回溯旅记,藉此确认跨越系统 崩溃与断电的异动(transaction)是单步的。TCL 测试框架含有一个作业系统後端实作 ,可辅助验证这项功能是否被正确触发。此旅记测试虚拟档案系统监视所有资料库档与回 溯旅记之间的磁碟 I/O 流程,确认在资料写入回溯旅记之前,没有任何资料被写入到资 料库档案。若任何违背以上原则的状况发生,会发出一个断言失败。 旅记测试是在崩溃测试之上额外的双重检验,可确认 SQLite 的异动能单步执行,即使中 间发生了系统崩溃与断电。 8.6 有号整数溢位检验 C 语言标准对有号整数溢位後的行为未有定义,换句话说,当你对一个有号整数做加法运 算而运算结果超过了该整数的存放空间,这个数值不见得像多数程式设计者认为的那样, 被处理为负数。这只是可能的现象之一,但完全不同的情况也可能发生,可参考这里与这 里。即使是同一个编译器也会因程式码的位置不同或最佳化的选项不同而对溢位采用不同 的处理方式。 SQLite 从不溢位一个有号数。为了验证这一点,测试套件至少会执行一次以 GCC 的 -ftrapv 参数编成的执行档。该参数让 GCC 遇到有号数溢位时自动呼叫 panic() 。此 外,有许多测试会尝试造成有号数溢位,像是 "SELECT -1*(-9223372036854775808);"。 9.0 关闭最佳化测试 sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) 允许 SQL 语句最佳化在 执行其关闭。不管最佳化开启与否,SQLite 的回应应该都是一致的;最佳化只是让回敬 速度较快。因此在产品使用上,预设是开启最佳化设定的。 为了验证最佳化不会带来臭虫,SQLite 的测试包含两次测试,一次在开启最佳化的情况 下,一次则在关的情况下。 并非所有测试都能这麽搞。有些测试本身是为了验证最佳化的有效性,比如藉由磁碟操作 计数降低运算量、排序操作、全扫描,或者其他查询中的处理。这些测试在关闭最佳化的 状况下当然会失败。不过主要的测试项目在於验证回应是否正确,这些项目就与最佳化无 关了。 10.0 静态分析 静态分析指的是在编译中或编译後检查正确性。静态检查包括编译器警告讯息以及用分析 引擎,像是 Clang Static Analyzer 深入检查。SQLite 以 GCC/Clang -Wall -Wextra 在 Linux, Mac, Windows 上的 MSVC 编译时,是完全没有警告讯息的。以 Clang 的 Clang Static Analyzer 工具 scan-build 也没有任何警告。不用说,可能其他的静态 分析工具会提出警告。我们鼓励使用者不要对这些警告太过紧张,可以用本文提到的测试 安慰一下自己。 静态分析还没被证明对除错很有用。他是有找到一些臭虫,但这些算是例外;更多臭虫的 产生是由於尝试移除静态分析提出警告。 11.0 总结 SQLite 是开放原码专案。这让很多人觉得他并未像商用软体般被良好测试,因而可能不 太可靠。然而这是个错误印象。SQLite 在这个领域呈现高度的可靠性与稀少的损毁率, 尤其考虑到他是这麽频繁的被使用。品质的达成一部分是由谨慎的程式码设计与实作;然 而全面性的测试,在 SQLite 的维护与改进中也占了重要的一席之地。这份文件总结了每 次 SQLite 发布前的测试的过程,冀望读者能理解 SQLite 能适用於严谨的应用程式。 --



※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.132.12.57
1F:推 PsMonkey:好强大... 有神快拜阿..... Orz 03/29 23:01
2F:推 coolcomm: 03/29 23:36







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:BabyMother站内搜寻

TOP