golang.org/x/build@v0.0.0-20240506185731-218518f32b70/dashboard/builders_test.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package dashboard
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"os"
    12  	"os/exec"
    13  	"regexp"
    14  	"sort"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  func TestOSARCHAccessors(t *testing.T) {
    21  	valid := func(s string) bool { return s != "" && !strings.Contains(s, "-") }
    22  	for _, conf := range Builders {
    23  		os := conf.GOOS()
    24  		arch := conf.GOARCH()
    25  		osArch := os + "-" + arch
    26  		if !valid(os) || !valid(arch) || !(conf.Name == osArch || strings.HasPrefix(conf.Name, osArch+"-")) {
    27  			t.Errorf("OS+ARCH(%q) = %q, %q; invalid", conf.Name, os, arch)
    28  		}
    29  	}
    30  }
    31  
    32  func TestDistTestsExecTimeout(t *testing.T) {
    33  	tests := []struct {
    34  		c    *BuildConfig
    35  		want time.Duration
    36  	}{
    37  		{
    38  			&BuildConfig{
    39  				env:          []string{},
    40  				TestHostConf: &HostConfig{},
    41  			},
    42  			20 * time.Minute,
    43  		},
    44  		{
    45  			&BuildConfig{
    46  				env:          []string{"GO_TEST_TIMEOUT_SCALE=2"},
    47  				TestHostConf: &HostConfig{},
    48  			},
    49  			40 * time.Minute,
    50  		},
    51  		{
    52  			&BuildConfig{
    53  				env: []string{},
    54  				TestHostConf: &HostConfig{
    55  					env: []string{"GO_TEST_TIMEOUT_SCALE=3"},
    56  				},
    57  			},
    58  			60 * time.Minute,
    59  		},
    60  		// BuildConfig's env takes precedence:
    61  		{
    62  			&BuildConfig{
    63  				env: []string{"GO_TEST_TIMEOUT_SCALE=2"},
    64  				TestHostConf: &HostConfig{
    65  					env: []string{"GO_TEST_TIMEOUT_SCALE=3"},
    66  				},
    67  			},
    68  			40 * time.Minute,
    69  		},
    70  	}
    71  	for i, tt := range tests {
    72  		got := tt.c.DistTestsExecTimeout(nil)
    73  		if got != tt.want {
    74  			t.Errorf("%d. got %v; want %v", i, got, tt.want)
    75  		}
    76  	}
    77  }
    78  
    79  // TestTrybots tests that a given repo & its branch yields the provided complete
    80  // set of builders. See also: TestPostSubmit, which tests only post-submit
    81  // builders, and TestBuilderConfig, which tests both trybots and post-submit
    82  // builders, both at arbitrary branches.
    83  func TestTrybots(t *testing.T) {
    84  	tests := []struct {
    85  		repo   string // "go", "net", etc
    86  		branch string // of repo
    87  		want   []string
    88  	}{
    89  		{
    90  			repo:   "go",
    91  			branch: "master",
    92  			want: []string{
    93  				"freebsd-amd64-12_3",
    94  				"linux-386",
    95  				"linux-amd64",
    96  				"linux-amd64-boringcrypto",
    97  				"linux-amd64-newinliner",
    98  				"linux-amd64-race",
    99  				"linux-arm64",
   100  				"openbsd-amd64-72",
   101  				"windows-386-2016",
   102  				"windows-amd64-2016",
   103  
   104  				"misc-compile-windows-arm",
   105  				"misc-compile-windows-arm64",
   106  				"misc-compile-darwin-amd64",
   107  				"misc-compile-darwin-arm64",
   108  				"misc-compile-linux-mips",
   109  				"misc-compile-linux-mips64",
   110  				"misc-compile-linux-mipsle",
   111  				"misc-compile-linux-mips64le",
   112  				"misc-compile-linux-ppc64",
   113  				"misc-compile-linux-ppc64le",
   114  				"misc-compile-aix-ppc64",
   115  				"misc-compile-freebsd-386",
   116  				"misc-compile-freebsd-arm",
   117  				"misc-compile-freebsd-arm64",
   118  				"misc-compile-freebsd-riscv64",
   119  				"misc-compile-netbsd-386",
   120  				"misc-compile-netbsd-amd64",
   121  				"misc-compile-netbsd-arm",
   122  				"misc-compile-netbsd-arm64",
   123  				"misc-compile-openbsd-386",
   124  				"misc-compile-openbsd-arm",
   125  				"misc-compile-openbsd-arm64",
   126  				"misc-compile-openbsd-ppc64-go1.22",
   127  				"misc-compile-openbsd-riscv64-go1.23",
   128  				"misc-compile-plan9-386",
   129  				"misc-compile-plan9-amd64",
   130  				"misc-compile-plan9-arm",
   131  				"misc-compile-solaris-amd64",
   132  				"misc-compile-illumos-amd64",
   133  				"misc-compile-dragonfly-amd64",
   134  				"misc-compile-linux-loong64",
   135  				"misc-compile-linux-riscv64",
   136  				"misc-compile-linux-s390x",
   137  				"misc-compile-linux-arm",
   138  				"misc-compile-linux-arm-arm5",
   139  			},
   140  		},
   141  		{
   142  			repo:   "go",
   143  			branch: "release-branch.go1.22",
   144  			want: []string{
   145  				"freebsd-amd64-12_3",
   146  				"linux-386",
   147  				"linux-amd64",
   148  				"linux-amd64-boringcrypto",
   149  				"linux-amd64-race",
   150  				"linux-arm64",
   151  				"openbsd-amd64-72",
   152  				"windows-386-2016",
   153  				"windows-amd64-2016",
   154  
   155  				"misc-compile-windows-arm",
   156  				"misc-compile-windows-arm64",
   157  				"misc-compile-darwin-amd64",
   158  				"misc-compile-darwin-arm64",
   159  				"misc-compile-linux-mips",
   160  				"misc-compile-linux-mips64",
   161  				"misc-compile-linux-mipsle",
   162  				"misc-compile-linux-mips64le",
   163  				"misc-compile-linux-ppc64",
   164  				"misc-compile-linux-ppc64le",
   165  				"misc-compile-aix-ppc64",
   166  				"misc-compile-freebsd-386",
   167  				"misc-compile-freebsd-arm",
   168  				"misc-compile-freebsd-arm64",
   169  				"misc-compile-freebsd-riscv64",
   170  				"misc-compile-netbsd-386",
   171  				"misc-compile-netbsd-amd64",
   172  				"misc-compile-netbsd-arm",
   173  				"misc-compile-netbsd-arm64",
   174  				"misc-compile-openbsd-386",
   175  				"misc-compile-openbsd-arm",
   176  				"misc-compile-openbsd-arm64",
   177  				"misc-compile-openbsd-ppc64-go1.22", // New to Go 1.22.
   178  				"misc-compile-plan9-386",
   179  				"misc-compile-plan9-amd64",
   180  				"misc-compile-plan9-arm",
   181  				"misc-compile-solaris-amd64",
   182  				"misc-compile-illumos-amd64",
   183  				"misc-compile-dragonfly-amd64",
   184  				"misc-compile-linux-loong64",
   185  				"misc-compile-linux-riscv64",
   186  				"misc-compile-linux-s390x",
   187  				"misc-compile-linux-arm",
   188  				"misc-compile-linux-arm-arm5",
   189  
   190  				// Include longtest builders on Go repo release branches. See issue 37827.
   191  				"linux-386-longtest",
   192  				"linux-amd64-longtest",
   193  				"linux-arm64-longtest",
   194  				"windows-amd64-longtest",
   195  			},
   196  		},
   197  		{
   198  			repo:   "go",
   199  			branch: "release-branch.go1.21",
   200  			want: []string{
   201  				"freebsd-amd64-12_3",
   202  				"linux-386",
   203  				"linux-amd64",
   204  				"linux-amd64-boringcrypto",
   205  				"linux-amd64-race",
   206  				"linux-arm64",
   207  				"openbsd-amd64-72",
   208  				"windows-386-2016",
   209  				"windows-amd64-2016",
   210  
   211  				"misc-compile-windows-arm",
   212  				"misc-compile-windows-arm64",
   213  				"misc-compile-darwin-amd64",
   214  				"misc-compile-darwin-arm64",
   215  				"misc-compile-linux-mips",
   216  				"misc-compile-linux-mips64",
   217  				"misc-compile-linux-mipsle",
   218  				"misc-compile-linux-mips64le",
   219  				"misc-compile-linux-ppc64",
   220  				"misc-compile-linux-ppc64le",
   221  				"misc-compile-aix-ppc64",
   222  				"misc-compile-freebsd-386",
   223  				"misc-compile-freebsd-arm",
   224  				"misc-compile-freebsd-arm64",
   225  				"misc-compile-freebsd-riscv64",
   226  				"misc-compile-netbsd-386",
   227  				"misc-compile-netbsd-amd64",
   228  				"misc-compile-netbsd-arm",
   229  				"misc-compile-netbsd-arm64",
   230  				"misc-compile-openbsd-386",
   231  				"misc-compile-openbsd-arm",
   232  				"misc-compile-openbsd-arm64",
   233  				"misc-compile-plan9-386",
   234  				"misc-compile-plan9-amd64",
   235  				"misc-compile-plan9-arm",
   236  				"misc-compile-solaris-amd64",
   237  				"misc-compile-illumos-amd64",
   238  				"misc-compile-dragonfly-amd64",
   239  				"misc-compile-linux-loong64",
   240  				"misc-compile-linux-riscv64",
   241  				"misc-compile-linux-s390x",
   242  				"misc-compile-linux-arm",
   243  				"misc-compile-linux-arm-arm5",
   244  
   245  				// Include longtest builders on Go repo release branches. See issue 37827.
   246  				"linux-386-longtest",
   247  				"linux-amd64-longtest",
   248  				"linux-arm64-longtest",
   249  				"windows-amd64-longtest",
   250  			},
   251  		},
   252  		{
   253  			repo:   "mobile",
   254  			branch: "master",
   255  			want: []string{
   256  				"android-amd64-emu",
   257  				"linux-amd64-androidemu",
   258  				"linux-amd64",
   259  				"linux-amd64-race",
   260  			},
   261  		},
   262  		{
   263  			repo:   "sys",
   264  			branch: "master",
   265  			want: []string{
   266  				"freebsd-386-13_0",
   267  				"freebsd-amd64-12_3",
   268  				"freebsd-amd64-13_0",
   269  				"linux-386",
   270  				"linux-amd64",
   271  				"linux-amd64-boringcrypto", // GoDeps will exclude, but not in test
   272  				"linux-amd64-race",
   273  				"linux-arm64",
   274  				"netbsd-amd64-9_3",
   275  				"openbsd-386-72",
   276  				"openbsd-amd64-72",
   277  				"windows-386-2016",
   278  				"windows-amd64-2016",
   279  
   280  				"misc-compile-windows-arm",
   281  				"misc-compile-windows-arm64",
   282  				"misc-compile-darwin-amd64",
   283  				"misc-compile-darwin-arm64",
   284  				"misc-compile-linux-mips",
   285  				"misc-compile-linux-mips64",
   286  				"misc-compile-linux-mipsle",
   287  				"misc-compile-linux-mips64le",
   288  				"misc-compile-linux-ppc64",
   289  				"misc-compile-linux-ppc64le",
   290  				"misc-compile-aix-ppc64",
   291  				"misc-compile-freebsd-386",
   292  				"misc-compile-freebsd-arm",
   293  				"misc-compile-freebsd-arm64",
   294  				"misc-compile-freebsd-riscv64",
   295  				"misc-compile-netbsd-386",
   296  				"misc-compile-netbsd-amd64",
   297  				"misc-compile-netbsd-arm",
   298  				"misc-compile-netbsd-arm64",
   299  				"misc-compile-openbsd-386",
   300  				"misc-compile-openbsd-arm",
   301  				"misc-compile-openbsd-arm64",
   302  				"misc-compile-openbsd-ppc64-go1.22",
   303  				"misc-compile-openbsd-riscv64-go1.23",
   304  				"misc-compile-plan9-386",
   305  				"misc-compile-plan9-amd64",
   306  				"misc-compile-plan9-arm",
   307  				"misc-compile-solaris-amd64",
   308  				"misc-compile-illumos-amd64",
   309  				"misc-compile-dragonfly-amd64",
   310  				"misc-compile-linux-loong64",
   311  				"misc-compile-linux-riscv64",
   312  				"misc-compile-linux-s390x",
   313  				"misc-compile-linux-arm",
   314  				"misc-compile-linux-arm-arm5",
   315  			},
   316  		},
   317  		{
   318  			repo:   "exp",
   319  			branch: "master",
   320  			want: []string{
   321  				"linux-amd64",
   322  				"linux-amd64-race",
   323  				"windows-amd64-2016",
   324  			},
   325  		},
   326  		{
   327  			repo:   "vulndb",
   328  			branch: "master",
   329  			want: []string{
   330  				"linux-amd64",
   331  				"linux-amd64-race",
   332  			},
   333  		},
   334  		{
   335  			repo:   "website",
   336  			branch: "master",
   337  			want: []string{
   338  				"linux-amd64",
   339  				"linux-amd64-race",
   340  			},
   341  		},
   342  	}
   343  	for i, tt := range tests {
   344  		if tt.branch == "" || tt.repo == "" {
   345  			t.Errorf("incomplete test entry %d", i)
   346  			return
   347  		}
   348  		t.Run(fmt.Sprintf("%s/%s", tt.repo, tt.branch), func(t *testing.T) {
   349  			goBranch := tt.branch // hard-code the common case for now
   350  			got := TryBuildersForProject(tt.repo, tt.branch, goBranch)
   351  			checkBuildersForProject(t, got, tt.want)
   352  		})
   353  	}
   354  }
   355  
   356  func checkBuildersForProject(t *testing.T, gotBuilders []*BuildConfig, want []string) {
   357  	t.Helper()
   358  
   359  	var got []string
   360  	for _, bc := range gotBuilders {
   361  		got = append(got, bc.Name)
   362  	}
   363  	m := map[string]bool{}
   364  	for _, b := range want {
   365  		m[b] = true
   366  	}
   367  	for _, b := range got {
   368  		if _, ok := m[b]; !ok {
   369  			t.Errorf("got unexpected %q", b)
   370  		}
   371  		delete(m, b)
   372  	}
   373  	for b := range m {
   374  		t.Errorf("missing expected %q", b)
   375  	}
   376  }
   377  
   378  // TestPostSubmit tests that a given repo & its branch yields the provided
   379  // complete set of post-submit builders. See also: TestTrybots, which tests only
   380  // trybots, and TestBuilderConfig, which tests both trybots and post-submit
   381  // builders, both at arbitrary branches.
   382  func TestPostSubmit(t *testing.T) {
   383  	tests := []struct {
   384  		repo   string // "go", "net", etc
   385  		branch string // of repo
   386  		want   []string
   387  	}{
   388  		{
   389  			repo:   "vulndb",
   390  			branch: "master",
   391  			want: []string{
   392  				"linux-amd64",
   393  				"linux-amd64-longtest",
   394  				"linux-amd64-race",
   395  				"linux-amd64-longtest-race",
   396  			},
   397  		},
   398  		{
   399  			repo:   "website",
   400  			branch: "master",
   401  			want: []string{
   402  				"linux-amd64",
   403  				"linux-amd64-longtest",
   404  				"linux-amd64-race",
   405  				"linux-amd64-longtest-race",
   406  			},
   407  		},
   408  	}
   409  	for i, tt := range tests {
   410  		if tt.branch == "" || tt.repo == "" {
   411  			t.Fatalf("incomplete test entry %d", i)
   412  		}
   413  		t.Run(fmt.Sprintf("%s/%s", tt.repo, tt.branch), func(t *testing.T) {
   414  			goBranch := tt.branch // hard-code the common case for now
   415  			got := buildersForProject(tt.repo, tt.branch, goBranch, (*BuildConfig).BuildsRepoPostSubmit)
   416  			checkBuildersForProject(t, got, tt.want)
   417  		})
   418  	}
   419  }
   420  
   421  // TestBuilderConfig tests whether a given builder and repo at different branches is
   422  // completely disabled ("none"),
   423  // a TryBot and a post-submit builder ("both"), or
   424  // a post-submit only builder ("onlyPost").
   425  func TestBuilderConfig(t *testing.T) {
   426  	// want is a bitmask of 4 different things to assert are wanted:
   427  	// - being a post-submit builder
   428  	// - NOT being a post-submit builder
   429  	// - being a trybot builder
   430  	// - NOT being a post-submit builder
   431  	// Note: a builder cannot be configured as a TryBot without also being a post-submit builder.
   432  	type want uint8
   433  	const (
   434  		isTrybot want = 1 << iota
   435  		notTrybot
   436  		isBuilder  // post-submit
   437  		notBuilder // not post-submit
   438  
   439  		// Available combinations:
   440  		none     = notTrybot + notBuilder
   441  		both     = isTrybot + isBuilder
   442  		onlyPost = notTrybot + isBuilder
   443  	)
   444  
   445  	type builderAndRepo struct {
   446  		testName string
   447  		builder  string
   448  		repo     string
   449  		branch   string
   450  		goBranch string
   451  	}
   452  	// builder may end in "@go1.N" or "@1.N" (as alias for "@release-branch.go1.N") or "@branch-name".
   453  	// repo (other than "go") may end in "@go1.N" or "@1.N" (as alias for "@release-branch.go1.N").
   454  	b := func(builder, repo string) builderAndRepo {
   455  		br := builderAndRepo{
   456  			testName: builder + "," + repo,
   457  			builder:  builder,
   458  			goBranch: "master",
   459  			repo:     repo,
   460  			branch:   "master",
   461  		}
   462  		if strings.Contains(builder, "@") {
   463  			f := strings.SplitN(builder, "@", 2)
   464  			br.builder = f[0]
   465  			br.goBranch = f[1]
   466  		}
   467  		if strings.Contains(repo, "@") {
   468  			f := strings.SplitN(repo, "@", 2)
   469  			br.repo = f[0]
   470  			br.branch = f[1]
   471  			if br.repo == "go" {
   472  				panic(fmt.Errorf(`b(%q, %q): for "go" repo, must use the @%s suffix on the builder, not on the repo`, builder, repo, br.branch))
   473  			}
   474  		}
   475  		expandBranch := func(s *string) {
   476  			if strings.HasPrefix(*s, "go1.") {
   477  				*s = "release-branch." + *s
   478  			} else if strings.HasPrefix(*s, "1.") {
   479  				*s = "release-branch.go" + *s
   480  			}
   481  		}
   482  		expandBranch(&br.branch)
   483  		expandBranch(&br.goBranch)
   484  		if br.repo == "go" {
   485  			br.branch = br.goBranch
   486  		}
   487  		return br
   488  	}
   489  	tests := []struct {
   490  		br   builderAndRepo
   491  		want want // none, both, or onlyPost.
   492  	}{
   493  		{b("linux-amd64", "go"), both},
   494  		{b("linux-amd64", "net"), both},
   495  		{b("linux-amd64", "sys"), both},
   496  		{b("linux-amd64", "website"), both},
   497  
   498  		// Don't test all subrepos on all the builders.
   499  		{b("linux-amd64-ssacheck", "net"), none},
   500  		{b("linux-amd64-ssacheck@go1.99", "net"), none},
   501  		{b("linux-386-softfloat", "crypto"), onlyPost},
   502  		{b("linux-386-softfloat@go1.99", "crypto"), onlyPost},
   503  
   504  		{b("android-amd64-emu", "go"), onlyPost},
   505  		{b("android-amd64-emu", "mobile"), both},
   506  		{b("android-amd64-emu", "crypto"), onlyPost},
   507  		{b("android-amd64-emu", "net"), onlyPost},
   508  		{b("android-amd64-emu", "sync"), onlyPost},
   509  		{b("android-amd64-emu", "sys"), onlyPost},
   510  		{b("android-amd64-emu", "text"), onlyPost},
   511  		{b("android-amd64-emu", "time"), onlyPost},
   512  		{b("android-amd64-emu", "tools"), onlyPost},
   513  		{b("android-amd64-emu", "website"), none},
   514  
   515  		{b("android-386-emu", "go"), onlyPost},
   516  		{b("android-386-emu", "mobile"), onlyPost},
   517  		{b("android-386-emu", "crypto"), onlyPost},
   518  
   519  		{b("linux-amd64", "net"), both},
   520  
   521  		{b("linux-loong64-3a5000", "go"), onlyPost},
   522  		{b("linux-loong64-3a5000@go1.99", "go"), onlyPost},
   523  		{b("linux-loong64-3a5000", "sys"), onlyPost},
   524  		{b("linux-loong64-3a5000@go1.99", "sys"), onlyPost},
   525  		{b("linux-loong64-3a5000", "net"), onlyPost},
   526  
   527  		// OpenBSD 7.2.
   528  		{b("openbsd-amd64-72", "go"), both},
   529  		{b("openbsd-amd64-72@go1.99", "go"), both},
   530  
   531  		// FreeBSD 13.0
   532  		{b("freebsd-amd64-13_0", "go"), onlyPost},
   533  		{b("freebsd-amd64-13_0", "net"), onlyPost},
   534  		{b("freebsd-amd64-13_0", "mobile"), none},
   535  		{b("freebsd-386-13_0", "go"), onlyPost},
   536  		{b("freebsd-386-13_0", "net"), onlyPost},
   537  		{b("freebsd-386-13_0", "mobile"), none},
   538  
   539  		// FreeBSD 12.3
   540  		{b("freebsd-amd64-12_3", "go"), both},
   541  		{b("freebsd-amd64-12_3", "net"), both},
   542  		{b("freebsd-amd64-12_3", "mobile"), none},
   543  		{b("freebsd-386-12_3", "go"), onlyPost},
   544  		{b("freebsd-386-12_3", "net"), onlyPost},
   545  		{b("freebsd-386-12_3", "mobile"), none},
   546  
   547  		// NetBSD
   548  		{b("netbsd-amd64-9_3", "go"), onlyPost},
   549  		{b("netbsd-amd64-9_3", "net"), onlyPost},
   550  		{b("netbsd-amd64-9_3", "sys"), both},
   551  		{b("netbsd-386-9_3", "go"), onlyPost},
   552  		{b("netbsd-386-9_3", "net"), onlyPost},
   553  
   554  		// AIX
   555  		{b("aix-ppc64", "go"), onlyPost},
   556  		{b("aix-ppc64", "net"), onlyPost},
   557  		{b("aix-ppc64", "mobile"), none},
   558  		{b("aix-ppc64", "exp"), none},
   559  		{b("aix-ppc64", "term"), onlyPost},
   560  
   561  		{b("linux-amd64-nocgo", "mobile"), none},
   562  
   563  		// Virtual mobiledevices
   564  		{b("ios-arm64-corellium", "go"), onlyPost},
   565  		{b("android-arm64-corellium", "go"), onlyPost},
   566  		{b("android-arm-corellium", "go"), onlyPost},
   567  
   568  		// Mobile builders that run with GOOS=linux/ios and have
   569  		// a device attached.
   570  		{b("linux-amd64-androidemu", "mobile"), both},
   571  
   572  		// The Android emulator builders can test all repos.
   573  		{b("android-amd64-emu", "mobile"), both},
   574  		{b("android-386-emu", "mobile"), onlyPost},
   575  		{b("android-amd64-emu", "net"), onlyPost},
   576  		{b("android-386-emu", "net"), onlyPost},
   577  		{b("android-amd64-emu", "go"), onlyPost},
   578  		{b("android-386-emu", "go"), onlyPost},
   579  
   580  		// Builders for js/wasm are fully ported to LUCI and stopped in the coordinator.
   581  		{b("js-wasm-node18", "go"), none},
   582  		{b("js-wasm-node18@go1.21", "go"), none},
   583  		{b("js-wasm-node18@go1.20", "go"), none},
   584  		{b("js-wasm-node18", "arch"), none},
   585  		{b("js-wasm-node18", "crypto"), none},
   586  		{b("js-wasm-node18", "sys"), none},
   587  		{b("js-wasm-node18", "net"), none},
   588  		{b("js-wasm-node18", "benchmarks"), none},
   589  		{b("js-wasm-node18", "debug"), none},
   590  		{b("js-wasm-node18", "mobile"), none},
   591  		{b("js-wasm-node18", "perf"), none},
   592  		{b("js-wasm-node18", "talks"), none},
   593  		{b("js-wasm-node18", "tools"), none},
   594  		{b("js-wasm-node18", "tour"), none},
   595  		{b("js-wasm-node18", "website"), none},
   596  
   597  		// Builders for wasip1-wasm are fully ported to LUCI and stopped in the coordinator.
   598  		{b("wasip1-wasm-wazero", "go"), none},
   599  		{b("wasip1-wasm-wazero@go1.21", "go"), none},
   600  		{b("wasip1-wasm-wazero@go1.20", "go"), none},
   601  		{b("wasip1-wasm-wasmtime", "go"), none},
   602  		{b("wasip1-wasm-wasmtime@go1.21", "go"), none},
   603  		{b("wasip1-wasm-wasmtime@go1.20", "go"), none},
   604  		{b("wasip1-wasm-wasmer", "go"), none},
   605  		{b("wasip1-wasm-wasmer@go1.21", "go"), none},
   606  		{b("wasip1-wasm-wasmer@go1.20", "go"), none},
   607  		{b("wasip1-wasm-wasmedge", "go"), none},
   608  		{b("wasip1-wasm-wasmedge@go1.21", "go"), none},
   609  		{b("wasip1-wasm-wasmedge@go1.20", "go"), none},
   610  		{b("wasip1-wasm-wazero", "arch"), none},
   611  		{b("wasip1-wasm-wazero", "crypto"), none},
   612  		{b("wasip1-wasm-wazero", "sys"), none},
   613  		{b("wasip1-wasm-wazero", "net"), none},
   614  		{b("wasip1-wasm-wazero", "benchmarks"), none},
   615  		{b("wasip1-wasm-wazero", "debug"), none},
   616  		{b("wasip1-wasm-wazero", "mobile"), none},
   617  		{b("wasip1-wasm-wazero", "perf"), none},
   618  		{b("wasip1-wasm-wazero", "talks"), none},
   619  		{b("wasip1-wasm-wazero", "tools"), none},
   620  		{b("wasip1-wasm-wazero", "tour"), none},
   621  		{b("wasip1-wasm-wazero", "website"), none},
   622  		{b("wasip1-wasm-wasmtime", "arch"), none},
   623  		{b("wasip1-wasm-wasmtime", "crypto"), none},
   624  		{b("wasip1-wasm-wasmtime", "sys"), none},
   625  		{b("wasip1-wasm-wasmtime", "net"), none},
   626  		{b("wasip1-wasm-wasmtime", "benchmarks"), none},
   627  		{b("wasip1-wasm-wasmtime", "debug"), none},
   628  		{b("wasip1-wasm-wasmtime", "mobile"), none},
   629  		{b("wasip1-wasm-wasmtime", "perf"), none},
   630  		{b("wasip1-wasm-wasmtime", "talks"), none},
   631  		{b("wasip1-wasm-wasmtime", "tools"), none},
   632  		{b("wasip1-wasm-wasmtime", "tour"), none},
   633  		{b("wasip1-wasm-wasmtime", "website"), none},
   634  		{b("wasip1-wasm-wasmer", "arch"), none},
   635  		{b("wasip1-wasm-wasmer", "crypto"), none},
   636  		{b("wasip1-wasm-wasmer", "sys"), none},
   637  		{b("wasip1-wasm-wasmer", "net"), none},
   638  		{b("wasip1-wasm-wasmer", "benchmarks"), none},
   639  		{b("wasip1-wasm-wasmer", "debug"), none},
   640  		{b("wasip1-wasm-wasmer", "mobile"), none},
   641  		{b("wasip1-wasm-wasmer", "perf"), none},
   642  		{b("wasip1-wasm-wasmer", "talks"), none},
   643  		{b("wasip1-wasm-wasmer", "tools"), none},
   644  		{b("wasip1-wasm-wasmer", "tour"), none},
   645  		{b("wasip1-wasm-wasmer", "website"), none},
   646  		{b("wasip1-wasm-wasmedge", "arch"), none},
   647  		{b("wasip1-wasm-wasmedge", "crypto"), none},
   648  		{b("wasip1-wasm-wasmedge", "sys"), none},
   649  		{b("wasip1-wasm-wasmedge", "net"), none},
   650  		{b("wasip1-wasm-wasmedge", "benchmarks"), none},
   651  		{b("wasip1-wasm-wasmedge", "debug"), none},
   652  		{b("wasip1-wasm-wasmedge", "mobile"), none},
   653  		{b("wasip1-wasm-wasmedge", "perf"), none},
   654  		{b("wasip1-wasm-wasmedge", "talks"), none},
   655  		{b("wasip1-wasm-wasmedge", "tools"), none},
   656  		{b("wasip1-wasm-wasmedge", "tour"), none},
   657  		{b("wasip1-wasm-wasmedge", "website"), none},
   658  
   659  		// Race builders. Linux for all, GCE builders for
   660  		// post-submit, and only post-submit for "go" for
   661  		// Darwin (limited resources).
   662  		{b("linux-amd64-race", "go"), both},
   663  		{b("linux-amd64-race", "net"), both},
   664  		{b("windows-amd64-race", "go"), onlyPost},
   665  		{b("windows-amd64-race", "net"), onlyPost},
   666  		{b("freebsd-amd64-race", "go"), onlyPost},
   667  		{b("freebsd-amd64-race", "net"), onlyPost},
   668  		{b("darwin-amd64-race", "go"), onlyPost},
   669  		{b("darwin-amd64-race", "net"), none},
   670  
   671  		// Long test.
   672  		{b("linux-amd64-longtest", "go"), onlyPost},
   673  		{b("linux-amd64-longtest", "net"), onlyPost},
   674  		{b("linux-amd64-longtest@go1.99", "go"), both},
   675  		{b("linux-amd64-longtest@go1.99", "net"), none},
   676  		{b("darwin-amd64-longtest", "go"), onlyPost},
   677  		{b("darwin-amd64-longtest", "net"), onlyPost},
   678  		{b("darwin-amd64-longtest@go1.99", "go"), onlyPost},
   679  		{b("darwin-amd64-longtest@go1.99", "net"), none},
   680  		{b("windows-amd64-longtest", "go"), onlyPost},
   681  		{b("windows-amd64-longtest@go1.99", "go"), both},
   682  		{b("windows-amd64-longtest", "net"), onlyPost},
   683  		{b("windows-amd64-longtest", "exp"), onlyPost},
   684  		{b("windows-amd64-longtest", "mobile"), none},
   685  		{b("linux-386-longtest", "go"), onlyPost},
   686  		{b("linux-386-longtest", "net"), onlyPost},
   687  		{b("linux-386-longtest", "exp"), none},
   688  		{b("linux-386-longtest", "mobile"), none},
   689  
   690  		// Experimental exp repo runs in very few places.
   691  		{b("linux-amd64", "exp"), both},
   692  		{b("linux-amd64-race", "exp"), both},
   693  		{b("linux-amd64-longtest", "exp"), onlyPost},
   694  		{b("windows-386-2016", "exp"), none},
   695  		{b("windows-amd64-2016", "exp"), both},
   696  		{b("darwin-amd64-10_15", "exp"), none},
   697  		{b("darwin-amd64-11_0", "exp"), onlyPost},
   698  		// ... but not on most others:
   699  		{b("freebsd-386-12_3", "exp"), none},
   700  		{b("freebsd-amd64-12_3", "exp"), none},
   701  		{b("js-wasm-node18", "exp"), none},
   702  		{b("wasip1-wasm-wazero", "exp"), none},
   703  		{b("wasip1-wasm-wasmtime", "exp"), none},
   704  		{b("wasip1-wasm-wasmer", "exp"), none},
   705  		{b("wasip1-wasm-wasmedge", "exp"), none},
   706  
   707  		// exp is experimental; it doesn't test against release branches.
   708  		{b("linux-amd64@go1.99", "exp"), none},
   709  
   710  		// the build repo is only really useful for linux-amd64 (where we run it),
   711  		// and darwin-amd64 and perhaps windows-amd64 (for stuff like gomote).
   712  		// No need for any other operating systems to use it.
   713  		{b("linux-amd64", "build"), both},
   714  		{b("linux-amd64-longtest", "build"), onlyPost},
   715  		{b("windows-amd64-2016", "build"), both},
   716  		{b("darwin-amd64-10_15", "build"), none},
   717  		{b("darwin-amd64-11_0", "build"), onlyPost},
   718  		{b("linux-amd64-fedora", "build"), none},
   719  		{b("linux-amd64-clang", "build"), none},
   720  		{b("linux-amd64-sid", "build"), none},
   721  		{b("linux-amd64-bullseye", "build"), none},
   722  		{b("linux-amd64-bookworm", "build"), none},
   723  		{b("linux-amd64-nocgo", "build"), none},
   724  		{b("linux-386-longtest", "build"), none},
   725  
   726  		{b("linux-amd64", "vulndb"), both},
   727  		{b("linux-amd64-longtest", "vulndb"), onlyPost},
   728  
   729  		{b("linux-amd64@go1.20", "pkgsite-metrics"), both},
   730  
   731  		{b("js-wasm-node18", "build"), none},
   732  		{b("wasip1-wasm-wazero", "build"), none},
   733  		{b("wasip1-wasm-wasmtime", "build"), none},
   734  		{b("wasip1-wasm-wasmer", "build"), none},
   735  		{b("wasip1-wasm-wasmedge", "build"), none},
   736  		{b("android-386-emu", "build"), none},
   737  		{b("android-amd64-emu", "build"), none},
   738  
   739  		{b("darwin-amd64-11_0", "go"), onlyPost},
   740  		// Go 1.22 is the last release with macOS 10.15 support:
   741  		{b("darwin-amd64-10_15", "go"), none},
   742  		{b("darwin-amd64-10_15@go1.23", "go"), none},
   743  		{b("darwin-amd64-10_15@go1.22", "go"), onlyPost},
   744  		{b("darwin-amd64-10_15", "net"), none},
   745  		{b("darwin-amd64-10_15@go1.23", "net"), none},
   746  		{b("darwin-amd64-10_15@go1.22", "net"), onlyPost},
   747  
   748  		// The darwin longtest builder added during the Go 1.21 dev cycle:
   749  		{b("darwin-amd64-longtest@go1.21", "go"), onlyPost},
   750  		{b("darwin-amd64-longtest@go1.20", "go"), none},
   751  
   752  		// plan9 only lived at master. We didn't support any past releases.
   753  		// But it's off for now as it's always failing.
   754  		{b("plan9-386", "go"), none},  // temporarily disabled
   755  		{b("plan9-386", "net"), none}, // temporarily disabled
   756  		{b("plan9-386", "exp"), none},
   757  		{b("plan9-386", "mobile"), none},
   758  		{b("plan9-386@go1.99", "go"), none},
   759  		{b("plan9-386@go1.99", "net"), none},
   760  		{b("plan9-amd64-0intro", "go"), onlyPost},
   761  		{b("plan9-amd64-0intro", "exp"), none},
   762  		{b("plan9-amd64-0intro", "mobile"), none},
   763  		{b("plan9-amd64-0intro@go1.99", "go"), none},
   764  		{b("plan9-amd64-0intro", "net"), onlyPost},
   765  		{b("plan9-amd64-0intro@go1.99", "net"), none},
   766  		{b("plan9-arm", "go"), onlyPost},
   767  		{b("plan9-arm", "exp"), none},
   768  		{b("plan9-arm", "mobile"), none},
   769  		{b("plan9-amd64-0intro@go1.99", "go"), none},
   770  		{b("plan9-amd64-0intro", "net"), onlyPost},
   771  		{b("plan9-amd64-0intro@go1.99", "net"), none},
   772  		{b("dragonfly-amd64-622", "go"), onlyPost},
   773  		{b("dragonfly-amd64-622", "net"), onlyPost},
   774  
   775  		{b("linux-amd64-staticlockranking", "go"), onlyPost},
   776  		{b("linux-amd64-staticlockranking", "net"), none},
   777  
   778  		{b("linux-amd64-newinliner", "go"), both},
   779  		{b("linux-amd64-newinliner", "tools"), none},
   780  		{b("linux-amd64-newinliner@go1.22", "go"), none},
   781  	}
   782  	for _, tt := range tests {
   783  		t.Run(tt.br.testName, func(t *testing.T) {
   784  			// Require a want value that asserts both dimensions: try or not, post or not.
   785  			switch tt.want {
   786  			case none, both, onlyPost:
   787  				// OK.
   788  			default:
   789  				t.Fatalf("tt.want must be one of: none, both, or onlyPost")
   790  			}
   791  
   792  			bc, ok := Builders[tt.br.builder]
   793  			if !ok {
   794  				t.Fatalf("unknown builder %q", tt.br.builder)
   795  			}
   796  			gotPost := bc.BuildsRepoPostSubmit(tt.br.repo, tt.br.branch, tt.br.goBranch)
   797  			if tt.want&isBuilder != 0 && !gotPost {
   798  				t.Errorf("not a post-submit builder, but expected")
   799  			}
   800  			if tt.want&notBuilder != 0 && gotPost {
   801  				t.Errorf("unexpectedly a post-submit builder")
   802  			}
   803  
   804  			gotTry := bc.BuildsRepoTryBot(tt.br.repo, tt.br.branch, tt.br.goBranch)
   805  			if tt.want&isTrybot != 0 && !gotTry {
   806  				t.Errorf("not trybot, but expected")
   807  			}
   808  			if tt.want&notTrybot != 0 && gotTry {
   809  				t.Errorf("unexpectedly a trybot")
   810  			}
   811  
   812  			if t.Failed() {
   813  				t.Logf("For: %+v", tt.br)
   814  			}
   815  		})
   816  	}
   817  }
   818  
   819  func TestHostConfigsAllUsed(t *testing.T) {
   820  	knownUnused := map[string]bool{}
   821  
   822  	used := make(map[string]bool)
   823  	for _, conf := range Builders {
   824  		used[conf.HostType] = true
   825  	}
   826  	for hostType := range Hosts {
   827  		if !used[hostType] && !knownUnused[hostType] {
   828  			t.Errorf("host type %q is not referenced from any build config", hostType)
   829  		}
   830  		if used[hostType] && knownUnused[hostType] {
   831  			t.Errorf("host type %q should not be listed in knownUnused since it's in use", hostType)
   832  		}
   833  	}
   834  }
   835  
   836  // Test that all specified builder owners are non-nil.
   837  func TestBuilderOwners(t *testing.T) {
   838  	for host, config := range Hosts {
   839  		for i, p := range config.Owners {
   840  			if p == nil {
   841  				t.Errorf("dashboard.Hosts[%q].Owners[%d] is nil, want non-nil", host, i)
   842  			}
   843  		}
   844  	}
   845  }
   846  
   847  // tests that goBranch is optional for repo == "go"
   848  func TestBuildsRepoAtAllImplicitGoBranch(t *testing.T) {
   849  	builder := Builders["android-amd64-emu"]
   850  	got := builder.buildsRepoAtAll("go", "master", "")
   851  	if !got {
   852  		t.Error("got = false; want true")
   853  	}
   854  }
   855  
   856  func TestShouldRunDistTest(t *testing.T) {
   857  	type buildMode int
   858  	const (
   859  		tryMode    buildMode = 0
   860  		postSubmit buildMode = 1
   861  	)
   862  
   863  	tests := []struct {
   864  		builder string
   865  		test    string
   866  		mode    buildMode
   867  		want    bool
   868  	}{
   869  		{"linux-amd64", "api", postSubmit, true},
   870  		{"linux-amd64", "api", tryMode, true},
   871  		{"freebsd-amd64-12_3", "api", postSubmit, true}, // freebsd-amd64-12_3 uses fasterTrybots policy, should still build.
   872  		{"freebsd-amd64-12_3", "api", tryMode, false},   // freebsd-amd64-12_3 uses fasterTrybots policy, should skip in try mode.
   873  
   874  		{"linux-amd64", "reboot", tryMode, true},
   875  		{"linux-amd64-race", "reboot", tryMode, false},
   876  
   877  		{"darwin-amd64-13", "test:foo", postSubmit, false},
   878  		{"darwin-amd64-13", "reboot", postSubmit, false},
   879  		{"darwin-amd64-13", "api", postSubmit, false},
   880  		{"darwin-amd64-13", "codewalk", postSubmit, false},
   881  		{"darwin-amd64-12_0", "test:foo", postSubmit, false},
   882  	}
   883  	for _, tt := range tests {
   884  		bc, ok := Builders[tt.builder]
   885  		if !ok {
   886  			t.Errorf("unknown builder %q", tt.builder)
   887  			continue
   888  		}
   889  		isTry := tt.mode == tryMode
   890  		if isTry && !bc.BuildsRepoTryBot("go", "master", "master") {
   891  			t.Errorf("builder %q is not a trybot, so can't run test %q in try mode", tt.builder, tt.test)
   892  			continue
   893  		}
   894  		got := bc.ShouldRunDistTest(tt.test, isTry)
   895  		if got != tt.want {
   896  			t.Errorf("%q.ShouldRunDistTest(%q, try %v) = %v; want %v", tt.builder, tt.test, isTry, got, tt.want)
   897  		}
   898  	}
   899  }
   900  
   901  func TestSlowBotAliases(t *testing.T) {
   902  	for term, name := range slowBotAliases {
   903  		if name == "" {
   904  			// Empty string means known missing builder.
   905  			continue
   906  		}
   907  		if _, ok := Builders[name]; !ok {
   908  			t.Errorf("slowbot term %q references unknown builder %q", term, name)
   909  		}
   910  	}
   911  
   912  	ports, err := listPorts()
   913  	if err != nil {
   914  		t.Fatal("listPorts:", err)
   915  	}
   916  
   917  	done := map[string]bool{}
   918  
   919  	var add bytes.Buffer
   920  	check := func(term string, isArch bool) {
   921  		if done[term] {
   922  			return
   923  		}
   924  		done[term] = true
   925  		_, isBuilderName := Builders[term]
   926  		_, hasAlias := slowBotAliases[term]
   927  		if !isBuilderName && !hasAlias {
   928  			prefix := term
   929  			if isArch {
   930  				prefix = "linux-" + term
   931  			}
   932  			var matches []string
   933  			for name := range Builders {
   934  				if strings.HasPrefix(name, prefix) {
   935  					matches = append(matches, name)
   936  				}
   937  			}
   938  			sort.Strings(matches)
   939  			t.Errorf("term %q has no match in slowBotAliases", term)
   940  			if len(matches) == 1 {
   941  				fmt.Fprintf(&add, "%q: %q,\n", term, matches[0])
   942  			} else if len(matches) > 1 {
   943  				t.Errorf("maybe add:  %q: %q,    (matches=%q)", term, matches[len(matches)-1], matches)
   944  			}
   945  		}
   946  	}
   947  
   948  	for _, port := range ports {
   949  		goos, goarch, ok := strings.Cut(port, "/")
   950  		if !ok {
   951  			t.Fatalf("unexpected port %q", port)
   952  		}
   953  		check(goos+"-"+goarch, false)
   954  		check(goos, false)
   955  		check(goarch, true)
   956  	}
   957  
   958  	if add.Len() > 0 {
   959  		t.Errorf("Missing items from slowBotAliases:\n%s", add.String())
   960  	}
   961  }
   962  
   963  // TestCrossCompileOnlyBuilders checks to make sure that only misc-compile
   964  // builders and the linux-s390x-crosscompile builder have IsCrossCompileOnly
   965  // return true.
   966  func TestCrossCompileOnlyBuilders(t *testing.T) {
   967  	for _, conf := range Builders {
   968  		isMiscCompile := strings.HasPrefix(conf.Name, "misc-compile") || conf.Name == "linux-s390x-crosscompile"
   969  		if ccOnly := conf.IsCrossCompileOnly(); isMiscCompile != ccOnly {
   970  			t.Errorf("builder %q has unexpected IsCrossCompileOnly state (want %t, got %t)", conf.Name, isMiscCompile, ccOnly)
   971  		}
   972  	}
   973  }
   974  
   975  // TestTryBotsCompileAllPorts verifies that each port (go tool dist list)
   976  // is covered by either a real TryBot or a misc-compile TryBot.
   977  //
   978  // The special pseudo-port 'linux-arm-arm5' is tested in TestMiscCompileLinuxGOARM5.
   979  func TestTryBotsCompileAllPorts(t *testing.T) {
   980  	ports, err := listPorts()
   981  	if err != nil {
   982  		t.Fatal("listPorts:", err)
   983  	}
   984  
   985  	// knownMissing tracks Go ports that that are known to be
   986  	// completely missing TryBot (pre-submit) test coverage.
   987  	//
   988  	// All completed ports should have either a real TryBot or at least a misc-compile TryBot,
   989  	// so this map is meant to be used to temporarily fix tests
   990  	// when the work of adding a new port is actively underway.
   991  	knownMissing := map[string]bool{
   992  		"openbsd-mips64": true, // go.dev/issue/58110
   993  
   994  		"js-wasm":     true, // Fully ported to LUCI and stopped in the coordinator.
   995  		"wasip1-wasm": true, // Fully ported to LUCI and stopped in the coordinator.
   996  	}
   997  
   998  	var done = make(map[string]bool)
   999  	check := func(goos, goarch string) {
  1000  		if goos == "android" || goos == "ios" {
  1001  			// TODO(golang.org/issue/25963): support
  1002  			// compilation-only Android and iOS trybots.
  1003  			// buildall.bash doesn't set the environment
  1004  			// up enough for e.g. compiling android-386
  1005  			// from linux-amd64. (Issue #35596 too)
  1006  			// iOS likely needs to be built on macOS
  1007  			// with Xcode available.
  1008  			return
  1009  		}
  1010  		goosArch := goos + "-" + goarch
  1011  		if done[goosArch] {
  1012  			return
  1013  		}
  1014  		for _, conf := range Builders {
  1015  			if conf.GOOS() == goos && conf.GOARCH() == goarch &&
  1016  				conf.BuildsRepoTryBot("go", "master", "master") {
  1017  
  1018  				// There's a real TryBot for this GOOS/GOARCH pair.
  1019  				done[goosArch] = true
  1020  				break
  1021  			}
  1022  
  1023  			if strings.HasPrefix(conf.Name, "misc-compile-") {
  1024  				var cGoos, cGoarch string
  1025  				for _, v := range conf.env {
  1026  					if strings.HasPrefix(v, "GOOS=") {
  1027  						cGoos = v[len("GOOS="):]
  1028  					}
  1029  					if strings.HasPrefix(v, "GOARCH=") {
  1030  						cGoarch = v[len("GOARCH="):]
  1031  					}
  1032  				}
  1033  				if cGoos == "" {
  1034  					t.Errorf("missing GOOS env var for misc-compile builder %q", conf.Name)
  1035  				}
  1036  				if cGoarch == "" {
  1037  					t.Errorf("missing GOARCH env var for misc-compile builder %q", conf.Name)
  1038  				}
  1039  				cGoosArch := cGoos + "-" + cGoarch
  1040  				if goosArch == cGoosArch {
  1041  					// There's a misc-compile TryBot for this GOOS/GOARCH pair.
  1042  					done[goosArch] = true
  1043  					break
  1044  				}
  1045  			}
  1046  		}
  1047  		if knownMissing[goosArch] && done[goosArch] {
  1048  			// Make it visible when a builder is added but the old
  1049  			// knownMissing entry isn't removed by failing the test.
  1050  			t.Errorf("knownMissing[%q] is true, but a corresponding TryBot (real or misc-compile) exists", goosArch)
  1051  		} else if _, ok := done[goosArch]; !ok && !knownMissing[goosArch] {
  1052  			t.Errorf("missing real TryBot or misc-compile TryBot for %q", goosArch)
  1053  		}
  1054  	}
  1055  
  1056  	for _, port := range ports {
  1057  		goos, goarch, ok := strings.Cut(port, "/")
  1058  		if !ok {
  1059  			t.Fatalf("unexpected port %q", port)
  1060  		}
  1061  		check(goos, goarch)
  1062  	}
  1063  }
  1064  
  1065  // The 'linux-arm-arm5' pseduo-port is supported by src/buildall.bash
  1066  // and tests linux/arm with GOARM=5 set. Since it's not a normal port,
  1067  // the TestTryBotsCompileAllPorts wouldn't report if the misc-compile
  1068  // TryBot that covers is accidentally removed. Check it explicitly.
  1069  func TestMiscCompileLinuxGOARM5(t *testing.T) {
  1070  	for _, b := range Builders {
  1071  		if !strings.HasPrefix(b.Name, "misc-compile-") {
  1072  			continue
  1073  		}
  1074  		var hasGOOS, hasGOARCH, hasGOARM bool
  1075  		for _, v := range b.env {
  1076  			if v == "GOOS=linux" {
  1077  				hasGOOS = true
  1078  				continue
  1079  			}
  1080  			if v == "GOARCH=arm" {
  1081  				hasGOARCH = true
  1082  				continue
  1083  			}
  1084  			if v == "GOARM=5" {
  1085  				hasGOARM = true
  1086  				continue
  1087  			}
  1088  		}
  1089  		if hasGOOS && hasGOARCH && hasGOARM {
  1090  			// Found it. Nothing left to do.
  1091  			return
  1092  		}
  1093  	}
  1094  	// We get here if the linux-arm-arm5 port is no longer checked by
  1095  	// a misc-compile TryBot. Report it as a failure in case the coverage
  1096  	// was removed accidentally (e.g., as part of a refactor).
  1097  	t.Errorf("no misc-compile TryBot coverage for the special 'linux-arm-arm5' pseudo-port")
  1098  }
  1099  
  1100  // Test that we have longtest builders and
  1101  // that their environment configurations are okay.
  1102  func TestLongTestBuilder(t *testing.T) {
  1103  	for _, name := range []string{"linux-amd64-longtest", "linux-amd64-longtest-race"} {
  1104  		name := name
  1105  		t.Run(name, func(t *testing.T) {
  1106  			long, ok := Builders[name]
  1107  			if !ok {
  1108  				t.Fatalf("we don't have a %s builder anymore, is that intentional?", name)
  1109  			}
  1110  			if !long.IsLongTest() {
  1111  				t.Errorf("the %s builder isn't a longtest builder, is that intentional?", name)
  1112  			}
  1113  			var shortDisabled bool
  1114  			for _, e := range long.Env() {
  1115  				if e == "GO_TEST_SHORT=0" {
  1116  					shortDisabled = true
  1117  				}
  1118  			}
  1119  			if !shortDisabled {
  1120  				t.Errorf("the %s builder doesn't set GO_TEST_SHORT=0, is that intentional?", name)
  1121  			}
  1122  		})
  1123  	}
  1124  }
  1125  
  1126  // Test that we have race builders and
  1127  // that their environment configurations are okay.
  1128  func TestRaceBuilder(t *testing.T) {
  1129  	for _, name := range []string{"linux-amd64-race", "linux-amd64-longtest-race"} {
  1130  		name := name
  1131  		t.Run(name, func(t *testing.T) {
  1132  			race, ok := Builders[name]
  1133  			if !ok {
  1134  				t.Fatalf("we don't have a %s builder anymore, is that intentional?", name)
  1135  			}
  1136  			if !race.IsRace() {
  1137  				t.Errorf("the %s builder isn't a race builder, is that intentional?", name)
  1138  			}
  1139  			if script := race.AllScript(); !strings.Contains(script, "race") {
  1140  				t.Errorf("the %s builder doesn't use race.bash or race.bat, it uses %s instead, is that intentional?", name, script)
  1141  			}
  1142  		})
  1143  	}
  1144  }
  1145  
  1146  func TestHostConfigIsVM(t *testing.T) {
  1147  	testCases := []struct {
  1148  		desc   string
  1149  		config *HostConfig
  1150  		want   bool
  1151  	}{
  1152  		{
  1153  			desc: "non-ec2-vm",
  1154  			config: &HostConfig{
  1155  				VMImage:        "image-x",
  1156  				ContainerImage: "",
  1157  				IsEC2:          false,
  1158  			},
  1159  			want: true,
  1160  		},
  1161  		{
  1162  			desc: "non-ec2-container",
  1163  			config: &HostConfig{
  1164  				VMImage:        "",
  1165  				ContainerImage: "container-image-x",
  1166  				IsEC2:          false,
  1167  			},
  1168  			want: false,
  1169  		},
  1170  		{
  1171  			desc: "ec2-container",
  1172  			config: &HostConfig{
  1173  				VMImage:        "image-x",
  1174  				ContainerImage: "container-image-x",
  1175  				IsEC2:          true,
  1176  			},
  1177  			want: false,
  1178  		},
  1179  		{
  1180  			desc: "ec2-vm",
  1181  			config: &HostConfig{
  1182  				VMImage:        "image-x",
  1183  				ContainerImage: "",
  1184  				IsEC2:          true,
  1185  			},
  1186  			want: true,
  1187  		},
  1188  	}
  1189  	for _, tc := range testCases {
  1190  		t.Run(fmt.Sprintf(tc.desc), func(t *testing.T) {
  1191  			if got := tc.config.IsVM(); got != tc.want {
  1192  				t.Errorf("HostConfig.IsVM() = %t; want %t", got, tc.want)
  1193  			}
  1194  		})
  1195  	}
  1196  }
  1197  
  1198  func TestDefaultPlusExpBuild(t *testing.T) {
  1199  	for _, tc := range []struct {
  1200  		repo string
  1201  		want bool
  1202  	}{
  1203  		{"exp", true},
  1204  		{"build", true},
  1205  		{"anything", true},
  1206  		{"vulndb", false},
  1207  	} {
  1208  		got := defaultPlusExpBuild(tc.repo, "", "")
  1209  		if got != tc.want {
  1210  			t.Errorf("%s: got %t, want %t", tc.repo, got, tc.want)
  1211  		}
  1212  	}
  1213  }
  1214  
  1215  func TestHostsSort(t *testing.T) {
  1216  	data, err := os.ReadFile("builders.go")
  1217  	if err != nil {
  1218  		t.Fatal(err)
  1219  	}
  1220  	table := regexp.MustCompile(`(?s)\nvar Hosts =.*?\n}\n`).FindString(string(data))
  1221  	if table == "" {
  1222  		t.Fatal("cannot find Hosts table in builders.go")
  1223  	}
  1224  	m := regexp.MustCompile(`\n\t"([^"]+)":`).FindAllStringSubmatch(table, -1)
  1225  	if len(m) < 10 {
  1226  		t.Fatalf("cannot find host keys in table")
  1227  	}
  1228  	var last string
  1229  	for _, sub := range m {
  1230  		key := sub[1]
  1231  		if last > key {
  1232  			t.Errorf("Host table unsorted: %s before %s", last, key)
  1233  		}
  1234  		last = key
  1235  	}
  1236  }
  1237  
  1238  func TestBuildersPortedToLUCI(t *testing.T) {
  1239  	// Check that map keys refer to builder names that exist,
  1240  	// otherwise the entry is a no-op. Mostly to catch typos.
  1241  	for name := range BuildersPortedToLUCI {
  1242  		if _, ok := Builders[name]; !ok {
  1243  			t.Errorf("BuildersPortedToLUCI contains an unknown legacy builder name %v", name)
  1244  		}
  1245  	}
  1246  }
  1247  
  1248  func TestHostConfigCosArchitecture(t *testing.T) {
  1249  	testCases := []struct {
  1250  		desc       string
  1251  		hostConfig HostConfig
  1252  		want       CosArch
  1253  	}{
  1254  		{"default", HostConfig{}, CosArchAMD64},
  1255  		{"amd64", HostConfig{cosArchitecture: CosArchAMD64}, CosArchAMD64},
  1256  		{"arm64", HostConfig{cosArchitecture: CosArchARM64}, CosArchARM64},
  1257  	}
  1258  	for _, tc := range testCases {
  1259  		t.Run(tc.desc, func(t *testing.T) {
  1260  			if got := tc.hostConfig.CosArchitecture(); got != tc.want {
  1261  				t.Errorf("HostConfig.CosArchitecture() = %+v; want %+v", got, tc.want)
  1262  			}
  1263  		})
  1264  	}
  1265  }
  1266  
  1267  // listPorts lists supported Go ports
  1268  // found by running go tool dist list.
  1269  func listPorts() ([]string, error) {
  1270  	cmd := exec.Command("go", "tool", "dist", "list")
  1271  	out, err := cmd.Output()
  1272  	if err != nil {
  1273  		if ee := (*exec.ExitError)(nil); errors.As(err, &ee) {
  1274  			out = append(out, ee.Stderr...)
  1275  		}
  1276  		return nil, fmt.Errorf("%q failed: %s\n%s", cmd, err, out)
  1277  	}
  1278  	return strings.Fields(string(out)), nil
  1279  }