package builder import ( "context" "os" "path/filepath" "strings" "testing" ) const aBundle = `{"module":"greeter","version":"1", "build":{"artifacts":[ {"name":"code","kind":"bundle","language":"typescript","entrypoints":["dist/index.js"]}]}, "resources":[ {"id":"files","type":"archive","path":"/opt/greeter","artifact":"code"}]}` // compiling is a runner that behaves like a toolchain: when asked to compile, it leaves output // where the toolchain says output lands. Without this the pack step has nothing to pack, and the // test would be asserting on a failure rather than on a build. type compiling struct{ *recorded } func (c compiling) run(ctx context.Context, dir, name string, args ...string) (string, error) { out, err := c.recorded.run(ctx, dir, name, args...) if name == "docker" && len(args) > 0 && args[0] == "run" { made := filepath.Join(dir, "dist") if err := os.MkdirAll(made, 0o755); err != nil { return "", err } if err := os.WriteFile(filepath.Join(made, "index.js"), []byte("console.log(1)"), 0o644); err != nil { return "", err } } return out, err } // **A module says what it is written in, and needs no Dockerfile.** This is the whole point of the // bundle recipe: the same module previously needed a hand-written recipe repeating an incantation // that is easy to get wrong in ways that fail somewhere else. func TestABundleIsCompiledAndPackedWithNoDockerfile(t *testing.T) { r, workspace := aRepository(t, aBundle, map[string]string{"index.ts": "console.log(1)"}) held := map[string]string{"mesh-tools/build": "registry.invalid/mesh-tools/build@sha256:" + strings.Repeat("b", 64)} got, err := Build(context.Background(), compiling{r}.run, r, "https://forge.invalid/greeter.git", "", "", workspace, held) if err != nil { t.Fatalf("a module with a language and no Dockerfile did not build: %v", err) } // Compiled in the toolchain the mesh chose, not in one the module named. var compiled string for _, line := range r.ran { if strings.HasPrefix(line, "docker run") { compiled = line } } if compiled == "" { t.Fatalf("nothing was compiled:\n%s", strings.Join(r.ran, "\n")) } if !strings.Contains(compiled, "mesh-tools/build@sha256:") { t.Fatalf("the compile did not run in the mesh's own toolchain: %s", compiled) } if strings.Contains(strings.Join(r.ran, "\n"), "docker build") { t.Fatalf("a bundle invoked a Dockerfile build, which is the thing it exists to avoid:\n%s", strings.Join(r.ran, "\n")) } // And pinned by a digest of what came out, like any other artifact. digest, _ := got.Manifest.Resources[0]["digest"].(string) if !strings.HasPrefix(digest, "sha256:") { t.Fatalf("the bundle was not pinned: %v", got.Manifest.Resources[0]) } } // **Refused before anything is built, naming what to build first.** A base the mesh has not built // is not a compile that fails on its first line — it is a question somebody can answer, and saying // it early is the difference between a fixable message and one about a missing image. func TestABundleWhoseToolchainIsNotHeldIsRefusedFirst(t *testing.T) { r, workspace := aRepository(t, aBundle, map[string]string{"index.ts": "console.log(1)"}) _, err := Build(context.Background(), compiling{r}.run, r, "https://forge.invalid/greeter.git", "", "", workspace, nil) if err == nil { t.Fatal("a bundle was built with no toolchain to compile it in") } if !strings.Contains(err.Error(), "mesh-tools") { t.Fatalf("the refusal does not name what has to be built first: %v", err) } for _, line := range r.ran { if strings.HasPrefix(line, "docker run") { t.Fatalf("a compile was attempted before the refusal: %s", line) } } } // A language the mesh does not build is refused the same way, and names what it can build. func TestABundleInAnUnknownLanguageIsRefused(t *testing.T) { manifest := strings.Replace(aBundle, `"language":"typescript"`, `"language":"cobol"`, 1) r, workspace := aRepository(t, manifest, map[string]string{"index.ts": "x"}) _, err := Build(context.Background(), compiling{r}.run, r, "https://forge.invalid/greeter.git", "", "", workspace, map[string]string{"mesh-tools/build": "registry.invalid/x@sha256:" + strings.Repeat("c", 64)}) if err == nil { t.Fatal("a language nothing can compile was accepted") } if !strings.Contains(err.Error(), "typescript") { t.Fatalf("the refusal does not say what would have worked: %v", err) } }