// Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause package tailscaleroot import ( "fmt" "os" "os/exec" "runtime" "strings" "testing" "golang.org/x/mod/modfile" ) func TestDockerfileVersion(t *testing.T) { goVersion := mustGetGoModVersion(t, false) dockerFile, err := os.ReadFile("Dockerfile") if err != nil { t.Fatal(err) } wantSub := fmt.Sprintf("FROM golang:%s-alpine AS build-env", goVersion) if !strings.Contains(string(dockerFile), wantSub) { t.Errorf("didn't find %q in Dockerfile", wantSub) } } // TestGoVersion tests that the Go version specified in go.mod matches ./tool/go version. func TestGoVersion(t *testing.T) { // We could special-case ./tool/go path for Windows, but really there is no // need to run it there. if runtime.GOOS == "windows" { t.Skip("Skipping test on Windows") } goModVersion := mustGetGoModVersion(t, true) goToolCmd := exec.Command("./tool/go", "version") goToolOutput, err := goToolCmd.Output() if err != nil { t.Fatalf("Failed to get ./tool/go version: %v", err) } // Version info will approximately look like 'go version go1.24.4 linux/amd64'. parts := strings.Fields(string(goToolOutput)) if len(parts) < 4 { t.Fatalf("Unexpected ./tool/go version output format: %s", goToolOutput) } goToolVersion := strings.TrimPrefix(parts[2], "go") if goModVersion != goToolVersion { t.Errorf("Go version in go.mod (%q) does not match the version of ./tool/go (%q).\nEnsure that the go.mod refers to the same Go version as ./go.toolchain.rev.", goModVersion, goToolVersion) } } func mustGetGoModVersion(t *testing.T, includePatchVersion bool) string { t.Helper() goModBytes, err := os.ReadFile("go.mod") if err != nil { t.Fatal(err) } modFile, err := modfile.Parse("go.mod", goModBytes, nil) if err != nil { t.Fatal(err) } if modFile.Go == nil { t.Fatal("no Go version found in go.mod") } version := modFile.Go.Version parts := strings.Split(version, ".") if !includePatchVersion { if len(parts) >= 2 { version = parts[0] + "." + parts[1] } } return version }