package catalogue import ( "strings" "testing" ) // Each test names the decision it defends: novox/hq ADR 0225, which refines ADR 0049 after issue 263. // The provision a module requires sets the bound on its identity, not the tightest backend anywhere. func TestABoundIsTheProvisionsOwn(t *testing.T) { store := Manifest{Module: "objects", Provides: []Offer{{Name: "s3-bucket", Scope: ScopeMesh, Identity: &OfferIdentity{Max: 20, In: "an S3 access key"}}}, Receives: map[string]string{"s3-bucket": "/var/lib/mesh/objects/mesh.json"}} database := Manifest{Module: "db", Provides: []Offer{{Name: "postgres-database", Scope: ScopeMesh, Identity: &OfferIdentity{Max: 63, In: "a PostgreSQL role"}}}, Receives: map[string]string{"postgres-database": "/var/lib/mesh/db/mesh.json"}} if b := store.IdentityBoundOf("s3-bucket"); b.Max != 20 || b.In != "an S3 access key" { t.Errorf("an object store's stated bound was not taken: %+v", b) } if b := database.IdentityBoundOf("postgres-database"); b.Max != 63 { t.Errorf("a database's stated bound was not taken: %+v", b) } // mesh_workstation_keycloak is 25: refused by the object store, accepted by the database. if CheckIdentityWithin("workstation", "keycloak", store.IdentityBoundOf("s3-bucket")) == nil { t.Error("a 25-character identity fit a 20-character access key") } if err := CheckIdentityWithin("workstation", "keycloak", database.IdentityBoundOf("postgres-database")); err != nil { t.Errorf("a database consumer paid the object store's limit: %v", err) } } // What an offer leaves unsaid follows from whether its provider can keep a name at all. func TestAnUnstatedBoundFollowsWhatTheProviderIsTold(t *testing.T) { // Told nothing about its consumers — no receives, nothing served from their identity: no bound. // The resolver provision is exactly this, and its consumers paid an object store's limit (263). resolver := Manifest{Module: "resolver", Provides: []Offer{{Name: "wildcard-resolution", Scope: ScopeMesh}}} if b := resolver.IdentityBoundOf("wildcard-resolution"); b.Bounded() { t.Errorf("a provision that is told nothing of its consumers bounds them: %+v", b) } // Told each consumer and silent about its backend: the old global bound, not none. told := Manifest{Module: "told", Provides: []Offer{{Name: "thing", Scope: ScopeMesh}}, Receives: map[string]string{"thing": "/var/lib/mesh/told/mesh.json"}} if b := told.IdentityBoundOf("thing"); b.Max != DefaultIdentityLimit { t.Errorf("a provider told its consumers and silent about its backend is not held to %d: %+v", DefaultIdentityLimit, b) } // Serving a value built from the identity is being told it, too. serving := Manifest{Module: "serving", Provides: []Offer{{Name: "bucket", Scope: ScopeMesh}}, Serves: map[string]map[string]any{"bucket": {"name": "b-${consumer:as:dns}"}}} if b := serving.IdentityBoundOf("bucket"); b.Max != DefaultIdentityLimit { t.Errorf("a provider deriving a name from its consumers is not bounded: %+v", b) } // And `false` says it outright, even for a provider that receives. routes := Manifest{Module: "routes", Provides: []Offer{{Name: "route", Scope: ScopeMesh, Identity: &OfferIdentity{None: true}}}, Receives: map[string]string{"route": "/var/lib/mesh/routes/mesh.json"}} if b := routes.IdentityBoundOf("route"); b.Bounded() { t.Errorf("`identity: false` still bounds: %+v", b) } } // The consumer's side of the same judgement the provider's composition makes: what `status` says. func TestAnOverflowingRequirementIsNamedFromTheConsumersSide(t *testing.T) { bound := IdentityBound{Max: 20, In: "an S3 access key"} r := Resolution{Node: "laptop", Modules: []Manifest{{Module: "photoalbum"}, {Module: "files"}, {Module: "gallery", Slug: "gal"}}, Needs: []Needed{ {Name: "s3-bucket", From: "anchor", For: "photoalbum", Identity: bound}, {Name: "s3-bucket", From: "anchor", For: "photoalbum", Local: "second", Identity: bound}, {Name: "s3-bucket", From: "anchor", For: "files", Identity: bound}, {Name: "s3-bucket", From: "anchor", For: "gallery", Identity: bound}, {Name: "licence", From: "records", For: "photoalbum", ByRecord: true, Identity: bound}, }} got := r.Overflowing() if len(got) != 1 || got[0].Module != "photoalbum" || got[0].Identity != "mesh_laptop_photoalbum" || got[0].Provider != "anchor" { t.Fatalf("one overflow, once, was expected: %+v", got) } if said := got[0].String(); !strings.Contains(said, "an S3 access key keeps 20") || !strings.Contains(said, "slug") { t.Fatalf("the overflow does not say what keeps it or the remedy: %s", said) } }