Skip to content

Commit 520188d

Browse files
heschistamblerre
authored andcommitted
go/packages: fix flaky failure creating non-test package from overlay
The core of processGolistOverlay was a map iteration, which is nondeterministic. When creating both a non-test and test package, we would sometimes encounter the test file before the non-test file. In that case, for reasons I didn't bother tracking down, we would never create the non-test package. Rather than doing complicated bookkeeping to fix the problem, simply process non-test before test, and make the loop deterministic to save all of our sanity. Updates golang/go#36661. Change-Id: I1f76869fa52794ac8ae96e22ad06a2b1e1861995 Reviewed-on: https://go-review.googlesource.com/c/tools/+/216717 Reviewed-by: Rebecca Stambler <[email protected]> Run-TryBot: Heschi Kreinick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent ae42f3c commit 520188d

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

go/packages/golist_overlay.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"go/token"
88
"os"
99
"path/filepath"
10+
"sort"
1011
"strconv"
1112
"strings"
1213
)
@@ -34,7 +35,24 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif
3435
// potentially modifying the transitive set of dependencies).
3536
var overlayAddsImports bool
3637

37-
for opath, contents := range state.cfg.Overlay {
38+
// If both a package and its test package are created by the overlay, we
39+
// need the real package first. Process all non-test files before test
40+
// files, and make the whole process deterministic while we're at it.
41+
var overlayFiles []string
42+
for opath := range state.cfg.Overlay {
43+
overlayFiles = append(overlayFiles, opath)
44+
}
45+
sort.Slice(overlayFiles, func(i, j int) bool {
46+
iTest := strings.HasSuffix(overlayFiles[i], "_test.go")
47+
jTest := strings.HasSuffix(overlayFiles[j], "_test.go")
48+
if iTest != jTest {
49+
return !iTest // non-tests are before tests.
50+
}
51+
return overlayFiles[i] < overlayFiles[j]
52+
})
53+
54+
for _, opath := range overlayFiles {
55+
contents := state.cfg.Overlay[opath]
3856
base := filepath.Base(opath)
3957
dir := filepath.Dir(opath)
4058
var pkg *Package // if opath belongs to both a package and its test variant, this will be the test variant

go/packages/packages_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,33 @@ func testNewPackagesInOverlay(t *testing.T, exporter packagestest.Exporter) {
11041104
}
11051105
}
11061106

1107+
// Test that we can create a package and its test package in an overlay.
1108+
func TestOverlayNewPackageAndTest(t *testing.T) { packagestest.TestAll(t, testOverlayNewPackageAndTest) }
1109+
func testOverlayNewPackageAndTest(t *testing.T, exporter packagestest.Exporter) {
1110+
exported := packagestest.Export(t, exporter, []packagestest.Module{
1111+
{
1112+
Name: "golang.org/fake",
1113+
Files: map[string]interface{}{
1114+
"foo.txt": "placeholder",
1115+
},
1116+
},
1117+
})
1118+
defer exported.Cleanup()
1119+
1120+
dir := filepath.Dir(exported.File("golang.org/fake", "foo.txt"))
1121+
exported.Config.Overlay = map[string][]byte{
1122+
filepath.Join(dir, "a.go"): []byte(`package a;`),
1123+
filepath.Join(dir, "a_test.go"): []byte(`package a; import "testing";`),
1124+
}
1125+
initial, err := packages.Load(exported.Config, "file="+filepath.Join(dir, "a.go"), "file="+filepath.Join(dir, "a_test.go"))
1126+
if err != nil {
1127+
t.Fatal(err)
1128+
}
1129+
if len(initial) != 2 {
1130+
t.Errorf("got %v packages, wanted %v", len(initial), 2)
1131+
}
1132+
}
1133+
11071134
func TestAdHocPackagesBadImport(t *testing.T) {
11081135
// This test doesn't use packagestest because we are testing ad-hoc packages,
11091136
// which are outside of $GOPATH and outside of a module.

0 commit comments

Comments
 (0)