textmachine/platform/internal/gates/contract_test.go

42 lines
2.1 KiB
Go

package gates
import (
"os"
"path/filepath"
"regexp"
"testing"
"textmachine/platform/internal/httpapi"
)
// canonPath is the ratified API contract, from this package's directory. It is outside the zone on
// purpose: the contract belongs to `docs/` and this zone only serves it.
const canonPath = zoneRoot + "/../docs/architecture/14-api-contract/openapi.yaml"
// The constant a deployment announces itself with must be the version the ratified canon carries.
//
// Every other test of this constant compares the WIRE to the constant, which is self-consistent and
// passes at any value — the class PD-1 names. This is the only check with an independent second
// source, and it is the reason the constant went two ratifications without moving: `0.3.0` was
// served while `0.4.0` was the canon, so a client generated against what the deployment ANNOUNCES
// would have refused the shapes it actually returns (while the major is `0`, a differing minor
// carries breaking changes by design — canon §Versioning).
//
// It reads the canon rather than a copy of the number: a gate that holds a second copy of the fact
// is one more place to forget.
func TestTheAnnouncedContractVersionIsTheOneTheCanonRatified(t *testing.T) {
src, err := os.ReadFile(filepath.Join(canonPath))
if err != nil {
// Not skipped. A missing canon leaves this constant with no check at all except a human
// noticing, which is exactly what failed twice.
t.Fatalf("the ratified canon could not be read, so the served contract version has nothing to be checked against: %v", err)
}
// `info.version` and not any other `version:` in the document: the file carries several.
m := regexp.MustCompile(`(?m)^info:\n(?:[ \t]+.*\n)*?[ \t]+version: (\S+)`).FindSubmatch(src)
if m == nil {
t.Fatal("the canon carries no info.version: this gate reads the wrong document or the wrong shape")
}
if got, want := httpapi.ContractVersion, string(m[1]); got != want {
t.Errorf("this build announces contract %s and the ratified canon is %s; the constant is raised in the same change as the code that implements a minor, never afterwards", got, want)
}
}