Skip to content

Commit c12c9e5

Browse files
dmitshurgopherbot
authored andcommitted
cmd/coordinator: handle new dist test names with current adjust policies
The coordinator has some custom logic for "go_test:*" dist test names involved in partitioning, merging, and sorting them using historical test timing data. We also have many builder-specific dist test adjust policies, and some parts of them have become out of date (e.g., macTestPolicy skips "wiki", a dist test that's long gone). Go 1.21 is simplifying the naming pattern for dist test names, and we want to do that without having to manually update the (many!) existing adjust policies, as well as to avoid breaking or creating a need to re-engineer the existing mechanisms that make "go_test:*" dist test names special. Make that possible by remapping the 'go tool dist test -list' output from the new "pkg[:variant]" format to the previous format (or pass it through unmodified if it's already in the old format) for the purpose of dist test adjust policies only. Also keep the raw unmodified dist test name around since it's needed for invoking said dist tests. For golang/go#37486. For golang/go#59990. Change-Id: Ie958609de2a810fa0053a00091a0c54c3f8bfd83 Reviewed-on: https://go-review.googlesource.com/c/build/+/496190 Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Austin Clements <[email protected]> Auto-Submit: Dmitri Shuralyov <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Dmitri Shuralyov <[email protected]>
1 parent 15ff97b commit c12c9e5

File tree

4 files changed

+161
-20
lines changed

4 files changed

+161
-20
lines changed

cmd/coordinator/buildstatus.go

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,13 @@ func (st *buildStatus) reportErr(err error) {
867867
gceErrsClient.ReportSync(ctx, errorreporting.Entry{Error: err})
868868
}
869869

870-
func (st *buildStatus) distTestList() (names []string, remoteErr, err error) {
870+
// distTestList uses 'go tool dist test -list' to get a list of dist test names.
871+
//
872+
// As of Go 1.21, the dist test naming pattern has changed to always be in the
873+
// form of "<pkg>[:<variant>]", where "<pkg>" means what used to be previously
874+
// named "go_test:<pkg>". distTestList maps those new dist test names back to
875+
// that previous format, a combination of "go_test[_bench]:<pkg>" and others.
876+
func (st *buildStatus) distTestList() (names []distTestName, remoteErr, err error) {
871877
workDir, err := st.bc.WorkDir(st.ctx)
872878
if err != nil {
873879
err = fmt.Errorf("distTestList, WorkDir: %v", err)
@@ -899,30 +905,94 @@ func (st *buildStatus) distTestList() (names []string, remoteErr, err error) {
899905
err = fmt.Errorf("Exec error: %v, %s", err, buf.Bytes())
900906
return
901907
}
902-
for _, test := range strings.Fields(buf.String()) {
908+
// To avoid needing to update all the existing dist test adjust policies,
909+
// it's easier to remap new dist test names in "<pkg>[:<variant>]" format
910+
// to ones used in Go 1.20 and prior. Do that for now.
911+
for _, test := range go120DistTestNames(strings.Fields(buf.String())) {
903912
isNormalTry := st.isTry() && !st.isSlowBot()
904-
if !st.conf.ShouldRunDistTest(test, isNormalTry) {
913+
if !st.conf.ShouldRunDistTest(test.Old, isNormalTry) {
905914
continue
906915
}
907916
names = append(names, test)
908917
}
909918
return names, nil, nil
910919
}
911920

921+
// go120DistTestNames converts a list of dist test names from
922+
// an arbitrary Go distribution to the format used in Go 1.20
923+
// and prior versions. (Go 1.21 introduces a simpler format.)
924+
//
925+
// This exists only to avoid rewriting current dist adjust policies.
926+
// We wish to avoid new dist adjust policies, but if they're truly needed,
927+
// they can choose to start using new dist test names instead.
928+
func go120DistTestNames(names []string) []distTestName {
929+
if len(names) == 0 {
930+
// Only happens if there's a problem, but no need to panic.
931+
return nil
932+
} else if strings.HasPrefix(names[0], "go_test:") {
933+
// In Go 1.21 and newer no dist tests have a "go_test:" prefix.
934+
// In Go 1.20 and older, go tool dist test -list always returns
935+
// at least one "go_test:*" test first.
936+
// So if we see it, the list is already in Go 1.20 format.
937+
var s []distTestName
938+
for _, old := range names {
939+
s = append(s, distTestName{old, old})
940+
}
941+
return s
942+
}
943+
// Remap the new Go 1.21+ dist test names to old ones.
944+
var s []distTestName
945+
for _, new := range names {
946+
var old string
947+
switch pkg, variant, _ := strings.Cut(new, ":"); {
948+
// Special cases. Enough to cover what's used by old dist
949+
// adjust policies. Not much use in going far beyond that.
950+
case variant == "nolibgcc":
951+
old = "nolibgcc:" + pkg
952+
case variant == "race":
953+
old = "race"
954+
case variant == "moved_goroot":
955+
old = "moved_goroot"
956+
case pkg == "cmd/internal/testdir":
957+
if variant == "" {
958+
// Handle this too for when we stop doing special-case sharding only for testdir inside dist.
959+
variant = "0_1"
960+
}
961+
old = "test:" + variant
962+
case pkg == "cmd/api" && variant == "check":
963+
old = "api"
964+
case pkg == "cmd/internal/bootstrap_test":
965+
old = "reboot"
966+
967+
// Easy regular cases.
968+
case variant == "":
969+
old = "go_test:" + pkg
970+
case variant == "racebench":
971+
old = "go_test_bench:" + pkg
972+
973+
// Neither a known special case nor a regular case.
974+
default:
975+
old = new // Less bad than leaving it empty.
976+
}
977+
s = append(s, distTestName{Old: old, Raw: new})
978+
}
979+
return s
980+
}
981+
912982
type token struct{}
913983

914-
// newTestSet returns a new testSet given the dist test names (strings from "go tool dist test -list")
984+
// newTestSet returns a new testSet given the dist test names (from "go tool dist test -list")
915985
// and benchmark items.
916-
func (st *buildStatus) newTestSet(testStats *buildstats.TestStats, distTestNames []string) (*testSet, error) {
986+
func (st *buildStatus) newTestSet(testStats *buildstats.TestStats, names []distTestName) (*testSet, error) {
917987
set := &testSet{
918988
st: st,
919989
testStats: testStats,
920990
}
921-
for _, name := range distTestNames {
991+
for _, name := range names {
922992
set.items = append(set.items, &testItem{
923993
set: set,
924994
name: name,
925-
duration: testStats.Duration(st.BuilderRev.Name, name),
995+
duration: testStats.Duration(st.BuilderRev.Name, name.Old),
926996
take: make(chan token, 1),
927997
done: make(chan token),
928998
})
@@ -1593,7 +1663,7 @@ func (st *buildStatus) runTests(helpers <-chan buildlet.Client) (remoteErr, err
15931663
timer.Stop()
15941664
break AwaitDone
15951665
case <-timer.C:
1596-
st.LogEventTime("still_waiting_on_test", ti.name)
1666+
st.LogEventTime("still_waiting_on_test", ti.name.Old)
15971667
case <-buildletsGone:
15981668
set.cancelAll()
15991669
return nil, errBuildletsGone
@@ -1720,10 +1790,10 @@ const maxTestExecErrors = 3
17201790

17211791
// runTestsOnBuildlet runs tis on bc, using the optional goroot & gopath environment variables.
17221792
func (st *buildStatus) runTestsOnBuildlet(bc buildlet.Client, tis []*testItem, goroot, gopath string) {
1723-
names := make([]string, len(tis))
1793+
names, rawNames := make([]string, len(tis)), make([]string, len(tis))
17241794
for i, ti := range tis {
1725-
names[i] = ti.name
1726-
if i > 0 && (!strings.HasPrefix(ti.name, "go_test:") || !strings.HasPrefix(names[0], "go_test:")) {
1795+
names[i], rawNames[i] = ti.name.Old, ti.name.Raw
1796+
if i > 0 && (!strings.HasPrefix(ti.name.Old, "go_test:") || !strings.HasPrefix(names[0], "go_test:")) {
17271797
panic("only go_test:* tests may be merged")
17281798
}
17291799
}
@@ -1748,7 +1818,7 @@ func (st *buildStatus) runTestsOnBuildlet(bc buildlet.Client, tis []*testItem, g
17481818
if st.useKeepGoingFlag() {
17491819
args = append(args, "-k")
17501820
}
1751-
args = append(args, names...)
1821+
args = append(args, rawNames...)
17521822
var buf bytes.Buffer
17531823
t0 := time.Now()
17541824
timeout := st.conf.DistTestsExecTimeout(names)

cmd/coordinator/buildstatus_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package main
1010

1111
import (
12+
"strings"
1213
"testing"
1314

1415
"github.com/google/go-cmp/cmp"
@@ -328,3 +329,53 @@ func TestModulesEnv(t *testing.T) {
328329
})
329330
}
330331
}
332+
333+
// Test that go120DistTestNames remaps both 1.20 (old) and 1.21 (new)
334+
// dist test names to old, and doesn't forget the original name (raw).
335+
func TestGo120DistTestNames(t *testing.T) {
336+
for _, tc := range [...]struct {
337+
name string
338+
in string
339+
want string
340+
}{
341+
{
342+
name: "empty",
343+
in: "",
344+
want: "",
345+
},
346+
{
347+
name: "old to old",
348+
in: "go_test:archive/tar go_test:cmd/go api reboot test:0_2 test:1_2",
349+
want: "go_test:archive/tar go_test:cmd/go api reboot test:0_2 test:1_2",
350+
},
351+
{
352+
name: "new to old",
353+
in: " archive/tar cmd/go cmd/api:check cmd/internal/bootstrap_test cmd/internal/testdir:0_2 cmd/internal/testdir:1_2",
354+
want: "go_test:archive/tar go_test:cmd/go api reboot test:0_2 test:1_2",
355+
},
356+
{
357+
name: "more special cases",
358+
in: "crypto/x509:nolibgcc fmt:moved_goroot flag:race net:race os:race",
359+
want: "nolibgcc:crypto/x509 moved_goroot race race race",
360+
},
361+
{
362+
name: "unhandled special case",
363+
in: "something:something",
364+
want: "something:something",
365+
},
366+
} {
367+
t.Run(tc.name, func(t *testing.T) {
368+
got := go120DistTestNames(strings.Fields(tc.in))
369+
var want []distTestName
370+
for _, old := range strings.Fields(tc.want) {
371+
want = append(want, distTestName{Old: old})
372+
}
373+
for i, raw := range strings.Fields(tc.in) {
374+
want[i].Raw = raw
375+
}
376+
if diff := cmp.Diff(want, got); diff != "" {
377+
t.Errorf("go120DistTestNames mismatch (-want +got):\n%s", diff)
378+
}
379+
})
380+
}
381+
}

cmd/coordinator/coordinator.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,8 +1842,8 @@ func (s *testSet) initInOrder() {
18421842
names := make([]string, len(s.items))
18431843
namedItem := map[string]*testItem{}
18441844
for i, ti := range s.items {
1845-
names[i] = ti.name
1846-
namedItem[ti.name] = ti
1845+
names[i] = ti.name.Old
1846+
namedItem[ti.name.Old] = ti
18471847
}
18481848

18491849
// First do the go_test:* ones. partitionGoTests
@@ -1860,7 +1860,7 @@ func (s *testSet) initInOrder() {
18601860
// Then do the misc tests, which are always by themselves.
18611861
// (No benefit to merging them)
18621862
for _, ti := range s.items {
1863-
if !strings.HasPrefix(ti.name, "go_test:") {
1863+
if !strings.HasPrefix(ti.name.Old, "go_test:") {
18641864
s.inOrder = append(s.inOrder, []*testItem{ti})
18651865
}
18661866
}
@@ -1915,7 +1915,7 @@ func (s *testSet) initBiggestFirst() {
19151915

19161916
type testItem struct {
19171917
set *testSet
1918-
name string // "go_test:sort"
1918+
name distTestName
19191919
duration time.Duration // optional approximate size
19201920

19211921
take chan token // buffered size 1: sending takes ownership of rest of fields:
@@ -1959,6 +1959,12 @@ func (ti *testItem) failf(format string, args ...interface{}) {
19591959
close(ti.done)
19601960
}
19611961

1962+
// distTestName is the name of a dist test as discovered from 'go tool dist test -list'.
1963+
type distTestName struct {
1964+
Old string // Old is dist test name converted to Go 1.20 format, like "go_test:sort" or "reboot".
1965+
Raw string // Raw is unmodified name from dist, suitable as an argument back to 'go tool dist test'.
1966+
}
1967+
19621968
type byTestDuration []*testItem
19631969

19641970
func (s byTestDuration) Len() int { return len(s) }

dashboard/builders.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,9 @@ type BuildConfig struct {
889889
// return run
890890
// }
891891
//
892+
// distTestAdjust works with dist test names expressed in the Go 1.20 format.
893+
// See ShouldRunDistTest for details.
894+
//
892895
distTestAdjust func(run bool, distTest string, isNormalTry bool) bool
893896

894897
// numTestHelpers is the number of _additional_ buildlets
@@ -976,6 +979,9 @@ func (c *BuildConfig) IsRestricted() bool {
976979

977980
// DistTestsExecTimeout returns how long the coordinator should wait
978981
// for a cmd/dist test execution to run the provided dist test names.
982+
//
983+
// The dist test names are expressed in the Go 1.20 format, even for
984+
// newer Go versions. See go120DistTestNames.
979985
func (c *BuildConfig) DistTestsExecTimeout(distTests []string) time.Duration {
980986
// TODO: consider using distTests? We never did before, but
981987
// now we have the TestStats in the coordinator. Pass in a
@@ -1177,13 +1183,20 @@ func (c *BuildConfig) BuildsRepoTryBot(repo, branch, goBranch string) bool {
11771183
}
11781184

11791185
// ShouldRunDistTest reports whether the named cmd/dist test should be
1180-
// run for this build config. The isNormalTry parameter is whether this
1181-
// is for a normal TryBot (non-SlowBot) run.
1186+
// run for this build config. The dist test name is expressed in the
1187+
// Go 1.20 format, even for newer Go versions. See go120DistTestNames.
1188+
//
1189+
// The isNormalTry parameter specifies whether this is for a normal
1190+
// TryBot build. It's false for SlowBot and post-submit builds.
11821191
//
11831192
// In general, this returns true. When in normal trybot mode,
11841193
// some slow portable tests are only run on the fastest builder.
11851194
//
1186-
// Individual builders can adjust this policy to fit their needs.
1195+
// It's possible for individual builders to adjust this policy for their needs,
1196+
// though it is preferable to handle that by adjusting test skips in the tests
1197+
// instead of here. That has the advantage of being easier to maintain over time
1198+
// since both the test and its skips would be in one repository rather than two,
1199+
// and having effect when tests are run locally by developers.
11871200
func (c *BuildConfig) ShouldRunDistTest(distTest string, isNormalTry bool) bool {
11881201
run := true
11891202

@@ -1198,7 +1211,8 @@ func (c *BuildConfig) ShouldRunDistTest(distTest string, isNormalTry bool) bool
11981211
}
11991212
}
12001213

1201-
// Let individual builders adjust the cmd/dist test policy.
1214+
// Individual builders have historically sometimes adjusted the cmd/dist test policy.
1215+
// Over time these can migrate to better ways of doing platform-based or speed-based test skips.
12021216
if c.distTestAdjust != nil {
12031217
run = c.distTestAdjust(run, distTest, isNormalTry)
12041218
}

0 commit comments

Comments
 (0)