# This test demonstrates dependency resolution when the main module imports a # new package from a previously-test-only dependency. # # When lazy loading is active, the loader will not load dependencies of any # module whose packages are *only* imported by tests outside the main module. If # the main module is changed to import a package from such a module, the # dependencies of that module will need to be reloaded. # The import graph used in this test looks like: # # m ---- a # \ | # \ a_test ---- b/x # \ # --------------b/y (new) ---- c # # Where b/x and b/y are disjoint packages, but both contained in module b. # # The module dependency graph initially looks like: # # m ---- a.1 ---- b.1 ---- c.1 # # This configuration is similar to that used in mod_lazy_new_import, # but the new import is from what is initially a test-only dependency. # Control case: in Go 1.14, the original go.mod is tidy, # and the dependency on c is eagerly loaded. cp go.mod go.mod.orig go mod tidy cmp go.mod.orig go.mod go list -m all stdout '^a v0.1.0 ' stdout '^b v0.1.0 ' stdout '^c v0.1.0 ' # After adding a new import of b/y, # the import of c from b/y should resolve to the version required by b. cp m.go m.go.orig cp m.go.new m.go go mod tidy cmp go.mod.new go.mod go list -m all stdout '^a v0.1.0 ' stdout '^b v0.1.0 ' stdout '^c v0.1.0 ' # With lazy loading, the go.mod requirements are the same, # but the dependency on c is initially pruned out. cp m.go.orig m.go cp go.mod.orig go.mod go mod edit -go=1.17 go mod edit -go=1.17 go.mod.new cp go.mod go.mod.orig go mod tidy cmp go.mod.orig go.mod go list -m all stdout '^a v0.1.0 ' stdout '^b v0.1.0 ' ! stdout '^c ' # After adding a new direct import of b/y, # the existing version of b should be promoted to a root, # bringing the version of c required by b into the build list. cp m.go.new m.go go mod tidy cmp go.mod.lazy go.mod go list -m all stdout '^a v0.1.0 ' stdout '^b v0.1.0 ' stdout '^c v0.1.0 ' -- m.go -- package main import ( "fmt" _ "a" // a_test imports b/x. ) func main() { } -- m.go.new -- package main import ( "fmt" _ "a" // a_test imports b/x. "b/y" // This is a new import, not yet reflected in the go.mod file. ) func main() { fmt.Println(b.CVersion()) } -- go.mod -- module m go 1.14 require a v0.1.0 replace ( a v0.1.0 => ./a1 b v0.1.0 => ./b1 c v0.1.0 => ./c1 c v0.2.0 => ./c2 ) -- go.mod.new -- module m go 1.14 require ( a v0.1.0 b v0.1.0 ) replace ( a v0.1.0 => ./a1 b v0.1.0 => ./b1 c v0.1.0 => ./c1 c v0.2.0 => ./c2 ) -- go.mod.lazy -- module m go 1.17 require ( a v0.1.0 b v0.1.0 ) require c v0.1.0 // indirect replace ( a v0.1.0 => ./a1 b v0.1.0 => ./b1 c v0.1.0 => ./c1 c v0.2.0 => ./c2 ) -- a1/go.mod -- module a go 1.17 require b v0.1.0 -- a1/a.go -- package a -- a1/a_test.go -- package a_test import _ "b/x" -- b1/go.mod -- module b go 1.17 require c v0.1.0 -- b1/x/x.go -- package x -- b1/y/y.go -- package y import "c" func CVersion() string { return c.Version } -- c1/go.mod -- module c go 1.17 -- c1/c.go -- package c const Version = "v0.1.0" -- c2/go.mod -- This file should be unused. -- c2/c.go -- This file should be unused.