我有一个测试工具(大致是一个差异工具),它接受两个输入,并返回一个输出(两个输入之间的差异)和一个返回码(如果两个输入匹配,则返回 0,否则返回 1)。它是用 Kotlin 构建的,可以//java/fr/enoent/phosphorus
在我的 repo 中找到。
我想编写一个规则来测试某个东西生成的文件是否与存储库中已经存在的参考文件相同。我尝试了一些东西ctx.actions.run
,问题是我的规则已经test = True
设置,需要返回由该规则构建的可执行文件(因此不是为规则提供的工具)。然后,我尝试按照示例将其包装在 shell 脚本中,如下所示:
def _phosphorus_test_impl(ctx):
output = ctx.actions.declare_file("{name}.phs".format(name = ctx.label.name))
script = phosphorus_compare(
ctx,
reference = ctx.file.reference,
comparison = ctx.file.comparison,
out = output,
)
ctx.actions.write(
output = ctx.outputs.executable,
content = script,
)
runfiles = ctx.runfiles(files = [ctx.executable._phosphorus_tool, ctx.file.reference, ctx.file.comparison])
return [DefaultInfo(runfiles = runfiles)]
phosphorus_test = rule(
_phosphorus_test_impl,
attrs = {
"comparison": attr.label(
allow_single_file = [".phs"],
doc = "File to compare to the reference",
mandatory = True,
),
"reference": attr.label(
allow_single_file = [".phs"],
doc = "Reference file",
mandatory = True,
),
"_phosphorus_tool": attr.label(
default = "//java/fr/enoent/phosphorus",
executable = True,
cfg = "host",
),
},
doc = "Compares two files, and fails if they are different.",
test = True,
)
(phosphorus_compare
只是一个生成实际命令的宏。)
但是,这种方法有两个问题:
- 不能以这种方式声明输出。它与任何行动都没有关联(Bazel 正在抱怨它)。也许我真的不需要为测试声明输出?测试失败时,Bazel 是否使测试文件夹中的任何内容可用?
- 运行该工具所需的运行文件似乎在测试运行时不可用:
java/fr/enoent/phosphorus/phosphorus: line 359: /home/kernald/.cache/bazel/_bazel_kernald/58c025fbb926eac6827117ef80f7d2fa/sandbox/linux-sandbox/1979/execroot/fr_enoent/bazel-out/k8-fastbuild/bin/tools/phosphorus/tests/should_pass.runfiles/remotejdk11_linux/bin/java: No such file or directory
总的来说,我觉得使用 shell 脚本只是添加了不必要的间接性,并丢失了一些上下文(例如工具的运行文件)。理想情况下,我只会使用ctx.actions.run
并依赖它的返回代码,但它似乎不是一个选项,因为测试显然需要生成可执行文件。编写这样一条规则的正确方法是什么?