Go version
go1.24.5 windows/amd64
Output of go env
in your module/workspace:
*(pathnames slightly redacted)*
set AR=ar
set CC=gcc
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_ENABLED=0
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set CXX=g++
set GCCGO=gccgo
set GO111MODULE=
set GOAMD64=v1
set GOARCH=amd64
set GOAUTH=netrc
set GOBIN=
set GOCACHE=C:\Users\MyUser\AppData\Local\go-build
set GOCACHEPROG=
set GODEBUG=
set GOENV=C:\Users\MyUser\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFIPS140=off
set GOFLAGS=
set GOGCCFLAGS=-m64 -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\MyUser\AppData\Local\Temp\go-build3111314214=/tmp/go-build -gno-record-gcc-switches
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMOD=D:\Stuff\Thingy\go.mod
set GOMODCACHE=C:\Users\MyUser\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\MyUser\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTELEMETRY=local
set GOTELEMETRYDIR=C:\Users\MyUser\AppData\Roaming\go\telemetry
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.24.5
set GOWORK=
set PKG_CONFIG=pkg-config
What did you do?
Ran a go test using -o
for a directory:
go test -o ..\GoTests\ .\stringutils\
What did you see happen?
Upon first run after having made changes, the test executable runs from within my standard temp directory, not from within the directory that I specified using -o
.
Upon further runs (until the next time changes have been made), the test executable runs from within the directory that I specified using -o
.
What did you expect to see?
The test executable should always run from within the directory that I specified using -o
.
EXPLANATION OF WHY I NOTICED THIS AND WHY IT MATTERS TO ME:
My antivirus program seems to be detecting any Go test executable as malware. With the default location, I can't effectively whitelist them, as they are created within a randomized directory (like %APP_DATA%\Local\Temp\go-build13853487
).
I thought that -o
would let me get around this, since I could make a blanket whitelist entry for all things within the directory I specified. This does help, as every time I run it other than the first time after having made changes, it runs from the directory I specified. But every single time I first run tests after having made some sort of change, my antivirus complains.
Incidentally, when this happens, go test
reports "ok", even if I introduce intentional errors in the test cases. I assume this is due to the antivirus having prevented the executable from running, and "go test" thus having seen zero test failures. Seems dangerously misleading, but I guess that's an issue for another bug report.
Comment From: gabyhelp
Related Issues
- How to specify `go test` to build and run executable in exact folder but not random folder #49238 (closed)
- `go test` breaks when working directory is outside of `go.mod` hierarchy even though argument path is inside module directory #47363 (closed)
- testing: TestChdir can fail on Windows when GOROOT and TMPDIR are on different drives #69159 (closed)
- cmd/go: invoking go run from go test can corrupt build cache #69566
- go test cache check wrong opened file when testing if user do `os.Chdir` #47305 (closed)
- cmd/go: build_trimpath test doesn't correctly test executable reproducibility #35435 (closed)
- x/tools/gopls: incorrect absolute test failure path reported through deferred helper func #69252
- testing: test failes if leaving files without write permission in T.TempDir #40853
- testing: go test -n is missing the creation of _testmain.go #66592
- os: TestFileChdir fail when GOROOT is a symbolic link #64281 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: thediveo
does the same happen when in wsl2?
Comment From: rwv37
Sorry, I don't know. I'll try to remember to give it a try when I get a chance.
Comment From: dolmen
You say "sometimes". Can you reproduce your issue always after go clean ./stringutils
?
Comment From: rwv37
I did not say "sometimes". I assume you're referring to the title, which is currently "cmd/go: test -o sometimes invokes test executable from build cache". The title was changed by another user. The original title was "import/testing: "go test -o" does not always respect specified directory".
With that said, I have literally never once seen the behavior I described not happen. However, I have not tried using go clean
before doing so (and to be clear, this is for more than just the one stringutils
package that I mentioned in the example). Again, I will try when I get a chance.
Comment From: rwv37
go clean
doesn't seem to have an effect on the behavior I described. However, while trying this, I noticed something which seems weird and which may be of interest (again, whether I used go clean
or not is irrelevant to this):
If I change the code by adding in a new test that succeeds, I've never seen it not get flagged (on first run) by my antivirus software. However, if I change the code by adding in a new test that fails, I have never seen it get flagged (at least not today; not sure about previously).
Comment From: matloob
As it is now, the go command doesn't make any guarantees about the path of the binary the test is run from. go test -o
will produce the executable file for the test at the specified location, but it runs the test binary that was produced by the previous build action.
The behavior that you're seeing where the binary is sometimes being run from the -o
location is a bit of an accident due to the way the go command caches the action of building the test's executable binary:
The first time go test -o
is run, the go command will check to see if the file specified by -o
already exists, and if the binary was already produced for the same inputs and action (that is, that the action id matches that for the binary it wants to produce). Because the file doesn't exist, the go command will rebuild the test in the randomized temporary directories you noticed, and satisfy the build of the test from the location. (A separate "install" action copies the binary from that temporary location to the location specified by -o
). Any subsequent time, if the file pointed to by the -o
argument already exists, and the inputs haven't changed, so that the hash matches, the build of the test binary is satisfied using that binary, so that binary will be run. And if the source files are changed, the hash won't match again, causing a rebuild, and for the file from the temporary directory to be used.
One option, if you're okay running any output of the go command, and if your antivirus can whitelist directories recursively, is to set the GOTMPDIR environment variable to a predetermined directory that's been recursively whitelisted by your antivirus.
The go command does the builds of its intermediate action outputs in that directory.
Comment From: rwv37
At the very least, then, go help test
is extremely misleading, and should be updated:
-o file
Compile the test binary to the named file.
The test still runs (unless -c or -i is specified).
If file ends in a slash or names an existing directory,
the test is written to pkg.test in that directory.
Strictly speaking, yeah, it doesn't say it will be run from the specified directory. But given that it says it will be run, and that it will be compiled to the specified directory, I tend to think that "It will be compiled to somewhere random, copied to the specified directory, and run from the random place" is -- at best -- an utterly unnatural interpretation of what it does say.
Comment From: matloob
I don't get that impression reading the text, but I my reading of it might be affected by my knowledge of what the implementation does. I can say that the text of the help message wasn't intend to imply anything about where the test binary is run from, so we may want to adjust the wording of the message.
(edit: adding a suggestion) How's this:
Run the test (unless -c or -i is specifed), but
also output the test binary to the named file.
If file ends in a slash or names an existing directory,
the test is written to pkg.test in that directory.
Comment From: thediveo
Not convinced of the proposed change; how about a very upfront and clear "Run the test binary inside a temporary(?) directory that differs from the output directory where the test binary will additionally be copied to."
Just brutal truth.
Comment From: rwv37
I mean, from a non-insider point of view, this seems pretty absurd, frankly; I genuinely have no idea why anyone would actually want the current behavior. But ignoring that:
I mostly agree with @thediveo - if the solution to this is to be "adjust the docs to conform to the wacky behavior" rather than "change the wacky behavior to not be wacky", then the docs should try to be as clear as possible about the wacky behavior. The modification to the docs suggested by @matloob just seems like shuffling the words around to me, not actually clarifying the underlying wackiness, i.e. that the executable that you "output" will not necessarily be the executable that is executed.
I said that I mostly agree with @thediveo because while I agree with their general idea, I feel their specific proposed wording isn't entirely accurate; the tests are only sometimes run from a temporary directory.
Comment From: seankhliao
I suggest:
- Compile the test binary to the named file.
+ Save a copy of the test binary to the named file.
Comment From: rwv37
Again, I think that if the solution to this is going to be "change the wording of the documentation to describe the weird behavior" rather than "make the behavior not weird in the first place", then the wording should be very explicit about the weirdness. It should explicitly point out, not vaguely but in no uncertain terms, that the test executable that you specify will not be the test executable that is actually executed.
With that said: Again, I don't actually understand why anyone would actually want the current behavior in the first place. I am willing to believe that someone would, for some reason, but I have no idea what that reason would be, nor do I have any idea why anyone would actually prefer it to running the executable that they specified. So, given that lack of understanding of mine, "change the wording of the documentation to describe the weird behavior" seems, to me, to be Kafkaesque.