- App-scoped typed Publish/Lookup with duplicate-provider errors - Set plugin IDs before Register so HasPlugin sees the full set - Greeter uses pact.OptionalMessage without importing optional
130 lines
3.6 KiB
Go
130 lines
3.6 KiB
Go
package build
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestLoadHelloManifest(t *testing.T) {
|
|
m, err := LoadManifest(filepath.Join("..", "..", "examples", "hello", "summer.yaml"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if m.Binary != "hello" {
|
|
t.Fatalf("binary = %q", m.Binary)
|
|
}
|
|
if len(m.Plugins) != 3 || m.Plugins[0].ID != "golem15.hello" || m.Plugins[1].ID != "golem15.greeter" || m.Plugins[2].ID != "golem15.optional" {
|
|
t.Fatalf("plugins = %+v", m.Plugins)
|
|
}
|
|
}
|
|
|
|
func TestParseManifestRejectsDuplicatesAndInvalidPaths(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
t.Run("duplicate id", func(t *testing.T) {
|
|
path := filepath.Join(dir, "dup.yaml")
|
|
write(t, path, "module: example.com/app\nbinary: app\nplugins:\n - id: a.b\n module: example.com/one\n - id: a.b\n module: example.com/two\n")
|
|
if _, err := LoadManifest(path); err == nil || !strings.Contains(err.Error(), "a.b") {
|
|
t.Fatalf("want duplicate id error, got %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("invalid module", func(t *testing.T) {
|
|
path := filepath.Join(dir, "bad.yaml")
|
|
write(t, path, "module: example.com/app\nbinary: app\nplugins:\n - id: a.b\n module: \"example.com/one; rm -rf /\"\n")
|
|
if _, err := LoadManifest(path); err == nil {
|
|
t.Fatal("want invalid module error")
|
|
}
|
|
})
|
|
|
|
t.Run("path traversal module", func(t *testing.T) {
|
|
path := filepath.Join(dir, "dotdot.yaml")
|
|
write(t, path, "module: example.com/app\nbinary: app\nplugins:\n - id: a.b\n module: example.com/../evil\n")
|
|
if _, err := LoadManifest(path); err == nil {
|
|
t.Fatal("want invalid module error")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGenerateStableQuotedImportsInManifestOrder(t *testing.T) {
|
|
m := Manifest{
|
|
Module: "example.com/app",
|
|
Binary: "hello",
|
|
Plugins: []Plugin{
|
|
{ID: "golem15.hello", Module: "example.com/app/plugins/base"},
|
|
{ID: "golem15.greeter", Module: "example.com/app/plugins/greeter"},
|
|
},
|
|
}
|
|
first, err := generatePluginsGen(m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
second, err := generatePluginsGen(m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !bytes.Equal(first, second) {
|
|
t.Fatal("generated plugins.gen.go is not byte-stable")
|
|
}
|
|
src := string(first)
|
|
baseAt := strings.Index(src, `example.com/app/plugins/base`)
|
|
greeterAt := strings.Index(src, `example.com/app/plugins/greeter`)
|
|
if baseAt < 0 || greeterAt < 0 || baseAt > greeterAt {
|
|
t.Fatalf("imports not in manifest order:\n%s", src)
|
|
}
|
|
if !strings.Contains(src, "\t_ \"example.com/app/plugins/base\"") {
|
|
t.Fatalf("import is not Go-quoted:\n%s", src)
|
|
}
|
|
|
|
mainSrc, err := generateMain(m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
again, err := generateMain(m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !bytes.Equal(mainSrc, again) {
|
|
t.Fatal("generated main.go is not byte-stable")
|
|
}
|
|
if !bytes.Contains(mainSrc, []byte(`bonfire.NewRoot("hello"`)) {
|
|
t.Fatalf("main does not use manifest binary:\n%s", mainSrc)
|
|
}
|
|
if bytes.Contains(mainSrc, []byte("examples/hello")) {
|
|
t.Fatal("generated main hard-codes examples/hello")
|
|
}
|
|
}
|
|
|
|
func TestWriteIfChangedSkipsIdenticalBytes(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "out.go")
|
|
content := []byte("package main\n")
|
|
if err := writeIfChanged(path, content); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := writeIfChanged(path, content); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
again, err := os.Stat(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !info.ModTime().Equal(again.ModTime()) {
|
|
t.Fatal("identical content rewrote the file")
|
|
}
|
|
}
|
|
|
|
func write(t *testing.T, path, body string) {
|
|
t.Helper()
|
|
if err := os.WriteFile(path, []byte(body), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|