Using modules with go test ./...

345 views
Skip to first unread message

John

unread,
Sep 20, 2018, 3:21:32 PM9/20/18
to golang-nuts
Just started playing with modules recently. Having an issue I don't understand, wondering if anyone has seen it, the few references to the error did not provide anything I saw relevant for what I'm doing.

given a directory structure such as:

<home>/go/
  src/
  pkg/
  bin/

GOPATH NOT SET
GO111MODULE = on

If the working directory is:
<home>/go/src/

go test ./...

Results in:
go: cannot determine module path for source directory /home/jdoak/go/src (outside GOPATH, no import comments)

This also occurs if I do:

go test subdir/subdir/packagedir/...

But it will work if I do:

working directory: <home>/go/src/subdir/subdir/packagedir/

go test ./...

I'm sure I'm doing something wrong.  If someone could enlighten me.

Scott Cotton

unread,
Sep 20, 2018, 5:15:18 PM9/20/18
to golang-nuts
I think you need to have a main module defined so there must be a go.mod in cwd or upwards in the directory tree, perhaps also with related .go files (not sure).

There are some issues such as this one where usage is confusing due to a lack of a main module.  They are marked needs fix and go1.1.2. I think your use case is related.  I haven't had a problem with that one because I just set up my workflow to run tests where there are go.mod files.

Best,
Scott

Dave Cheney

unread,
Sep 20, 2018, 5:54:27 PM9/20/18
to golang-nuts
I think because GOPATH is not set it is defaulting to $HOME/go (see Go 1.9 release notes, from memory). Try moving your code to another folder.

John

unread,
Sep 20, 2018, 7:13:23 PM9/20/18
to golang-nuts
Thanks for the link.

I did try the following:
  • Adding a main.go file and doing a go mod init, but that fails.
  • Just adding a go.mod file with "module main", which allowed compilation, but nothing else worked.
  • And of course, I added GOPATH back, but that didn't help (and I'm pretty sure I saw it was ignored if I turn modules on).
I could write workflow to only run tests if go.mod exists.  That seems to defeat the whole ./... argument to the tool.  I just was assuming that I've made a mistake somewhere in setting this up.  If that is not the case, I can certainly modify what I'm doing.  

John

unread,
Sep 20, 2018, 7:17:49 PM9/20/18
to golang-nuts
I think I missed something in this Dave.  Since my directory is already $HOME/go, isn't that what I'd want? Since my path is $HOME/go/...?  I found the reference in 1.8 release notes (I would not even have gotten close with a piece of trivia like that!).  

I did try to move it to another folder, even though I'm not sure why.  I just got different errors.

Dave Cheney

unread,
Sep 20, 2018, 7:26:37 PM9/20/18
to golang-nuts
Sorry, I probably wasn’t clear or didn’t understand that you were asking. I saw that you said GOPATH is not set, it because your code is inside $HOME/go, because of the rules of the default gopath introduced in 1.8, gopath IS actually set.

To be extra sure, when I’m playing with go modules I use a different directory for my experiments, ~/devel in my case, to avoid conflicts with explicit or implicit gopaths

John

unread,
Sep 20, 2018, 8:24:04 PM9/20/18
to golang-nuts
Gotcha.  Thanks Dave.

Well, looks like I'm going back to my old methods for the time being.  Thanks everyone!

Paul Jolly

unread,
Sep 21, 2018, 3:48:13 AM9/21/18
to w...@iri-labs.com, golan...@googlegroups.com
John,

Scott is on the money with this response:

> I think you need to have a main module defined so there must be a go.mod in cwd or upwards

The way to ensure that you are in a valid module context is simply:

go env GOMOD

which will return the path to the current (or main) module context (go.mod) if:

a) you are in module mode (either by being outside of GOPATH or with
GO111MODULE=on) and
b) there is a go.mod on the directory path from $PWD to the root.

As you have set GO111MODULE=on you can put your source code pretty
much anywhere you like; even within your GOPATH (whether GOPATH is set
or not, in the latter case as has been pointed out it defaults to
$HOME/go)

All you are missing is a go.mod file (go end GOMOD would confirm this,
and would return "")

Here's a simple example that shows things working within GOPATH:

$ export GO111MODULE=on
$ export GOPATH=/tmp/tmp.JJgvIDI0Uc
$ cd /tmp/tmp.In4INnkIH0
$ mkdir -p src/example.com/blah
$ cd src/example.com/blah/
$ cat <<EOD >main.go
package main
func main() {}
EOD
$ go env GOMOD

$ go list
go: cannot find main module; see 'go help modules'
$ go mod init example.com/blah
go: creating new go.mod: module example.com/blah
$ go env GOMOD
/tmp/tmp.In4INnkIH0/src/example.com/blah/go.mod
$ go list
example.com/blah
$ go test
? example.com/blah [no test files]


Paul

John

unread,
Sep 21, 2018, 11:31:44 AM9/21/18
to golang-nuts
Paul, thanks for the explanation.  But I think maybe either I'm missing something or I'm not explaining something correctly.

What I would expect with "go test ./..." is behavior similar to what I had before modules.  That behavior would be that the go tool would recursively run all tests from the directory I am in and below it, regardless if there was a package in the current directory. 

I built your example, which works exactly as you expect.  But it doesn't solve my issue, which is around "go test ./..." recursively.  As I go back up the hierarchy, if I do a go test ./..., it fails.  I could always test by just going into the package and running "go test".  I want to be able to recursively run tests as the current behavior allows with GOPATH.  If this recursive use of "./..." is going away with mod files, then I have to adjust to making smart tools.  But I've got to imagine that this isn't the intention or that I am still doing something incorrectly. 
 
Additionally, I have also tried to add go.mod files in sub directories that contain no go files between the root and the package.  This did not work either.

Thanks to everyone (Paul, Dave, Scott) who looked at this.

Sidenote on my original directory(bug?):
Interestingly enough, I have made a top level mod file and put a "hello world" main.go file.  That did not make this work.
But what looks like a bug is that I deleted both of those files, but if I run "go env GOMOD" at src/, I get back a path to a go.mod file that is the one I deleted.
Running "go mod tidy" gave the same error, so no auto cleanup
And go init mod also throws the same error.

I'm sure I can clean this up by removing some cached file somewhere.

thepud...@gmail.com

unread,
Sep 21, 2018, 2:05:28 PM9/21/18
to golang-nuts
    > "What I would expect with 'go test ./...' is behavior similar to what I had before modules."

Hi John, all,

Just to expand slightly on the points from Dave, Scott, and Paul...

I suspect part of what you are encountering is that in general:

  1. Modules are opt-in for Go 1.11, so by design old behavior is preserved by default. This has a few implications, including you get old behavior by default inside GOPATH, but that only applies if you haven't explicitly forced non-default behavior via GO111MODULE. (In your case, you started with GO111MODULE=on set, so that is part of why you are not seeing the old behavior you are used to).
  
  2. Most of the modules-specific behavior requires that you be "inside" a module (that is, inside a file tree with a go.mod).
  
A consequence of #2 is that if you explicitly ask for modules-specific behavior (e.g., via setting GO111MODULE=on) but are *not* inside a file tree with a 'go.mod' file, then you might see an error message that effectively tells you need to be inside a module. In your case, I think that is why you saw the error "go: cannot determine module path for source directory" when you tried one of your early go commands with GO111MODULE=on but were outside of a file tree with a 'go.mod' file.

In addition, I think in a module-world, something like 'go test ./...' only tests the active module(s), and won't traverse down into an unrelated module that happens to be in a sub-directory of the current module. I believe the doc says that explicitly for a '...' pattern appearing in 'go list', and I think that is true beyond just 'go list', at least as far as I am aware:


  "The main module is the module containing the current directory. The active modules are the main module and its dependencies."

and

  "The special pattern "all" specifies all the active modules, first the main module and then dependencies sorted by module path. A pattern containing "..." specifies the active modules whose module paths match the pattern."

I think that explains at least one of the examples you sent where 'go test ./...' did not work as you expected when modules were enabled (because in module-mode, './...' won't match modules that are not dependencies of the current module, even if they are in sub-directories, because they would not be part of the current "active modules").

One related item I'll mention is that a nice part of the modules work is that 'go test all' has been re-defined to be more useful to include all the packages in the current module, plus all the packages they depend on (in other words, all direct and indirect dependencies of the current module).  If you want to test the current module and all of its dependencies, 'go test all' would do that (rather than 'go test ./...').

In any event, I am just a member of the community and we are all still learning about modules, so I would be happy to learn if any of what I outlined above doesn't line up with what you are seeing...

Finally, I'm not sure what would be going on with the last piece you reported where 'go env GOMOD' returned the path to a deleted 'go.mod' file.

Best,
thepudds

John

unread,
Sep 21, 2018, 3:41:39 PM9/21/18
to golang-nuts
Thanks for the reply.  Other that the bug I encountered, this seems to be the behavior.

This new "mod" behavior for ./... at least for "go test" seems to be a step backwards.  It assumes a kind of test methodology based around a certain type of file layout.
If I am at the top of my src/ and I want to test everything underneath, I can't without adding some tooling.  I have to go inside a specific module.  It is nice that it will now test dependencies.  I'm somewhat lost to why the go tool would need to change the behavior for "go test ./...", seems like adding go.mod wouldn't require this change.  

I imagine I might be in the minority in using test this way.  Its useful when you have a small monorepo to do tests.  People who run large monorepos must have advanced tooling and individual modules won't notice the behavior change.  

But this thread was about if this was expected, not if I think it should be changed (I can always open a bug, see if anyone else agrees).  It turns out I'm not doing something wrong per say, its just that it doesn't do what I want.  I need to adjust my expectations.

Scott Cotton

unread,
Sep 21, 2018, 7:57:02 PM9/21/18
to golang-nuts
Hi all,

I for one would also consider the interface an improvement if as part of 
making modules work outside of a "main module" included making go test ./... work
as before.  Perhaps ./... could mean find each top level module in src/ and test.

I am not sure what the modules implementors would prefer w.r.t. such feedback.  On
the one hand they need it and can't possibly envision how everyone uses the tooling,  and
have wisely called it preliminary.

On the other, maybe it's not a bug as modules are defined; also I think they have obligated 
themselves to maintaining support for the current functionality, which some might not
find fitting to the way they work. For example from golang.org/cmd/go:
"""
We intend to keep revising this support, while preserving compatibility, until it can be declared official (no longer preliminary), and then at a later point we may remove support for work in GOPATH and the old 'go get' command.
"""


This makes it unclear to me at least how to categorise or proceed with feedback like John's,
where there is an unexpected error.

I would like to suggest that a tendency towards flexibility in implementing the statement above from golang.org 
might allow a more informed basis on which to take modules out of preliminary status.  But others
may depend on or like modules behaviour like this.  I have no way of knowing.

Also, yes I agree the listing of the deleted go.mod looks like a bug to me as well.

Best,
Scott

thepud...@gmail.com

unread,
Sep 22, 2018, 2:27:04 PM9/22/18
to golang-nuts
   > "I imagine I might be in the minority in using test this way.  Its useful when you have a small monorepo to do tests.  People who run large monorepos must have advanced tooling and individual modules won't notice the behavior change."
 
Hi John,
  
Stepping back, one side question: how many modules (`go.mod` files) do you have in your single repo?  The easiest approach (especially to start) is to have a single module / single `go.mod` file at the root of a repo.  That simplifies working with modules overall, and the official modules proposal predicts that most projects will have a single module per repo.  That might or might not help the specific issue you raised in this thread, but it very likely would simplify other aspects of your workflow.

In terms of your other comment here:

   > "But this thread was about if this was expected, not if I think it should be changed (I can always open a bug, see if anyone else agrees).  It turns out I'm not doing something wrong per say, its just that it doesn't do what I want.  I need to adjust my expectations."

If you think the current behavior should change, I would encourage you to file an issue. Most important probably is to outline your use case and where the current behavior falls short. In addition, you could optionally suggest some alternatives you might view as better, but most important probably is to outline your use case.

Some possible alternatives for module-aware mode might include:

 1. 'go test ./...' could be redefined to always traverse down the filesystem directory structure, ignoring module structure completely.
 
 2. behavior #1 could be the behavior when outside of a `go.mod` file tree, but the current behavior for 'go test ./...' could be retained when inside of a `go.mod` file tree.
 
 3. 'go test ./...' could be redefined to only find packages within the current active module (and not dependencies of the current module that happen to be in sub-directories). 
 
 4. behavior #1 could be the behavior when outside of a `go.mod` file tree, but behavior #3 could be the behavior when inside of a `go.mod` file tree.

There are pros and cons to each of those, but there are also many more options that could be possible. Also, it is of course not just about 'go test ./...' behavior, but also 'go build ./...', 'go list ./...', etc.
 
--thepudds

thepud...@gmail.com

unread,
Sep 22, 2018, 2:37:51 PM9/22/18
to golang-nuts
Hi Scott, all,

   > "also I think they have obligated themselves to maintaining support for the current functionality, which some might not
find fitting to the way they work."

Regarding the concern raised in that post -- I think it is definitely not too late to give feedback on how modules work, even if the core Go team has said they will maintain backwards compatibility for modules.

My understanding of that backwards compatibility is that a module that is defined today will be understood by future Go releases, but that the statement of backwards compatibility does not imply that the exact behavior of modules is frozen (especially for the behavior of the go tool itself, what flags it supports, what those flags do, what does './...' mean, etc.).  Rather, as far as I understand, the exact behavior is *expected* to change based on 1.11 feedback.

For example, from back in February (from the initial detailed vgo blog series):

  > "The details here may be revised, but today's go.mod files will be understood by any future tooling. Please start tagging your packages with release tags; add go.mod files if that makes sense for your project."
  
And from the 1.11 release notes:

   > "Module support is considered experimental. Details are likely to change in response to feedback from Go 1.11 users, and we have more tools planned. Although the details of module support may change, projects that convert to modules using Go 1.11 will continue to work with Go 1.12 and later."
   
I read that as saying that the exact behavior of modules may very well change before modules become the default behavior, but that modules defined and released under vgo or Go 1.11 will still be understood.

In other words, feedback is still very valuable and will influence what the behavior is in 1.12 and beyond.

In my personal experience and from what I have observed, the core Go team has been very willing not only to discuss changes to modules, but also to make actual changes to how modules behave based on community feedback.  Here is one sample list of changes from the "Modules" wiki page, where almost all of these changes were primarily driven by community feedback I think:


In terms of the Go 1.11 behavior, there are still open questions, including around what should the exact behavior be when modules are enabled but you are outside of any particular module, or how to best support simultaneously editing multiple modules, or what if any behavior the core tooling might pick up from community tooling such as https://github.com/rogpeppe/gohack, etc.  In many cases, I believe some of the currently open questions were purposefully left as open questions in 1.11, including so that actual experience could better inform future approaches.

Filing module issues or commenting on existing issues is of course valuable, but the core team has also expressed great interest in people filing experience reports on real-world usages of modules. From the experience reports wiki page (https://github.com/golang/go/wiki/ExperienceReports):

  "The best experience reports tell: (1) what you wanted to do, (2) what you actually did, and (3) why that wasn’t great, illustrating those by real concrete examples, ideally from production use. Please write these reports about the problems most significant to you, post them on your own blog, or on Medium, or as a Github Gist (use a .md extension for Markdown), or as a publicly-readable Google doc, and then link them here."
  
In any event, as a member of the community, I would certainly encourage feedback from other members of the community...

--thepudds

Scott Cotton

unread,
Sep 23, 2018, 6:30:50 AM9/23/18
to golang-nuts
Hi @thepudds, 

Good to hear and glad to have followed up so as to have introduced in the conversation how to address the concern in that post.

Thanks for the great summary of how to give effective feedback about about modules and the general context.

Best,
Scott
Reply all
Reply to author
Forward
0 new messages