Go Wiki:Watchflakes
Watchflakes 是一个程序,用于对 build.golang.org 仪表板上的明显测试缺陷进行分类。
明显的测试缺陷是指
- 不在完全失败的构建器上。
- 不在 排除的构建器 上。
- 未运行在 4 个或更多构建器上失败的提交上。
- 不是其构建器上 4 个或更多失败提交运行的一部分。
Watchflakes 将每个明显的测试缺陷发布到 测试缺陷项目 中的问题中。
测试缺陷项目中的每个问题描述都以与该问题相关的失败模式开头:例如,#55260 的描述的标记语言以
```
#!watchflakes
post <- pkg == "cmd/go" && test == "" && `unexpected files left in tmpdir`
```
Watchflakes 将每个明显的测试缺陷与问题中的模式进行匹配
- 如果一个 flake 匹配某个 issue 中的模式,它会被发布到该 issue。
- 如果一个 flake 匹配多个 issue 中的模式,它会被发布到编号最低的 issue。
- 如果一个 flake 不匹配任何 issue 中的模式,watchflakes 会创建一个新的 issue,其中包含与失败的包和测试用例匹配的模式。
新创建的 issue 的模式通常过于宽泛,应该对其进行编辑,使其更具体地针对实际故障。将故障发送到编号最低的匹配 issue 可以确保为新故障创建宽泛的默认模式不会“窃取”早期 issue 的故障,也不会向新 issue 发送同一测试中已单独跟踪的不相关故障。
Watchflakes 将新创建的 issue 放入 Test Flakes 项目,并添加 NeedsInvestigation 标签。这些 issue 最初没有状态(不是 Active,也不是 Done)。没有状态的 issue 需要由人来检查,通常应该优化模式以捕获有关故障的重要信息。已检查的 issue 随后可以移至 Active。当 issue 关闭时,GitHub 会自动将 issue 从 Active 移至 Done。
Watchflakes 在匹配新故障时会考虑任何状态的 issue。如果它为已关闭的 issue 找到新故障,它将发布该故障并重新打开该 issue。因此,当修复程序发布时,可以关闭 issue,而不必等待几周来查看故障是否真的消失了:如果出现新故障,该 issue 将自动重新打开。
Watchflakes 不维护自己的状态:所有状态都在 GitHub issue 中。每次运行时,它都会考虑过去 60 天的构建仪表板故障,并确保每个明显的 flake 都在 Test Flakes 项目中得到说明。如果与 issue 匹配的故障已发布到该 issue,watchflakes 当然不会再次发布它。如果编辑 issue 以更新其模式以排除某些故障,watchflakes 不会删除其旧帖子,但它会为这些故障寻找不同的匹配 issue,包括可能创建一个新的 issue。
语法
每个 issue 中的 watchflakes 节必须出现在 issue 描述的顶部。它必须是一个代码块(使用 ```
围起来或缩进),第一行必须是 #!watchflakes
,以防止 watchflakes 误解不相关的代码块。
该块的其余部分是一个小的 watchflakes 脚本。行尾注释以 #
引入。该脚本是一系列规则,每条规则都具有 action <- pattern
的形式(将模式匹配项发送到操作)。
操作
操作为
post
将失败发布到脚本出现的 issue 中。skip
忽略失败,将其抛到地上。此操作应仅在极少数情况下使用(例如,在 #55166 中设置策略)。default
是 post 的低优先级版本。如果某个 issue 具有与失败匹配的post
或skip
,watchflakes 会执行该操作。但如果没有其他匹配项,watchflakes 会考虑default
模式匹配。(然后,如果没有default
匹配项,watchflakes 会创建一个新 issue。)
记录
模式的输入是一个具有命名字段的记录,每个字段都有一个字符串值
-
pkg
是构建失败或测试失败的包的完整导入路径。 -
test
是包中失败的测试函数的名称。 -
mode
是build
或test
,具体取决于这是构建失败还是测试失败。 -
output
是失败测试的输出。此输出在测试二进制文件退出时打印的最终FAIL
行之前停止。它不包括在同一运行中也失败的其他测试用例的输出,也不包括测试开始前 all.bash 或 buildlet 打印的任何上下文。 -
log
是整个失败的构建日志。 -
snippet
是output
的缩写形式,它将发布到 issue 本身。匹配几乎总是应该使用output
代替。 -
builder
是运行测试的构建器的名称(如dragonfly-amd64-622
)。 -
repo
是正在测试的仓库的名称(go
、net
、tools
、…)。 -
goos
是 GOOS 值(linux
、windows
、…)。 -
goarch
是 GOARCH 值(amd64
、mips64le
、…)。 -
date
是正在测试的提交的日期,格式为2006-01-02T15:04:05
。没有日期比较逻辑;请改用字符串比较。应极少使用比较日期。 -
section
是失败发生的构建日志部分。在 all.bash 输出中,该部分由#####
引入,并且引导期间的每行Building
也被视为其自己的部分。在子仓库中,每行:: Running
都引入一个以正在运行的 go 命令命名的部分(例如go test golang.org/x/tools/...
)。大多数模式不需要使用
section
。它对主仓库中的测试最有用,该测试使用备用执行环境重新运行测试。
模式
模式是 Go 类语法中的布尔表达式,允许使用 ||、&&、!、( 和 ) 来构建复杂表达式;==、!=、<、<=、> 和 >= 用于比较字段与字符串文字;~ 和 !~ 用于与正则表达式匹配。
所有字符串比较都必须在左侧有一个字段名称,在右侧有一个双引号字符串文字,如 builder == "linux-amd64-alpine"
或 `goos == "
所有正则表达式匹配都必须在左侧有一个字段名称,在右侧有一个反引号字符串文字,如 builder ~ `corellium`
。
单独的反引号字符串文字被视为与 output
字段的比较,这适用于模式中绝大多数正则表达式。
示例
将所有这些放在一起,这里有一些示例脚本。
#!watchflakes
post <- pkg == "net/http" && test == "TestHandlerAbortRacesBodyRead"
55277 中的这个脚本是 watchflakes 自动创建的,以响应在 http.TestHandlerAbortRacesBodyRead 中失败的构建运行。引发问题创建的特定故障是超时。如果在该测试中发现更多具有不同根本原因的故障,则添加 && `panic: test timed out`
或进一步优化模式可能是合适的。
#!watchflakes
post <- goos == "openbsd" && `unlinkat .*: operation not permitted`
49751 中的这个脚本收集了 openbsd 上由 os.Remove 调用 unlinkat 导致的意外 EPERM 错误造成的故障。这些故障在各种测试中都会导致问题,因此对 pkg
或 test
没有条件。
#!watchflakes
post <- pkg ~ `^cmd/go` && `appspot.com.*: 503`
54608 中的这个脚本跟踪 cmd/go/… 包层次结构中任何测试中 appspot.com 的 503 响应的网络问题,而不仅仅是 cmd/go 本身。
#!watchflakes
post <- goos == "windows" &&
(`dnsquery: DNS server failure` || `getaddrinfow: This is usually a temporary error`)
55165 中的这个脚本匹配在运行 Windows 的构建器上任何测试中的特定 DNS 故障。
#!watchflakes
post <- builder == "darwin-arm64-12" && pkg == "" && test == ""
55312 中的这个脚本是 watchflakes 自动创建的,用于跟踪 darwin-arm64-12 构建器上在特定包测试运行之前发生的故障。
#!watchflakes
# note: sometimes the URL is printed with one /
default <- `(Get|read) "https://?(goproxy.io|proxy.golang.com.cn|goproxy.cn)`
55163 中的这个脚本匹配使用某些非标准 Go 代理的错误。它使用 default
允许其他问题解决由这些代理导致的更具体的故障。不匹配其他问题的故障转到 #55163,而不是创建分配给触发问题的特定测试的新问题。
#!watchflakes
default <- `: internal compiler error:`
55257 中的这个脚本匹配任何构建中的编译器故障,无论正在测试哪个包或仓库。它出于与上一个示例相同的原因使用 default
:以便仍然可以归档匹配特定编译器错误的问题,但与其他问题不匹配的故障被分组到 #55257 中,而不是创建分配给碰巧触发问题的特定测试的新问题。
此内容是 Go Wiki 的一部分。