The two halves of an object-store edge, as a readable pair
Manifests for a provider and a consumer, so the contract can be read rather than only exercised through a lab fixture that stages the grants by hand. Checked as a pair rather than separately, because two manifests that only ever parse alone are two manifests nobody has held against each other. The test asserts the names match, that each side says where it wants to be told, and that the consumer contributes the key the provisioner actually reads. That last one is the trap worth having a test for: a consumer contributing "name" — which is exactly what a database consumer contributes — resolves cleanly, deploys, and then fails on the machine with "asked for a bucket and did not name it". Nothing in that message points back at the manifest that caused it. Both mistakes were made while writing these two files.
This commit is contained in:
@@ -214,3 +214,52 @@ func TestTheResolverDoesNotAskItselfForUpstreams(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The two halves of an object-store edge, as a pair.
|
||||
//
|
||||
// A provider and a consumer that only ever appear separately are two manifests nobody has checked
|
||||
// against each other: the name one provides has to be the name the other requires, and the key a
|
||||
// consumer contributes has to be the one the provisioner reads. Both were got wrong while writing
|
||||
// them, and neither would have been caught by parsing either file alone.
|
||||
func TestTheObjectStoreEdgeFitsTogether(t *testing.T) {
|
||||
provider := read(t, "object-store.json")
|
||||
consumer := read(t, "photos.json")
|
||||
|
||||
const provision = "s3-bucket"
|
||||
|
||||
var provides bool
|
||||
for _, offer := range provider.Provides {
|
||||
if offer.Name == provision {
|
||||
provides = true
|
||||
}
|
||||
}
|
||||
if !provides {
|
||||
t.Fatalf("the provider does not offer %q", provision)
|
||||
}
|
||||
if !strings.Contains(strings.Join(consumer.Requires, ","), provision) {
|
||||
t.Fatalf("the consumer does not require %q", provision)
|
||||
}
|
||||
|
||||
// Where each side wants to be told. A provider that receives nowhere is a provider the mesh
|
||||
// writes nothing for, and a provisioner with nothing to read.
|
||||
if provider.Receives[provision] == "" {
|
||||
t.Error("the provider says nowhere to write what its consumers asked for")
|
||||
}
|
||||
if provider.Grants[provision] == "" {
|
||||
t.Error("the provider says nowhere to write its consumers' credentials")
|
||||
}
|
||||
if consumer.Binds[provision] == "" {
|
||||
t.Error("the consumer says nowhere to be told where its bucket is")
|
||||
}
|
||||
if consumer.Secrets[provision] == "" {
|
||||
t.Error("the consumer says nowhere to be given its key")
|
||||
}
|
||||
|
||||
// The key the provisioner reads out of `values`. It looks for `bucket`, so a consumer
|
||||
// contributing `name` — which is what the database one contributes — resolves cleanly and
|
||||
// then fails on the machine with "asked for a bucket and did not name it".
|
||||
if _, named := consumer.Contributes[provision]["bucket"]; !named {
|
||||
t.Errorf("the consumer contributes %v, and the provisioner reads \"bucket\"",
|
||||
consumer.Contributes[provision])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user