测试执行环境的详尽规范。
背景
Bazel BUILD 语言中包含可用于定义自动化 测试程序。
使用 bazel test
运行测试。
用户也可以直接执行测试二进制文件。我们允许这种做法,但不表示认可 因此此类调用将不遵循下述授权。
测试应该是封闭的:也就是说,测试应该只访问这些资源 它们已声明了依赖项如果测试未正确封闭 则它们不会给出可重现的历史结果。这可能是 找出导致罪魁祸首的重大问题(确定哪些更改破坏了测试)、 发布工程可审核性,以及测试的资源隔离(自动化 测试框架不应对服务器进行 DDOS,因为有些测试正好需要与 )。
目标
本页的目标是正式为 Cloud Storage 和 Cloud Storage 的 Bazel 测试的预期行为还会对测试施加要求 运行程序和构建系统
测试环境规范可帮助测试作者避免依赖 从而赋予测试基础设施更大的自由 实施更改。该规范增加了一些漏洞, 目前允许许多测试通过,尽管测试没有适当的封闭, 确定性和可重入性。
本页内容具有规范性和权威性。如果 与测试运行程序的实现行为不一致, 优先级。
建议的规范
关键字“必须”“不得”“必需”“会”“不会”“应” “不应该”“建议”“可以”和“可选”将被解释为 (如 IETF RFC 2119 中所述)。
测试目的
Bazel 测试的目的是确认源文件的某个属性 签入代码库(在本页中,“源文件”包括测试数据, 黄金输出,以及保持版本控制的其他内容。)一位用户写入 以断言预期会得到维护的不变量。其他用户 稍后执行测试以检查不变量是否已损坏。如果 测试依赖于除源文件(非封闭)之外的任何变量,其值 因为之后的用户无法确定他们的更改是否有误 当测试停止通过时触发。
因此,测试的结果必须仅取决于:
- 测试已声明其依赖项的源文件
- 已声明测试依赖的构建系统的产品
- 行为由测试运行程序保证保持不变的资源
目前,未强制执行此类行为。不过,测试运行程序会保留 拥有权利。
构建系统的角色
测试规则类似于二进制规则,每个规则都必须生成一个可执行文件 计划。对于某些语言,这是一个存根程序,用于将 测试代码。测试规则必须生成 输出内容。除了主测试可执行文件之外,测试运行程序 将需要一个 runfiles 的清单,这些输入文件应该可供使用 在运行时进行测试,可能需要关于类型、大小和 代码。
构建系统可以使用 runfile 传递代码和数据。( 可以作为优化措施, 文件。)构建系统 应确保生成的可执行文件通过 runfile 测试运行程序提供的图像,而不是对绝对 在源树或输出树中的位置。
测试运行程序的角色
从测试运行程序的角度来看,每个测试都是一个程序,
使用 execve()
调用。可以通过其他方式进行测试;例如
IDE 可能允许在进程中执行 Java 测试。不过,结果
必须被视为权威性测试。如果
测试进程运行至完成并正常终止,并显示退出代码
零,则表示测试已通过。任何其他结果均被视为测试失败。在
具体来说,如果将任何字符串 PASS
或 FAIL
写入 stdout,
对测试运行程序的重要性。
如果测试的执行时间过长、超出某些资源限制,或者 其他运行程序检测到禁止的行为,则可能会选择终止测试并 系统会将运行视为失败。运行程序之后不得将测试报告为通过 向测试进程或其任何子级发送信号。
为整个测试目标(而非单个方法或测试)指定有限的
运行完毕所需的时间测试的时间限制取决于
timeout
属性
如下表所示:
超时 | 时间限制(秒) |
---|---|
短片 | 60 |
适中 | 300 |
long | 900 |
永恒 | 3600 |
未明确指定超时的测试会根据
测试的 size
,如下所示:
大小 | 隐含的超时标签 |
---|---|
小 | 短片 |
medium | 适中 |
大 | long |
超大 | 永恒 |
“大型”对于没有显式超时设置的测试,将分配 900 秒。“媒介”测试超时值“short”将分配到 60 。
与 timeout
不同,size
还决定了
在本地运行测试时访问的其他资源(例如 RAM)中,具体说明请参阅
常见定义。
size
和 timeout
标签的所有组合都是合法的,因此“特大”测试
可以声明超时为“short”。它应该能
很快会发生可怕的事情
无论超时多久,测试都可能会以任意快的速度返回。测试不会受到处罚 设置超时值,虽然系统可能会发出警告: 通常,应尽可能将超时设置得很紧,不易出现任何不稳定的情况。
在以下情况下,可以使用 --test_timeout
bazel 标志替换测试超时:
在已知慢速条件下手动运行。通过
--test_timeout
值以秒为单位。例如:--test_timeout=120
将测试超时设置为两分钟。
此外,还有一个建议的测试超时下限,如下所示:
超时 | 最短时间(秒) |
---|---|
短片 | 0 |
适中 | 30 |
long | 300 |
永恒 | 900 |
例如,如果“中等”测试在 5.5 秒内完成,请考虑设置 timeout =
"short"
或 size = "small"
。使用 bazel --test_verbose_timeout_warnings
命令行选项会显示指定大小过大的测试。
测试大小和超时在 BUILD 文件中根据 此处查看规范。如果 未指定,测试大小将默认为“medium”。
如果测试的主进程退出,但其部分子级进程仍在运行, 测试运行程序应认为运行已完成并将其计为成功,或者 根据从主进程观察到的退出代码判断是否失败。测试运行程序 可能会终止任何散乱进程测试不应以这种方式泄露进程。
测试分片
您可以通过测试分片并行运行测试。请参阅
--test_sharding_strategy
和shard_count
至
启用测试分片。启用分片后,测试运行程序将启动一次
每个分片环境变量 TEST_TOTAL_SHARDS
是碎片数,而 TEST_SHARD_INDEX
是
分片索引,从 0 开始。运行程序会使用这些信息来选择哪些测试
运行 - 例如,使用轮循策略。并非所有测试运行程序都支持
。如果运行程序支持分片,则必须创建或更新最后一个
指定的文件的修改日期
TEST_SHARD_STATUS_FILE
。否则,如果
--incompatible_check_sharding_support
启用后,如果 Bazel 被分片,测试将无法通过。
初始条件
在执行测试时,测试运行程序必须建立特定的初始 条件。
测试运行程序必须使用测试可执行文件的路径来调用每个测试。
argv[0]
。此路径必须是相对路径,并且位于测试的当前目录下
(位于 runfiles 树,请参阅下文)。测试运行程序不应通过任何
为测试添加其他参数,除非用户明确要求。
初始环境块应按如下方式组成:
变量 | 值 | 状态 |
---|---|---|
HOME |
$TEST_TMPDIR 的值 |
推荐 |
LANG |
unset | 必填 |
LANGUAGE |
unset | 必填 |
LC_ALL |
unset | 必填 |
LC_COLLATE |
unset | 必填 |
LC_CTYPE |
unset | 必填 |
LC_MESSAGES |
unset | 必填 |
LC_MONETARY |
unset | 必填 |
LC_NUMERIC |
unset | 必填 |
LC_TIME |
unset | 必填 |
LD_LIBRARY_PATH |
以冒号分隔的包含共享库的目录列表 | 可选 |
JAVA_RUNFILES |
$TEST_SRCDIR 的值 |
已弃用 |
LOGNAME |
$USER 的值 |
必填 |
PATH |
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:. |
推荐 |
PWD |
$TEST_SRCDIR/workspace-name |
推荐 |
SHLVL |
2 |
推荐 |
TEST_INFRASTRUCTURE_FAILURE_FILE |
可写目录中某个私有文件的绝对路径(此文件 只能用于报告 而非作为报告不稳定故障的一般机制 测试。在这种情况下,测试基础设施就是系统 或并非特定于测试但可能会导致测试失败的库 出现故障。第一行是测试基础架构的名称 第二个组件是人类可读的 失败的说明。其他行会被忽略)。 | 可选 |
TEST_LOGSPLITTER_OUTPUT_FILE |
可写目录中私有文件的绝对路径(用于写入 Logsplitter 协议缓冲区日志) | 可选 |
TEST_PREMATURE_EXIT_FILE |
可写目录中私有文件的绝对路径(用于
捕获对 exit() 的调用) |
可选 |
TEST_RANDOM_SEED |
如果使用 --runs_per_test 选项,
TEST_RANDOM_SEED 设置为 run number
(从 1 开始)。 |
可选 |
TEST_RUN_NUMBER |
如果使用 --runs_per_test 选项,
TEST_RUN_NUMBER 设置为 run number
(从 1 开始)。 |
可选 |
TEST_TARGET |
要测试的目标的名称 | 可选 |
TEST_SIZE |
测试 size |
可选 |
TEST_TIMEOUT |
测试 timeout (以秒为单位) |
可选 |
TEST_SHARD_INDEX |
分片索引(如果使用了 sharding ) |
可选 |
TEST_SHARD_STATUS_FILE |
要触摸的文件路径,用于表示支持 sharding |
可选 |
TEST_SRCDIR |
runfiles 树基底的绝对路径 | 必填 |
TEST_TOTAL_SHARDS |
总计
shard count ,
如果使用 sharding |
可选 |
TEST_TMPDIR |
私有可写目录的绝对路径 | 必填 |
TEST_WORKSPACE |
本地代码库的工作区名称 | 可选 |
TEST_UNDECLARED_OUTPUTS_DIR |
私有可写目录的绝对路径(用于写入未声明的
测试输出)。任何写入到
TEST_UNDECLARED_OUTPUTS_DIR 目录将被压缩,
添加到outputs.zip 下
bazel-testlogs 。 |
可选 |
TEST_UNDECLARED_OUTPUTS_ANNOTATIONS_DIR |
私有可写目录的绝对路径(用于写入未声明的
测试输出注释 .part 和 .pb 文件)。 |
可选 |
TEST_WARNINGS_OUTPUT_FILE |
可写目录中私有文件的绝对路径(用于写入 测试目标警告) | 可选 |
TESTBRIDGE_TEST_ONLY |
值
--test_filter ,
(如果指定) |
可选 |
TZ |
UTC |
必填 |
USER |
getpwuid(getuid())->pw_name 的值 |
必填 |
XML_OUTPUT_FILE |
测试操作应将测试结果 XML 输出文件写入到的位置。 否则,Bazel 会生成封装测试日志的默认 XML 输出文件 作为测试操作的一部分。XML 架构基于 JUnit 测试结果架构。 | 可选 |
BAZEL_TEST |
表示测试可执行文件由 bazel test 驱动 |
必填 |
环境可能包含其他条目。测试不应依赖于 上面未列出的任何环境变量的存在、缺失或值。
初始工作目录应为 $TEST_SRCDIR/$TEST_WORKSPACE
。
当前的进程 ID、进程组 ID、会话 ID 和父级进程 ID 为 未指定。该进程不一定是进程组领导者或会话 主要副本。该进程不一定有控制终端。该过程可能会 具有零个或零个或多个正在运行或未回收的子进程。该过程不应 当测试代码获得控制权时,有多个线程。
文件描述符 0 (stdin
) 应处于开放状态以供读取,但它被附加到
未指定参数。测试不得从中读取数据。文件描述符 1 (stdout
) 和 2
(stderr
) 应开放写入,但附加的内容为
未指定。它可以是终端、管道、常规文件
可以写出哪些字符。他们可能会共享打开文件表中的条目
(这意味着它们不能独立寻找)。测试不应继承任何
其他打开的文件描述符
初始 umask 应为 022
或 027
。
不应有闹铃或间隔计时器。
被屏蔽信号的初始掩码应为空。所有信号均应设置为 执行默认操作。
初始资源限制(包括软资源限制和硬资源限制)应按如下方式设置:
资源 | 限制 |
---|---|
RLIMIT_AS |
无限制 |
RLIMIT_CORE |
未指定 |
RLIMIT_CPU |
无限制 |
RLIMIT_DATA |
无限制 |
RLIMIT_FSIZE |
无限制 |
RLIMIT_LOCKS |
无限制 |
RLIMIT_MEMLOCK |
无限制 |
RLIMIT_MSGQUEUE |
未指定 |
RLIMIT_NICE |
未指定 |
RLIMIT_NOFILE |
至少 1024 |
RLIMIT_NPROC |
未指定 |
RLIMIT_RSS |
无限制 |
RLIMIT_RTPRIO |
未指定 |
RLIMIT_SIGPENDING |
未指定 |
RLIMIT_STACK |
无限制,或 2044KB <= rlim <= 8192KB |
初始进程时间(由 times()
返回)和资源利用率
(由 getrusage()
返回)。
未指定初始调度政策和优先级。
主机系统的角色
除了测试直接控制的用户情境的各个方面之外, 运行程序,执行测试的操作系统必须满足 属性。
文件系统
测试观察到的根目录不一定是真实的根目录。
应装载 /proc
。
所有构建工具都应位于/usr
本地安装
以 /home
开头的路径可能不可用。测试不应访问任何
此类路径
/tmp
应可写入,但测试应避免使用这些路径。
测试不得假设任何常量路径可用于其专有 。
测试不得假设已为任何已装载的文件系统启用 atime。
用户和组
users root、nobody 和 unittest 必须存在。群组 root、nobody 和 eng 必须存在。
测试必须以非根用户的身份执行。真实有效的用户 ID 必须 相等;同样地,也适用于群组 ID。除此之外,当前的用户 ID、群组 ID、 用户名和群组名称均未指定补充的群组 ID 集合为 未指定。
当前的用户 ID 和组 ID 必须有相应的名称,
使用 getpwuid()
和 getgrgid()
进行检索。对于
补充的群组 ID。
当前用户必须有一个主目录。可能无法写入。测试必须 请勿尝试对其执行写入操作。
网络
未指定主机名。它不一定包含点。解决 主机名必须提供当前主机的 IP 地址。解决主机名剪切的问题 第一个点之后的结果也必须有效。localhost 必须解析主机名。
其他资源
测试至少被授予一个 CPU 核心。其他可能可用,但不可用 。未指定此核心的其他性能方面。您可以 通过添加标记将预留增加到更多 CPU 核心数 "cpu:n"(其中 n 为正数)。如果机器的 CPU 核心总数超过请求的 CPU 核心数,则 Bazel 仍会运行测试。如果测试使用 sharding 表示,每个分片都会预留一些 CPU 核心机器类型
测试可以创建子进程,但不能处理组或会话。
测试可使用的输入文件数量是有限制的。此限制为 可能会有变化,但目前在数万个输入范围内。
时间和日期
未指定当前时间和日期。未指定系统时区。
X Windows 可能可用,也可能不可用。需要 X 服务器的测试应启动 Xvfb。
测试与文件系统的交互
测试环境变量中指定的所有文件路径均指向 本地文件系统(除非另有说明)。
测试应仅在
$TEST_TMPDIR
和 $TEST_UNDECLARED_OUTPUTS_DIR
(如果已设置)。
这些目录最初为空。
测试不得尝试移除、chmod 或以其他方式更改这些目录。
这些目录可能是符号链接。
$TEST_TMPDIR/.
的文件系统类型仍然未指定。
测试还可以将 .part 文件写入
$TEST_UNDECLARED_OUTPUTS_ANNOTATIONS_DIR
,用于为未声明的输出文件添加注释。
在极少数情况下,测试可能会强制在 /tmp
中创建文件。例如:
Unix 网域套接字的路径长度限制
通常需要在 /tmp
下创建套接字。Bazel 将无法
跟踪此类文件;测试本身必须要注意封闭
避免与其他(同时运行测试和非测试)发生冲突的路径
进程,以及清理它在 /tmp
中创建的文件。
一些常用的测试框架,例如
JUnit4 TemporaryFolder
或 Go TempDir
,
用自己的方式在 /tmp
下创建临时目录。这些测试
框架包含清理 /tmp
中的文件的功能,因此您可以使用
即使他们在 TEST_TMPDIR
之外创建文件,也是如此。
测试必须通过 runfiles 机制或其他部分 执行环境, 可用。
测试不得在从以下推断出的路径中访问构建系统的其他输出: 自己的可执行文件的位置
不指定 runfiles 树是否包含符号
链接或两者的组合。runfiles 树可能包含指向目录的符号链接。
测试应避免在 runfile 中使用包含 ..
组成部分的路径
树。
runfiles 树中没有任何目录、文件或符号链接(包括
遍历符号链接)。(因此,最初的工作是
目录。)测试不得假定
runfiles 可写,或归当前用户所有(例如,chmod
和 chgrp
可能
失败)。
Runfiles 树(包括遍历符号链接的路径)不得更改 。不得更改父级目录和文件系统装载 以任何方式影响运行文件中某个路径的解析结果 树。
为了捕获提前退出,测试可能会在由
在启动时调用 TEST_PREMATURE_EXIT_FILE
,并在退出时将其移除。如果 Bazel
文件,则会认为测试过早退出,
将其标记为已失败
代码规范
测试规则中的某些代码具有特殊含义。另请参阅
tags
属性的 Bazel 构建百科全书。
标记 | 含义 |
---|---|
exclusive |
不同时运行其他测试 |
external |
测试具有外部依赖项;停用测试缓存 |
large |
test_suite 惯例;大型测试套件 |
manual * |
请勿在通配符目标格式中包含测试目标,例如
:... 、:* 或 :all |
medium |
test_suite 惯例;中型测试套件 |
small |
test_suite 惯例;一套小型测试 |
smoke |
test_suite 惯例;意味着它应该在
将代码更改提交到版本控制系统 |
Runfile
在下例中,假设有一条 *_binary() 规则,
//foo/bar:unittest
,运行时依赖于标记为
//deps/server:server
。
位置
目标 //foo/bar:unittest
的 runfiles 目录
$(WORKSPACE)/$(BINDIR)/foo/bar/unittest.runfiles
。该路径称为
runfiles_dir
。
依赖项
将 runfiles 目录声明为
*_binary()
规则。runfiles 目录本身依赖于 BUILD 文件集
影响 *_binary()
规则或其任何编译时或运行时的文件
依赖项修改源文件不会影响
runfiles 目录,因此不会触发任何重新构建。
目录
runfiles 目录包含以下内容:
- 指向运行时依赖项的符号链接:
是
*_binary()
规则的运行时依赖项,由 runfiles 目录符号链接的名称为$(WORKSPACE)/package_name/rule_name
。例如,服务器的符号链接 将命名为$(WORKSPACE)/deps/server/server
,而完整路径将为$(WORKSPACE)/foo/bar/unittest.runfiles/$(WORKSPACE)/deps/server/server
。 符号链接的目标是 OutputFile 或 CommandRule,表示为绝对路径。因此, 符号链接可能是$(WORKSPACE)/linux-dbg/deps/server/42/server
。 - 子运行时的符号链接:针对运行时的每个
*_binary()
Z*_binary()
C 的依赖项,则 runfile 中还有第二个链接 复制到 Z 的 runfile 中。符号链接的名称为$(WORKSPACE)/package_name/rule_name.runfiles
。符号链接的目标为 runfiles 目录例如,所有子程序共享一个 目录。