summaryrefslogtreecommitdiffhomepage
path: root/cache_key_test.go
blob: 8600bcd719f04eebb39f931834e5f1e4dbd57531 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause

package tailscaleroot

import (
	"os"
	"os/exec"
	"strings"
	"testing"

	"tailscale.com/util/cibuild"
)

// TestTsgoRevInCacheKey verifies that the Tailscale Go toolchain's git
// revision (from go.toolchain.rev) is blended into Go build cache keys.
// Without this, bumping the toolchain to a new commit that doesn't change
// the Go version number would silently reuse stale cached build artifacts.
//
// See https://github.com/tailscale/tailscale/issues/36589.
func TestTsgoRevInCacheKey(t *testing.T) {
	goRoot := goEnv(t, "GOROOT")
	isTsgo := strings.Contains(goRoot, "/.cache/tsgo/")
	if !cibuild.On() && !isTsgo {
		t.Skip("skipping; not in CI and not using the Tailscale Go toolchain")
	}

	rev := strings.TrimSpace(GoToolchainRev)
	if rev == "" {
		t.Fatal("go.toolchain.rev is empty")
	}

	// Build the small stdlib "errors" package with GODEBUG=gocachehash=1,
	// which causes cmd/go to log its cache key computations to stderr.
	cmd := exec.Command("go", "build", "errors")
	cmd.Env = append(os.Environ(), "GODEBUG=gocachehash=1")
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("go build errors failed: %v\n%s", err, out)
	}

	// The cache key output should contain the toolchain rev alongside the
	// Go version, e.g.:
	//   HASH[moduleIndex]: "go1.26.2 dfe2a5fd8ee2e68b08ce5ff259269f50ecadf2f4"
	if !strings.Contains(string(out), rev) {
		t.Errorf("go.toolchain.rev %q not found in GODEBUG=gocachehash=1 output:\n%s", rev, out)
	}
}

func goEnv(t *testing.T, key string) string {
	t.Helper()
	out, err := exec.Command("go", "env", key).Output()
	if err != nil {
		t.Fatalf("go env %s: %v", key, err)
	}
	return strings.TrimSpace(string(out))
}