Files
mesh-catalog/modules/mesh-provisioner-client/cmd/mesh-provisioner-client/bound_gitea_test.go
T
jochen e7ff7c3045
mesh/merge-gate head e7ff7c3045fc merged into trunk afb94d925e94 — pass: builds mesh-provisioner-client → ace, g14, novox, shanks; no bus step; every machi…
mesh/repo-check head e7ff7c3045fc merged into trunk afb94d925e94 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
Write a provisioner client's files only on a change over the bus, never on a timer (issue 1129, ADR 0349 clause 4)
2026-10-18 18:08:50 +02:00

146 lines
6.8 KiB
Go

package main
import (
"context"
"os"
"strings"
"testing"
"github.com/nats-io/nats.go/jetstream"
)
// A handed gitea's server.env (issue 788): its template is the catalogue's own, and its machine's client fills it from
// its provider's entry as the provider's helper now writes it (`as`, and `at` and `from` among the values) and from
// the vault's rows, to the text the controller composed for the same values before it was handed.
const giteaEnvPath = "/etc/gitea/server.env"
func giteaTemplate(t *testing.T) string {
t.Helper()
raw, err := os.ReadFile("../../../gitea/files/server.env")
if err != nil {
t.Fatal(err)
}
return string(raw)
}
// giteaBoundExpected is that file as the controller rendered it: the database as the binding file told gitea.
func giteaBoundExpected(internalToken, password string) string {
return "GITEA__security__INTERNAL_TOKEN=" + internalToken + "\n" +
"GITEA__database__DB_TYPE=postgres\n" +
"GITEA__database__HOST=10.7.0.1:5432\n" +
"GITEA__database__NAME=mesh_g14_gitea\n" +
"GITEA__database__USER=mesh_g14_gitea\n" +
"GITEA__database__PASSWD=" + password + "\n" +
"GITEA__webhook__ALLOWED_HOST_LIST=172.17.0.1\n"
}
func giteaRun(t *testing.T, entry string, extra string) (*engine, *aBus, *reports) {
t.Helper()
b := startBus(t)
registryOf679(t, b)
vault := startVault(t, b)
vault.keep("own/g14/gitea/internal-token", "tok-never-on-the-bus", false)
vault.keep("pair/novox/postgres-database/g14/gitea", "pw-never-on-the-bus", false)
heard := b.listen(t)
e := startEngine(t, map[string]string{giteaEnvPath: "owned"})
tpl, _ := templates(t, map[string]string{"server.env": giteaTemplate(t) + extra})
b.assign(t, "gitea", Plan{Templates: tpl, Files: []PlannedFile{{ID: "env", Path: giteaEnvPath,
Template: "server.env", OwnerAtRuntime: "owned"}},
Secrets: []PlannedSecret{{Name: "internal-token"}},
Provisions: []PlannedProvision{{Name: "postgres-database", Provision: "postgres-database", Provider: "novox",
ProviderModule: "postgres", CredentialForm: "pair"}}})
kv, err := b.domain.CreateKeyValue(context.Background(), jetstream.KeyValueConfig{Bucket: "postgres_bound"})
if err != nil {
t.Fatal(err)
}
b.kv["postgres_bound"] = kv
b.put(t, "postgres_bound", node+".gitea.postgres-database", entry)
aClient(t, b, e, t.TempDir())
return e, b, heard
}
func TestNatsAHandedGiteasServerEnvIsFilledAsTheControllerComposedIt(t *testing.T) {
e, _, _ := giteaRun(t, `{"provider":"novox","provider-module":"postgres","provision":"postgres-database",`+
`"consumer":"g14","module":"gitea","as":"mesh_g14_gitea","user":"mesh_g14_gitea",`+
`"values":{"at":"10.7.0.1","from":"novox","port":5432},"vault-name":"pair/novox/postgres-database/g14/gitea"}`,
"FROM=${bound:postgres-database:from}\n")
eventually(t, "server.env is filled to the controller's text", func() bool {
return e.read(t, giteaEnvPath) == giteaBoundExpected("tok-never-on-the-bus", "pw-never-on-the-bus")+"FROM=novox\n"
})
}
// An entry without `at`, or without `from`, fills nothing: the module fails naming the key, never a file with a hole.
func TestNatsAnEntryWithoutAtOrFromLeavesGiteasServerEnvUnfilled(t *testing.T) {
for key, values := range map[string]string{"at": `{"from":"novox","port":5432}`, "from": `{"at":"10.7.0.1","port":5432}`} {
e, _, heard := giteaRun(t, `{"as":"mesh_g14_gitea","user":"mesh_g14_gitea","values":`+values+`}`,
"FROM=${bound:postgres-database:from}\n")
eventually(t, "the module fails for the missing "+key, func() bool {
r, _ := heard.last("gitea")
return r.Status == StatusFailed && strings.Contains(r.Reason, `no "`+key+`"`)
})
if got := e.read(t, giteaEnvPath); strings.Contains(got, "GITEA__database__HOST") {
t.Fatalf("without %s the file was filled: %q", key, got)
}
}
}
// A handed gitea's origins file (issue 792): filled by its machine's client from the route provider's entry, which
// carries the public name the controller composed for gitea, to the text the controller wrote for the binding file.
func TestNatsAHandedGiteasOriginsAreFilledFromTheRouteProvidersEntry(t *testing.T) {
const originsPath = "/etc/gitea/origins"
raw, err := os.ReadFile("../../../gitea/files/origins")
if err != nil {
t.Fatal(err)
}
b := startBus(t)
registryOf679(t, b)
startVault(t, b)
e := startEngine(t, map[string]string{originsPath: "owned"})
tpl, _ := templates(t, map[string]string{"origins": string(raw)})
b.assign(t, "gitea", Plan{Templates: tpl, Files: []PlannedFile{{ID: "origins", Path: originsPath,
Template: "origins", OwnerAtRuntime: "owned"}},
Provisions: []PlannedProvision{{Provision: "route", Provider: "novox", ProviderModule: "route-adapter"}}})
kv, err := b.domain.CreateKeyValue(context.Background(), jetstream.KeyValueConfig{Bucket: "route-adapter_bound"})
if err != nil {
t.Fatal(err)
}
b.kv["route-adapter_bound"] = kv
b.put(t, "route-adapter_bound", node+".gitea.route", `{"provider":"novox","provider-module":"route-adapter",`+
`"provision":"route","consumer":"g14","module":"gitea","as":"mesh_g14_gitea",`+
`"values":{"name":"git.example.org","internal-name":"git.novox.internal","name-web":"git.example.org"}}`)
aClient(t, b, e, t.TempDir())
eventually(t, "origins is filled to the controller's text", func() bool {
return e.read(t, originsPath) == "https://git.example.org\n"
})
}
// The same where route-proxy, not route-adapter, answers the route, as on novox (issue 792): filled by its machine's client from the route provider's entry, which
// carries the public name the controller composed for gitea, to the text the controller wrote for the binding file.
func TestNatsAHandedGiteasOriginsAreFilledFromRouteProxysEntryOnNovox(t *testing.T) {
const originsPath = "/etc/gitea/origins"
raw, err := os.ReadFile("../../../gitea/files/origins")
if err != nil {
t.Fatal(err)
}
b := startBus(t)
registryOf679(t, b)
startVault(t, b)
e := startEngine(t, map[string]string{originsPath: "owned"})
tpl, _ := templates(t, map[string]string{"origins": string(raw)})
b.assign(t, "gitea", Plan{Templates: tpl, Files: []PlannedFile{{ID: "origins", Path: originsPath,
Template: "origins", OwnerAtRuntime: "owned"}},
Provisions: []PlannedProvision{{Provision: "route", Provider: "novox", ProviderModule: "route-proxy"}}})
kv, err := b.domain.CreateKeyValue(context.Background(), jetstream.KeyValueConfig{Bucket: "route-proxy_bound"})
if err != nil {
t.Fatal(err)
}
b.kv["route-proxy_bound"] = kv
b.put(t, "route-proxy_bound", node+".gitea.route", `{"provider":"novox","provider-module":"route-proxy",`+
`"provision":"route","consumer":"g14","module":"gitea","as":"mesh_g14_gitea",`+
`"values":{"name":"git.example.org","internal-name":"git.novox.internal","name-web":"git.example.org"}}`)
aClient(t, b, e, t.TempDir())
eventually(t, "origins is filled to the controller's text", func() bool {
return e.read(t, originsPath) == "https://git.example.org\n"
})
}