如何使用提供的工具而不是规则构建的工具编写 Bazel 测试规则?



我有一个测试工具(大致是一个差异工具(,它接受两个输入,并返回一个输出(两个输入之间的差异(和一个返回代码(如果两个输入匹配,则为 0,否则为 1(。它是在 Kotlin 中构建的,在我的存储库中//java/fr/enoent/phosphorus可用。

我想编写一个规则来测试由某些内容生成的文件是否与存储库中已存在的参考文件相同。我尝试了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并依赖它的返回代码,但它似乎不是一个选项,因为测试显然需要生成可执行文件。编写这样一条规则的正确方法是什么?

事实证明,生成脚本是正确的方法,据我所知(不可能返回某种指向ctx.actions.run的指针。测试规则需要具有可执行输出。

关于该工具生成的输出文件:根本不需要声明它。我只需要确保它是在$TEST_UNDECLARED_OUTPUTS_DIR中生成的.此目录中的每个文件都将添加到 Bazel 名为output.zip的存档中。这(部分(记录在这里。

关于运行文件,好吧,我有该工具的二进制文件,但没有它自己的运行文件。这是固定规则:

def _phosphorus_test_impl(ctx):
script = phosphorus_compare(
ctx,
reference = ctx.file.reference,
comparison = ctx.file.comparison,
out = "%s.phs" % ctx.label.name,
)
ctx.actions.write(
output = ctx.outputs.executable,
content = script,
)
return [
DefaultInfo(
runfiles = ctx.runfiles(
files = [
ctx.executable._phosphorus_tool,
ctx.file.reference,
ctx.file.comparison,
],
).merge(ctx.attr._phosphorus_tool[DefaultInfo].default_runfiles),
executable = ctx.outputs.executable,
),
]
def phosphorus_test(size = "small", **kwargs):
_phosphorus_test(size = size, **kwargs)
_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 = "target",
),
},
doc = "Compares two files, and fails if they are different.",
test = True,
)

在返回的DefaultInfo.merge(ctx.attr._phosphorus_tool[DefaultInfo].default_runfiles)的关键部分。

我还在配置上犯了一个小错误,因为此测试旨在在目标配置上运行,而不是在主机上运行,它已相应地修复。

最新更新