Files
mesh-controller/internal/link/conformance_integration_test.go
T

149 lines
5.2 KiB
Go

//go:build integration
package link
import (
"bytes"
"encoding/json"
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"strings"
"testing"
"time"
"github.com/novox/mesh-controller/internal/beside"
)
func loadFixture(t *testing.T, name string) fixture {
t.Helper()
raw, from, err := sdkFixture(os.Getenv(beside.Env), goModFile, capturedSDK, capturedLog, name)
if err != nil {
// Failed, never skipped: a skip here passed the suite with nothing judged.
t.Fatal(err)
}
t.Logf("%s: %s", name, from)
if strings.HasPrefix(from, notJudged) {
// Said on the check's own output too, where `go test` without -v prints no log of a passing test.
saidNotJudged.Do(func() { fmt.Fprintln(os.Stderr, "internal/link conformance: "+from) })
}
var f fixture
if err := json.Unmarshal(raw, &f); err != nil {
t.Fatalf("%s: %v", name, err)
}
return f
}
func sdkFixture(root, goMod, captured, capturedLog, name string) ([]byte, string, error) {
file := path.Join("conformance", name)
readCaptured := func() ([]byte, error) {
raw, err := os.ReadFile(filepath.Join(captured, filepath.FromSlash(file)))
if err != nil {
return nil, fmt.Errorf("the captured SDK's %s: %w", file, err)
}
return raw, nil
}
if root == "" {
raw, err := readCaptured()
return raw, "the copy captured in testdata/beside (see CAPTURED); a merge check reads the SDK's clone " +
"at this tree's pin", err
}
clone := filepath.Join(root, "mesh-sdk")
if _, err := os.Stat(clone); err != nil {
// A build seat asked by a controller from before mesh-controller #220 places no mesh-sdk beside the
// check, so #220 could never pass its own check if this failed. Until #220 has rolled out, the
// captured copy is read and the log says so loudly; the follow-up of novox/hq issue 449 makes this
// a failure again.
at, cerr := capturedCommit(capturedLog)
if cerr != nil {
return nil, "", cerr
}
raw, rerr := readCaptured()
return raw, fmt.Sprintf(notJudged+": the seat placed no mesh-sdk beside this check in "+
"%s=%s (it does once mesh-controller #220 has rolled out); read the captured copy at %s", beside.Env,
root, at), rerr
}
ref, err := sdkRef(goMod)
if err != nil {
return nil, "", err
}
raw, err := gitShow(clone, ref, file)
if err != nil {
return nil, "", fmt.Errorf("the mesh-sdk clone beside this check has no %s at %s, the SDK this tree's "+
"go.mod pins: %w", file, ref, err)
}
// The captured copy is the SDK's own, never edited by hand: the clone at the captured commit says so.
at, err := capturedCommit(capturedLog)
if err != nil {
return nil, "", err
}
theirs, err := gitShow(clone, at, file)
if err != nil {
return nil, "", fmt.Errorf("the mesh-sdk clone has no %s at %s, the commit CAPTURED names: %w", file, at, err)
}
ours, err := os.ReadFile(filepath.Join(captured, filepath.FromSlash(file)))
if err != nil {
return nil, "", fmt.Errorf("the captured SDK's %s: %w", file, err)
}
if !bytes.Equal(ours, theirs) {
return nil, "", fmt.Errorf("the captured %s is not mesh-sdk's at %s, the commit CAPTURED names: it was "+
"edited or captured wrong; capture it again as CAPTURED says", file, at)
}
return raw, "mesh-sdk cloned beside this check, at " + ref + " (this tree's go.mod)", nil
}
func gitShow(repository, ref, file string) ([]byte, error) {
cmd := exec.Command("git", "-c", "safe.directory=*", "-C", repository, "show", ref+":"+file)
var stderr bytes.Buffer
cmd.Stderr = &stderr
out, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("git show %s:%s: %v: %s", ref, file, err, strings.TrimSpace(stderr.String()))
}
return out, nil
}
func TestTheGoEmitterSetsEveryRequiredHeader(t *testing.T) {
f := loadFixture(t, "events/module-event.json")
sent := goEventHeaders(f.Given.Key, f.Given.Module, f.Given.Node)
for _, want := range f.Wire.RequiredHeaders {
if _, ok := sent[want]; !ok {
t.Errorf("the Go emitter does not set %q, which the fixture requires — an event it "+
"emits is one a conforming consumer refuses", want)
}
}
}
func TestTheGoEmittersHeaderFormatsMatch(t *testing.T) {
f := loadFixture(t, "events/module-event.json")
sent := goEventHeaders(f.Given.Key, f.Given.Module, f.Given.Node)
if got := sent["content-type"]; got != f.Wire.HeaderFormats["content-type"] {
t.Errorf("content-type is %q, the fixture says %q", got, f.Wire.HeaderFormats["content-type"])
}
if _, err := time.Parse(time.RFC3339, sent["x-time"]); err != nil {
t.Errorf("x-time %q is not RFC3339, which the fixture requires: %v", sent["x-time"], err)
}
if pattern := f.Wire.HeaderFormats["x-event-id"]; pattern != "" {
if !regexp.MustCompile(pattern).MatchString(sent["x-event-id"]) {
t.Errorf("x-event-id %q does not match %q", sent["x-event-id"], pattern)
}
}
// The origin the envelope claims is the one the bus enforces by namespace. A disagreement
// here means the envelope is lying about where it came from.
if sent["x-source"] != f.Given.Module {
t.Errorf("x-source is %q for module %q", sent["x-source"], f.Given.Module)
}
}
func TestTheGoSubjectMatchesTheFixture(t *testing.T) {
f := loadFixture(t, "events/module-event.json")
got := "mesh.mod." + f.Given.Module + ".event." + f.Given.Key
if got != f.Wire.Subject {
t.Errorf("this implementation would publish on %q; the fixture says %q", got, f.Wire.Subject)
}
}