``` cmd/go: 测试缓存在修改testdata子目录时未失效 ```

tquggr8v  于 4个月前  发布在  Go
关注(0)|答案(9)|浏览(36)

你正在使用的Go版本是什么( go version )?

$ go version
go version go1.18.2 linux/amd64

这个问题在最新版本中是否重现?

是的

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/fhenneke/.cache/go-build"
GOENV="/home/fhenneke/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/fhenneke/go/pkg/mod"
GONOPROXY="code-intelligence.com/*"
GONOSUMDB="code-intelligence.com/*"
GOOS="linux"
GOPATH="/home/fhenneke/go"
GOPRIVATE="code-intelligence.com/*"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.18.2"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/fhenneke/git/cifuzz/go.mod"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2057125203=/tmp/go-build -gno-record-gcc-switches"

你做了什么?

  1. 进行一些访问包含子目录 subdir 的测试数据,该子目录包含一个文件 foo
  2. 运行 go test ./...
  3. 更改 foo
  4. 运行 go test ./...

你期望看到什么?

由于数据依赖项发生了变化,尽管启用了缓存,测试仍会重新运行。

你看到了什么?

测试没有再次运行。

根本原因

test.go 中的缓存失效逻辑列出了 testdata 中的所有条目,并在 go/src/cmd/go/internal/test/test.go 的第 1737 行调用 hashWriteStat 对它们进行操作(在这种情况下,对 testdata/subdir 进行操作)。此函数记录了 stat 的结果,包括目录的 mtime。但是,当它包含的任何文件发生更改时,目录的 mtime 不会更新。
相反,逻辑可以对目录进行完整的递归遍历,收集其内容的各个 mtime。

bihw5rsg

bihw5rsg1#

你如何在测试中使用文件?如何修改文件?
我无法重现描述的行为

fcipmucu

fcipmucu2#

你是如何使用tests/目录下的文件的?我无法复现描述的行为
在我原来的示例中,我在访问Go测试的testdata目录后,在testdata目录上运行一个外部工具。我将这个简化为一个复现器:

  1. 克隆 https://github.com/fmeum/go-53053
  2. 运行 ./test.sh
jqjz2hbq

jqjz2hbq3#

我看到数据的读取是通过一个外部命令(exec.Command(bash, -c, cat file))进行的,这就是为什么更改没有被跟踪的原因。

wztqucjr

wztqucjr4#

确实如此。一般来说,Go测试过程必须接触到所有应该用作缓存输入的数据,因为它没有其他程序的仪器。

jmo0nnb3

jmo0nnb35#

确实。一般来说,Go测试过程必须接触到所有应该用作缓存输入的数据,因为它没有其他程序的仪器。我不指望Go只捕获外部工具触及的文件的更改。让我感到惊讶并导致我打开这个问题的是,从Go测试中触及一个目录会导致某些该目录内容的更改,从而使缓存失效,但不是所有这样的更改。

8yoxcaq7

8yoxcaq76#

我认为我们在这里可能最好做的是提供一些库函数,这些函数可以处理当前包(https://go.dev/play/p/cnjP1PbosLa)中testdata子目录下的所有文件。也许在默认情况下,这对testing包是有意义的?

shstlldc

shstlldc7#

让我感到惊讶并引发我提出这个问题的是,从Go测试结果中触摸一个目录会导致该目录内容的某些更改,从而使缓存失效,但并非所有这样的更改都会使缓存失效。
如果(并且仅当)更改了由Go测试进程调用的函数的结果,那么更改应该使缓存失效。我同意,当涉及到子进程时,这有时会令人惊讶。 😅

bfhwhh0e

bfhwhh0e8#

我认为我们在这里可能最好做的是提供一些库函数,这些函数可以处理当前包(https://go.dev/play/p/cnjP1PbosLa)中testdata子目录下的所有文件。也许在testing包中默认这样做是有意义的?
这听起来很好。这正是我采用的解决方法(当然,除了为testing启用此功能默认值之外;-))

ivqmmu1c

ivqmmu1c9#

或者只有当使用exec时才可能?这听起来像是一项非常昂贵的操作,尤其是如果有一个仅供外部工具使用的深层层次结构。

相关问题