Chapter 13. 回归测试

Table of Contents
13.1. 测试评估
13.1.1. 错误信息差别
13.1.2. 区域差别
13.1.3. 日期和时间差别
13.1.4. 浮点数差别
13.1.5. 元组顺序差别
13.1.6. "随机"测试
13.2. 平台相关的比较文件

回归测试的指导和分析.

回归测试是一套复杂完整的测试, 用来测试嵌入在 PostgreSQL 里的的 SQL 实现. 它同时测试标准 SQL 操作和PostgreSQL的扩展SQL. 这个套件最初是 Jolly Chen 和 Andrew Yu开发的,并且由 Marc Fournier 和 Thomas Lockhart 进行了大量的改进和重新封装. 自 PostgreSQL 6.1 以上开始, 这个回归测试包含在每个正式发布版本里.

回归测试可以就一套已经安装好并且在运行的服务器进行测试, 也可以就制作树里面临时安装的服务器进行测试.详细些说,有 "并行""串行"运行测试之分. 串行模式顺序运行每个测试,而并行模式启动多个服务器进程, 并行地运行一组测试. 并行测试使我们对进程内部通讯和锁的正确工作有足够的信心. 由于历史原因,串行测试通常对一个现存的安装进行测试,而并行 测试是"独立"的,不过这么做没有什么技术原因.

制作之后和安装之前运行回归测试,你可以在顶级目录键入

$ gmake check

(或者你可以进入 src/test/regress 然后 在那里运行命令.) 这样将先制作几个辅助文件,比如平台相关的 "expected(预期)" 文件和一些用户定义的触发器函数,然后再运行测试驱动脚本. 最后你会看到类似下面的东西

======================
 All 76 tests passed.
======================

或者是一些关于某项测试失败的信息.参阅下面的 Section 13.1获取更多信息.

注意: 因为这个测试方法运行临时的服务器,所以如果你是 root 用户, 那这个方法不能运行(服务器不能以 root 身份启动). 如果你已经以 root 身份制作了,你就什么也干不了. 这时候你应该把测试目录的权限变成某个用户可以写, 然后以那个用户身份登陆,再开始测试.比如,

root# chmod -R a+w src/test/regress
root# chmod -R a+w contrib/spi
root# su - joeuser
joeuser$ cd top-level build directory
joeuser$ gmake check

(这里唯一可能的"安全隐患"就是那个用户可能会背着你 修改回归测试的结果.用你的常识管理用户权限.)

如果不是上面那样,安装后就可以运行测试.

窍门: 并行的回归测试会在你的用户 ID 下启动相当多的进程. 目前,最大的并发数是 20 给并行测试脚本,这意味着 60 个进程 --- 一个后端,一个psql以及通常还有一个 shell 父进程用于每个测试脚本 的psql.因此,如果你的系统有每用户的进程数限制,那么请确保这个 限制至少是 75,否则你就可能在并行测试时看到随机出现的失败. 如果你没有办法提升该限制,那么你可以编辑文件 src/test/regress/parallel_schedule,把大的并行测试 套件分割成更容易管理的小组.

小技巧: 在某些系统上,缺省的 Bourne 兼容的 shell(/bin/sh) 在管理太多并行的子进程的时候会出乱子.这可能导致并行测试锁住或者失败. 出现这种情况时,请在命令行上声明另外一个 Bourne 兼容的 shell,比如:

$ gmake SHELL=/bin/ksh check

如果能用比较好的 shell,那么你可以象上面那样修改并行测试计划.

安装后(参阅 Chapter 1)运行测试, 初始化一个数据区然后启动服务器,象我们在 Chapter 3 里面描述的那样,然后键入

$ gmake installcheck

该测试将与在本地主机和缺省端口号上运行的服务器进行联接, 除非你用PGHOSTPGPORT环境变量设置为其它值.

13.1. 测试评估

有一些正确安装并且具有完整功能的 PostgreSQL可能会在一些回归测试中 "失效", 这些主要是因为浮点数的形式和时区支持的问题.目前的测试只是简单的用 diff与参考系统的输出进行比较, 因而对一些细小的系统区别很敏感. 当一项测试报告"failed"("失败")时,只要检查一下预期和实际的结果, 你就会发现区别区别并不大. 当然,我们仍然在努力维护所有我们支持的平台的准确的参考文件, 这样我们就可以假定所有测试都通过.

回归测试的实际输出是在 src/test/regress/results 目录里的文件里.测试脚本使用 diff 以比较 每个输出文件和存放在 src/test/regress/expected 目录里的参考输出.任何区别都存放在 src/test/regress/regression.diffs 里面供你检查.(或者如果你愿意的话,你也可以自己运行 diff.)

13.1.1. 错误信息差别

有一些回归测试涉及到有意的非法输入值. 错误信息可能会来自PostgreSQL 代码或来自主机平台系统过程. 对于后者,信息可能在平台之间区别比较大,但应该反映相似的信息. 这些信息上的差别将会导致一个"失败"的回归测试, 我们可以通过检查文件发现这一点.

13.1.2. 区域差别

如果你在一台已经安装好了的服务器上运行测试,而该服务器是用一种 非 C 的区域设置初始化的,那么可能因为有排序顺序和其它类似的差别 导致的失败.回归测试套件处理这种问题的方法是提供可选的结果文件, 这些文件一起处理一大堆的区域.比如,对于 "char" 测试, 预期的文件 char.out 处理CPOSIX区域, 而文件 char_1.out 处理许多其它区域. 回归测试驱动将自动选取最接近的文件进行成功检查以及计算失败差别. (这就意味着回归测试不能检测该结果对于配置的区域是否合适. 该测试将简单地选取一个运转得最好的文件.)

如果由于某些原因,现有的预期文件无法覆盖一些区域,那么你可以 增加一个新文件.命名纲要是 testname_digit.out. 实际的 digit 是什么并不重要.要记住回归测试驱动将认为所有 这样的文件都是有效的测试结果.如果测试结果是平台相关的, 那么应该使用在 Section 13.2 里描述的技巧.

13.1.3. 日期和时间差别

如果你在夏时制时间切换的那天,或者是之前或之后一天运行测试,那么 在 horology 测试中的一些查询会失败, 这些查询假设在昨日午夜,今日午夜和明日午夜之间的差距正好时 24 小时 -- 如果在夏时制切换的时候这个数值时错误的.

大多数日期和时间结果依赖于时区环境变量。参考文件是为时区 PST8PDT (伯克利,加州)准备的,因而如果测试没有设置为那个时区是显然会失败的。 回归测试的驱动器把环境变量 PGTZ设置为PST8PDT以保证正确的测试。 不过,你的系统必须为PST8PDT提供库支持, 否则与时区相关的测试将会失败.

$ env TZ=PST8PDT date

上面的命令应该返回PST8PDT时区的当前时间.如果没有能用的 PST8PDT数据库,那么你的系统可能会返回 GMT 的形式的时间. 如果没有可用的PST8PDT数据库,那么你可以明确设置时区规则:

PGTZ='PST8PDT7,M04.01.0,M10.05.03'; export PGTZ

有些系统不能接受我们推荐的显式设置时区的语法; 在这样的机器上你可能要用不同的 PGTZ设置。

有些使用旧的时区库的系统在对PDT1970 年前的时间使用夏时制时会出毛病, 导致PDT1970 年以前的时间显示为PST。 这会导致在测试结果里的本地化区别。

如果你在改为夏时制的日切日或者该天的前天或者后天测试时, 在 "timestamp" 测试里的一些查询可能失败. 这些查询假设昨天午夜, 今天午夜和明天午夜之间的间隔是精确的 24 小时... 如果是夏时制开始或结束的日切日,这些(假设)是错的.

13.1.4. 浮点数差别

有些测试涉及到对表中的数据列进行 64位(double precision) 计算的问题. 我们观察了涉及到计算double precision字段的数学函数的 结果的差别. float8geometry(几何类型)测试尤其容易在不同平台之间产生小差别。 这时需要肉眼对这些差别进行比较, 以判断这些差别究竟有多大,我们发现是在小数点右边10位数。

有些系统把负零显示为 -0,而其它的只是显示 0

有些系统在pow()exp() 出错时产生的信号与目前 Postgres代码里期望的机制不一样.

13.1.5. 元组顺序差别

你可能会看见同样的元组以与预期文件的不同的顺序输出.在大多数情况下, 严格说来这不算臭虫.大多数回归测试脚本都不会迂腐到在每个 SELECT 中都使用 ORDER BY 的地步,因此根据 SQL 规范里的词汇的说明,它们的结果集的顺序 并非定义得非常好的.尤其是因为我们是在同样的数据上运行同样的查询, 因此我们在所有平台上通常都获得同样的结果, 因此即使缺少 ORDER BY 也不算什么大问题. 不过有些查询的确存在跨平台的排序问题. (如果你使用了非 C 的区域设置,也可能造成排序差异的问题.)

因此,如果你看到一个排序差异,应该不是什么要担心的问题(除非 出问题的查询的确使用了 ORDER BY).不过,如果有这样的现象,请告诉我们, 这样我们就可以在那条查询上加一个 ORDER BY, 这样我们就可以在以后版本里消除着种伪"失败"

你可能会问,为什么我们不对所有回归测试的 SELECT 进行排序 以一次性消灭所有这类问题. 原因是这样做只能让回归测试用处更少,而不是更多,因为它们会试图使用 那些生成顺序结果的查询规划,而不再使用那些不排序的查询规划.

13.1.6. "随机"测试

"随机"测试脚本里至少有一个测试会产生随机结果. 这会导致回归测试中的随机测试失败(可能每五次到十次出现一次). 键入

diff results/random.out expected/random.out

会产生仅仅一行或几行差别. 你不必担心这些,除非随机测试在重复测试中总是失败. (另一方面,如果在多次回归测试中随机测试 从不 失败,你可能也 应该 担心.)