package provision import ( "encoding/json" "sort" "testing" ) // The bootstrap.json key set is a CROSS-REPO contract: it must match felhom-controller's // internal/bootstrap.Bootstrap exactly. This test pins the emitted key set; the controller's // bootstrap_test.go ingests the same shape. A drift here (or there) breaks provisioning. func TestDoc_ContractKeySet(t *testing.T) { d := Doc{ Schema: SchemaV2, Customer: DocCustomer{ID: "c"}, Hub: DocHub{URL: "u", RetrievalPassword: "p"}, LocalAPI: DocLocalAPI{Endpoint: "ep", Fingerprint: "fp", Token: "tok"}, } b, err := d.render() if err != nil { t.Fatal(err) } var m map[string]json.RawMessage if err := json.Unmarshal(b, &m); err != nil { t.Fatal(err) } assertKeys(t, "top", m, []string{"schema", "customer", "hub", "local_api"}) var full struct { Customer map[string]json.RawMessage `json:"customer"` Hub map[string]json.RawMessage `json:"hub"` LocalAPI map[string]json.RawMessage `json:"local_api"` } if err := json.Unmarshal(b, &full); err != nil { t.Fatal(err) } // v2: customer carries only id; hub carries url + retrieval_password (NO api_key/host_id). assertKeys(t, "customer", full.Customer, []string{"id"}) assertKeys(t, "hub", full.Hub, []string{"url", "retrieval_password"}) assertKeys(t, "local_api", full.LocalAPI, []string{"endpoint", "fingerprint", "token"}) if SchemaV2 != "felhom.bootstrap/v2" { t.Fatalf("schema drift: %q", SchemaV2) } } func assertKeys(t *testing.T, label string, m map[string]json.RawMessage, want []string) { t.Helper() got := make([]string, 0, len(m)) for k := range m { got = append(got, k) } sort.Strings(got) sort.Strings(want) if len(got) != len(want) { t.Fatalf("%s: key set %v, want %v", label, got, want) } for i := range want { if got[i] != want[i] { t.Fatalf("%s: key set %v, want %v", label, got, want) } } }