Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests in main package don't work with GO111MODULE=on #28514

Closed
onitake opened this issue Oct 31, 2018 · 11 comments

Comments

Projects
None yet
3 participants
@onitake
Copy link

commented Oct 31, 2018

What version of Go are you using (go version)?

go version go1.11.1 linux/amd64

After initially encountering the issue, I reproduced it with the official golang:1.11-alpine Docker container.

Does this issue reproduce with the latest release?

Yes, it is Go 1.11 specific.
I didn't test with a development build directly from the Git tree.

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/root/test/go.mod"
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 -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build838179380=/tmp/go-build -gno-record-gcc-switches"

What did you do?

The following is a minimal test case that doesn't actually use any external modules.

It fails in exactly the same way if the source file imports other modules that are not part of the Go distribution. It is also not relevant if go build or go tidy were ran beforehand.

Create x_test.go with the following contents, in a directory outside the GOPATH:

package main
import "testing"
func TestMain(t *testing.T) {
        t.Log("Test successful")
}

Create a placeholder go.mod file:

module main

Run the test without Go module support:

$ GO111MODULE=off go test
PASS
ok      _/root/test     0.001s

Run the test with Go 1.11 module support:

$ GO111MODULE=on go test
# main.test
/tmp/go-build011410304/b001/_testmain.go:12:2: cannot import "main"
FAIL    main [build failed]

What did you expect to see?

That the test would succeed in both cases, with or without module support.

What did you see instead?

The compiler complains about a missing main package when GO111MODULE=on is set:

# main.test
/tmp/go-build011410304/b001/_testmain.go:12:2: cannot import "main"
FAIL    main [build failed]
@bcmills

This comment has been minimized.

Copy link
Member

commented Oct 31, 2018

When you run the test using GO111MODULE=off, the effective import path is the relative path from your GOPATH root. (I'm not sure what the effective import path is outside of GOPATH, but I'm guessing it's not just main.)

When you run the test using GO111MODULE=on, the effective import path is whatever the go.mod file declares it to be.

So, what happens if your go.mod file declares a real module path rather than module main?

@onitake

This comment has been minimized.

Copy link
Author

commented Oct 31, 2018

The "real" module path in this case is package main: I'm working on an application rather than a Go module, and I want to keep a bunch of test cases alongside the application to test various features.
During development, the source code is actually in a valid location on the GOPATH, but when running CI tests, I'd rather not have to reproduce the whole project path on the build server.

If this is an unsupported use case, I can live with that; in that case I'll have to reorganise the project a bit.

But it strikes me as very odd that it won't work this way, as one of the points of Go module management is that a project doesn't have to live inside the Go path to be built (and perhaps tested).

@bcmills

This comment has been minimized.

Copy link
Member

commented Oct 31, 2018

The module path is a prefix of the package import path. The first component of the module path should always be a name that you control — typically a domain name.

You don't have to reproduce the whole GOPATH to run tests in module mode. All you need is the module that you want to build, with a go.mod file declaring the correct module path. (The final name of the package is <module path>/<relative path within module>.)

@onitake

This comment has been minimized.

Copy link
Author

commented Nov 1, 2018

So you're saying I should put my tests on the $GOPATH/my.package/prefix, then run go test my.package/prefix, and it will work even though the package is called "main"?
Ok, I can try that.

But still: I don't see why it shouldn't work otherwise. It did without enabling Go module handing, and go build works fine too.

@onitake

This comment has been minimized.

Copy link
Author

commented Nov 5, 2018

After experimenting some more, I don't think your suggestion is the right solution.
As stated before, I'm building an application where all source code is in the main package, as are tests related to the application. Putting a prefix in front of the package makes no sense.
I also tested a few other go tools, and the only one that doesn't support this use case is go test.

So: Instead of discussing on how to use go tools correctly, could we focus on why go test tries to import the main package from an invalid location?

@onitake

This comment has been minimized.

Copy link
Author

commented Nov 6, 2018

Ok, it seems I simply misunderstood what you meant and what the documentation said.
I was under the impression that the module would have the same name as the package.

The error went away when I replaced the package name (main) in go.mod with the module path (my/project).
Now I can build and test out-of-tree without problems.
It's just a bit confusing that every other go tool except go test works with the incorrect module path.

Anyway, thanks for the help!

@onitake onitake closed this Nov 6, 2018

@grantbow

This comment has been minimized.

Copy link

commented Jan 4, 2019

Thank you for the questions and explanations above. I have been struggling with this same problem. I forked a project on github. I am using go.mod files to adjust the submodule names for the fork I'm editing.

I found a bunch of older explanations that all pointed to using 'module main' in main.go and main_test.go. I set go.mod to the the same module main. Using GO111MODULE=on go build was fine but go test failed. Then in go.mod I had to change from 'module main' to 'module github.com/grantbow/'project'/main' and it worked!

So with go.mod set to module main go build will find the module path (github.com/grantbow/'project' for me) and module name (main for me) and join them with a / like it does with main.go and main_test.go. So go.mod fails running go testbecause it does not find it's own location? We need to specify the module differently in go.mod from main.go and main_test.go? Isn't that a bug?

@onitake

This comment has been minimized.

Copy link
Author

commented Jan 6, 2019

Not a bug. If anything, the documentation is a bit misleading if you don't pay close attention.

You need to take into account that package name and module name are two different things in Go. That's not a new thing in 1.11, it has been like this forever.

What you import is the module, but what you use as namespace is the package.
For example, you would

import "net/http"

but

http.ListenAndServe(":80", nil)

Mind that the import namespace can be changed at import time, so the package name would only provide a default if nothing is specified.

In go.mod, you would name the module, while the package statements in each source file would name the package.

@bcmills

This comment has been minimized.

Copy link
Member

commented Jan 7, 2019

You need to take into account that package name and module name are two different things in Go.
[…]
What you import is the module, but what you use as namespace is the package.

@onitake, to be clear, there are actually three things involved here: the module path, the package import path, and the package name.

The module path is a prefix of the package import path, for every package in that module.

The package name is conventionally the last component of the package import path, possibly omitting a /vN suffix, but can be any arbitrary identifier. (See also proposal #29036.)

@grantbow

This comment has been minimized.

Copy link

commented Jan 18, 2019

It still feels something is wrong or I am missing something. If go build works then go test should work. Why should the two tools require something different? Which part of what documentation is a bit misleading and needs a close reading?

@bcmills

This comment has been minimized.

Copy link
Member

commented Jan 25, 2019

go build works with the module named main because nothing ends up importing the resulting package.

go test does not work because the generated test package needs to import the package under test in order to actually run the tests.

The relevant documentation is in https://golang.org/doc/code.html#ImportPaths:

The packages from the standard library are given short import paths such as "fmt" and "net/http". For your own packages, you must choose a base path that is unlikely to collide with future additions to the standard library or other external libraries.

yanzay added a commit to yanzay/tbot that referenced this issue Jun 15, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.