165 lines
7.0 KiB
Go
165 lines
7.0 KiB
Go
package seatgen
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// ADR 0627 §3's catalog check of a client, ADR 0625 §5's rule for what is hand-written, and module.json's Go package
|
|
// artifacts against the tree (ADR 0625 §1, §3): each row writes one tree and names what the checks must say of it.
|
|
func TestAClientUsesOnlyItsSeatAndTheRuntime(t *testing.T) {
|
|
m, err := Load("testdata/contracts", "example.org/contracts/go", "@example/contracts")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m.DomainSDK = "example.org/domain/sdk"
|
|
files, err := Generate(m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
const good = `package aregistryclient
|
|
|
|
import (
|
|
"context"
|
|
|
|
"example.org/contracts/go/seats/aregistry"
|
|
"git.novox.be/novox/mesh-sdk/go/keys"
|
|
)
|
|
|
|
func Publish(ctx context.Context) string { _ = keys.EscapeName; return "seat:" + aregistry.Seat + ".publish" }
|
|
`
|
|
const ts = `,{"name":"ts-aregistry","kind":"package","language":"typescript","paths":["ts/seats/aregistry"]},
|
|
{"name":"ts-bregistry","kind":"package","language":"typescript","paths":["ts/seats/bregistry"]}`
|
|
artifacts := func(extra string) string {
|
|
return `{"build":{"artifacts":[{"name":"go-aregistry","kind":"package","language":"go","paths":["go/seats/aregistry"]},
|
|
{"name":"go-bregistry","kind":"package","language":"go","paths":["go/seats/bregistry"]}` + ts + extra + `]}}`
|
|
}
|
|
clientArtifact := `,{"name":"go-aregistryclient","kind":"package","language":"go","paths":["go/clients/aregistryclient"]}`
|
|
for _, c := range []struct {
|
|
name string
|
|
tree map[string]string
|
|
module string
|
|
want []string
|
|
}{
|
|
{"no client: the seats alone", nil, artifacts(""), nil},
|
|
{"a client of its own seat over the runtime", map[string]string{
|
|
"go/clients/aregistryclient/go.mod": "module example.org/contracts/go/clients/aregistryclient\n",
|
|
"go/clients/aregistryclient/client.go": good,
|
|
}, artifacts(clientArtifact), nil},
|
|
{"a client with no artifact, and an artifact of no module", map[string]string{
|
|
"go/clients/aregistryclient/go.mod": "module example.org/contracts/go/clients/aregistryclient\n",
|
|
"go/clients/aregistryclient/client.go": good,
|
|
}, artifacts(`,{"name":"go-extra","kind":"package","language":"go","paths":["go/extra"]}`),
|
|
[]string{"module.json: no Go package artifact go-aregistryclient", "module.json: the Go package artifact go-extra is no seat's"}},
|
|
{"a seat's npm package with no artifact, one at another path, and one of no package", nil,
|
|
`{"build":{"artifacts":[{"name":"go-aregistry","kind":"package","language":"go","paths":["go/seats/aregistry"]},
|
|
{"name":"go-bregistry","kind":"package","language":"go","paths":["go/seats/bregistry"]},
|
|
{"name":"ts-aregistry","kind":"package","language":"typescript","paths":["ts"]},
|
|
{"name":"ts-onestore","kind":"package","language":"typescript","paths":["ts/seats/onestore"]}]}}`,
|
|
[]string{"module.json: no npm package artifact ts-bregistry", "module.json: the artifact ts-aregistry's paths are [ts], not [ts/seats/aregistry]",
|
|
"module.json: the npm package artifact ts-onestore is no seat's"}},
|
|
{"a client using its own sub-package, which is no other seat's client", map[string]string{
|
|
"go/clients/aregistryclient/go.mod": "module example.org/contracts/go/clients/aregistryclient\n",
|
|
"go/clients/aregistryclient/client.go": `package aregistryclient
|
|
|
|
import "example.org/contracts/go/clients/aregistryclient/provider"
|
|
|
|
var _ = provider.X
|
|
`,
|
|
}, artifacts(clientArtifact), nil},
|
|
{"a client importing its domain's SDK, which another module's is not", map[string]string{
|
|
"go/clients/aregistryclient/go.mod": "module example.org/contracts/go/clients/aregistryclient\n",
|
|
"go/clients/aregistryclient/client.go": `package aregistryclient
|
|
|
|
import (
|
|
"example.org/domain/sdk/reference"
|
|
"example.org/other/sdk/reference"
|
|
)
|
|
`,
|
|
}, artifacts(clientArtifact), []string{`client.go: imports example.org/other/sdk/reference: a client uses only`}},
|
|
{"a client of no seat defined whole, and one not a module of its own", map[string]string{
|
|
"go/clients/onestoreclient/x.go": "package onestoreclient\n",
|
|
"go/clients/aregistryclient/go.mod": "module example.org/contracts/go\n",
|
|
}, artifacts(clientArtifact + `,{"name":"go-onestoreclient","kind":"package","language":"go","paths":["go/clients/onestoreclient"]}`),
|
|
[]string{"go/clients/aregistryclient/go.mod: not", "go/clients/onestoreclient: the client of no seat defined whole"}},
|
|
{"a client using another seat, its client, a module's subject and tool", map[string]string{
|
|
"go/clients/aregistryclient/go.mod": "module example.org/contracts/go/clients/aregistryclient\n",
|
|
"go/clients/aregistryclient/client.go": `package aregistryclient
|
|
|
|
import (
|
|
"example.org/contracts/go/seats/bregistry"
|
|
"example.org/contracts/go/clients/bregistryclient"
|
|
"github.com/some/thing"
|
|
)
|
|
|
|
var a, b, c, d, e = bregistry.Seat, bregistryclient.X, thing.Y, "mesh.mod.holder.event.x", "seat:b-registry.publish"
|
|
var f = "records.records_search"
|
|
`,
|
|
}, artifacts(clientArtifact), []string{
|
|
`client.go: imports example.org/contracts/go/clients/bregistryclient, another seat's client`,
|
|
`client.go: imports example.org/contracts/go/seats/bregistry, not its own seat's contract`,
|
|
`client.go: imports github.com/some/thing: a client uses only`,
|
|
`client.go: names a module's subject "mesh.mod.holder.event.x"`,
|
|
`client.go: names a module's tool "records.records_search"`,
|
|
`client.go: names another seat "seat:b-registry.publish"`,
|
|
}},
|
|
} {
|
|
dir := t.TempDir()
|
|
write := func(p, s string) {
|
|
full := filepath.Join(dir, p)
|
|
if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(full, []byte(s), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
for p, b := range files {
|
|
write(p, string(b))
|
|
}
|
|
for p, s := range c.tree {
|
|
write(p, s)
|
|
}
|
|
write("module.json", c.module)
|
|
var got []string
|
|
cmp, err := Compare(dir, files)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got = append(got, cmp...)
|
|
for _, check := range []func(string, *Module) ([]string, error){CheckClients, CheckArtifacts} {
|
|
more, err := check(dir, m)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", c.name, err)
|
|
}
|
|
got = append(got, more...)
|
|
}
|
|
if len(got) != len(c.want) {
|
|
t.Errorf("%s: said %d problems, want %d:\n%s", c.name, len(got), len(c.want), strings.Join(got, "\n"))
|
|
continue
|
|
}
|
|
for _, w := range c.want {
|
|
found := false
|
|
for _, g := range got {
|
|
found = found || strings.Contains(g, w)
|
|
}
|
|
if !found {
|
|
t.Errorf("%s: no problem says %q:\n%s", c.name, w, strings.Join(got, "\n"))
|
|
}
|
|
}
|
|
}
|
|
// A hand-written file outside a client is still out of step (ADR 0625 §5).
|
|
dir := t.TempDir()
|
|
for p, b := range files {
|
|
full := filepath.Join(dir, p)
|
|
_ = os.MkdirAll(filepath.Dir(full), 0o755)
|
|
_ = os.WriteFile(full, b, 0o644)
|
|
}
|
|
_ = os.WriteFile(filepath.Join(dir, "go/seats/aregistry/helper.go"), []byte("package aregistry\n"), 0o644)
|
|
if out, _ := Compare(dir, files); len(out) != 1 || !strings.Contains(out[0], "helper.go: not written by the generator") {
|
|
t.Errorf("a hand-written file beside a contract: %v", out)
|
|
}
|
|
}
|