Files
mesh-controller/internal/builder/go_toolchain_test.go
T
jschoubben 0983b00284 The mesh can compile Go, which is why nothing delivered the host
novox/hq 04-ISSUES/142, and ADR 0141's own progressive insight naming
this as the first of two things missing: "nothing can compile it". The
toolchain list was a closed set of typescript and python, whose warning —
every language is another implementation of the contracts modules share —
does not attach to Go. Go is how the host, the control plane and the
builder are written, and none of them is a module in that sense: the host
is what APPLIES modules.

The toolchain names mesh-tools-go as its base rather than pinning an
upstream release here (ADR 0142, 0044): named and not pinned means the
mesh answers with the copy it holds, and moving compiler is a build
instead of an edit to this file.

Two things beyond the list also assumed one language, and both would have
failed after the entry was added:

  sourcesFor turned every entrypoint into a `.ts` file. The extension is
  the toolchain's now — one language's file extension written into the
  code that serves every language is a wall the next one hits.

  The output directory was the compiler's to create. tsc --outDir makes
  one; go build -o writes into a directory and does not make it, failing
  with a message about a path rather than about a build. Made here for
  every toolchain, because which compilers are forgiving is not something
  a reader should have to know.

And a toolchain now says what it is pointed at: a file list from the
module's entrypoints, or the one package the artifact is built `from`.
Pointing `go build` at a file list builds a program out of exactly those
files and ignores the rest of the package — a missing symbol rather than a
legible refusal.

Static and -trimpath: what a machine holds is a file, not a container, so
a binary needing a libc it did not bring is a delivery that works until a
machine differs; and a version comes from where a component sits rather
than from its linker, so two builds of one commit are the same bytes.
2026-09-30 09:48:50 +02:00

72 lines
2.8 KiB
Go

package builder
import (
"strings"
"testing"
)
// Nothing could compile the mesh's own components, which is why nothing delivers the host
// (novox/hq 04-ISSUES/142, and ADR 0141's own insight naming it). The toolchain list was a closed
// set of typescript and python, and two things in the path beyond it assumed TypeScript.
func TestTheMeshCanCompileGo(t *testing.T) {
chain, err := ToolchainFor("go")
if err != nil {
t.Fatal(err)
}
// Named, not pinned: the mesh answers with the copy it holds, so moving compiler is a build
// rather than an edit to this source (ADR 0044, 0142).
if chain.Base != "mesh-tools-go" || chain.Artifact != "build" {
t.Fatalf("the go toolchain is based on %s/%s", chain.Base, chain.Artifact)
}
joined := strings.Join(chain.Compile, " ")
// Static, because what a machine holds is a file and not a container: a binary needing a libc
// it did not bring is a delivery that works until a machine differs.
if !strings.Contains(joined, "CGO_ENABLED=0") {
t.Fatalf("the go toolchain does not build statically: %q", joined)
}
// Reproducible: a version comes from where a component sits, not from its linker (ADR 0142),
// so two builds of one commit should produce the same bytes.
if !strings.Contains(joined, "-trimpath") {
t.Fatalf("the go toolchain leaves build paths in the binary: %q", joined)
}
if chain.Unit != UnitPackage {
t.Fatalf("the go toolchain compiles %q, wanted a package", chain.Unit)
}
}
func TestEveryToolchainSaysWhatItIsPointedAt(t *testing.T) {
// The field exists because the compile path used to assume one language. A toolchain that says
// nothing would fall through to the entrypoint branch and compile a file list, which for a
// compiled language builds a program out of exactly those files and ignores the rest of the
// package — a missing symbol rather than a legible refusal.
for _, chain := range toolchains {
switch chain.Unit {
case UnitPackage:
case UnitSources:
if chain.SourceExt == "" {
t.Fatalf("%s compiles a file list and names no source extension", chain.Language)
}
if !strings.HasPrefix(chain.SourceExt, ".") {
t.Fatalf("%s's source extension %q is not an extension", chain.Language, chain.SourceExt)
}
default:
t.Fatalf("%s says it is pointed at %q, which is neither sources nor a package",
chain.Language, chain.Unit)
}
}
}
func TestAnEntrypointBecomesASourceInItsOwnLanguage(t *testing.T) {
// It used to become a `.ts` whatever the language was.
out := Out("build")
got := sourcesFor([]string{out + "/tools/index.js"}, out, ".ts")
if len(got) != 1 || got[0] != "tools/index.ts" {
t.Fatalf("a typescript entrypoint became %v", got)
}
got = sourcesFor([]string{out + "/tools/index.js"}, out, ".py")
if len(got) != 1 || got[0] != "tools/index.py" {
t.Fatalf("a python entrypoint became %v", got)
}
}