Resolve collection identity during strict composition
This commit is contained in:
@@ -437,10 +437,7 @@ func TestComposeDocumentsValidatesRegisteredSequenceSingletons(t *testing.T) {
|
||||
wantCode Code
|
||||
}{
|
||||
{name: "nonmapping item", body: "records: [plain]\n", path: "/records/0", wantCode: CodeComposeInvalid},
|
||||
{name: "missing identity", body: "records: [{name: plain}]\n", path: "/records/0", wantCode: CodeComposeInvalid},
|
||||
{name: "null identity", body: "records: [{id: null}]\n", path: "/records/0/id", wantCode: CodeComposeInvalid},
|
||||
{name: "numeric identity", body: "records: [{id: 12}]\n", path: "/records/0/id", wantCode: CodeComposeInvalid},
|
||||
{name: "boolean identity", body: "records: [{id: false}]\n", path: "/records/0/id", wantCode: CodeComposeInvalid},
|
||||
{name: "missing identity", body: "records: [{name: plain}]\n", path: "/records/0/id", wantCode: CodeComposeInvalid},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -458,14 +455,138 @@ func TestComposeDocumentsValidatesRegisteredSequenceSingletons(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestComposeDocumentsUsesLowerIdentityForStrictPeers(t *testing.T) {
|
||||
path := Keys("records")
|
||||
lower := collectionPolicyScope{collections: map[string]collectionPolicyEntry{
|
||||
path.String(): {
|
||||
destination: path,
|
||||
policy: collectionPolicy{identityFields: []string{"id"}, identityPresent: true},
|
||||
},
|
||||
}}
|
||||
composed, diagnostics := composeDocumentsWithCollectionPolicy(
|
||||
sequencePolicy{}, lower, nil,
|
||||
parseCompositionDocument(t, "source-1", "records: [{id: first}]\n"),
|
||||
parseCompositionDocument(t, "source-2", "records: [{id: second}]\n"),
|
||||
)
|
||||
if len(diagnostics) != 0 {
|
||||
t.Fatalf("compose strict peers with lower identity: %#v", diagnostics)
|
||||
}
|
||||
value, present := documentAtPath(composed.root, path)
|
||||
if !present || value.Kind != document.Sequence || len(value.Sequence) != 2 {
|
||||
t.Fatalf("composed records = %#v, %v; want two strict peer records", value, present)
|
||||
}
|
||||
resolved, present := composed.collectionPolicies.collections[path.String()]
|
||||
if !present || !resolved.policy.identityPresent || !reflect.DeepEqual(resolved.policy.identityFields, []string{"id"}) {
|
||||
t.Fatalf("composed collection policy = %#v, %v; want retained lower identity", resolved, present)
|
||||
}
|
||||
clone := cloneComposedDocument(composed)
|
||||
resolved.policy.identityFields[0] = "mutated"
|
||||
if !reflect.DeepEqual(clone.collectionPolicies.collections[path.String()].policy.identityFields, []string{"id"}) {
|
||||
t.Fatal("cloned composition shares mutable collection identity fields")
|
||||
}
|
||||
}
|
||||
|
||||
func TestComposeDocumentsResolvesDeclarationsBeforePeerComposition(t *testing.T) {
|
||||
path := Keys("records")
|
||||
declaration := func(source string, line int, fields ...string) sequenceDeclarationSpec {
|
||||
location := Location{SourceID: source, Line: line}
|
||||
return sequenceDeclarationSpec{
|
||||
destination: path, identityFields: fields, identityPresent: true,
|
||||
identityLocation: &location,
|
||||
}
|
||||
}
|
||||
|
||||
_, diagnostics := composeDocumentsWithCollectionPolicy(
|
||||
sequencePolicy{}, collectionPolicyScope{},
|
||||
[]sequenceDeclarationSpec{declaration("source-1", 2, "id"), declaration("source-2", 4, "name")},
|
||||
parseCompositionDocument(t, "source-1", "left: true\n"),
|
||||
parseCompositionDocument(t, "source-2", "right: true\n"),
|
||||
)
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceConflict || diagnostics[0].Path.String() != "/records" {
|
||||
t.Fatalf("conflicting policy-only declarations = %#v", diagnostics)
|
||||
}
|
||||
if diagnostics[0].Primary == nil || len(diagnostics[0].Related) != 1 {
|
||||
t.Fatalf("declaration conflict lacks both locations: %#v", diagnostics[0])
|
||||
}
|
||||
|
||||
composed, diagnostics := composeDocumentsWithCollectionPolicy(
|
||||
sequencePolicy{}, collectionPolicyScope{},
|
||||
[]sequenceDeclarationSpec{declaration("source-1", 2, "tenant", "id"), declaration("source-2", 4, "id", "tenant")},
|
||||
parseCompositionDocument(t, "source-1", "records: [{tenant: true, id: null}, {tenant: \"alpha\", id: 1}]\n"),
|
||||
parseCompositionDocument(t, "source-2", "records: [{id: 1.0, tenant: \"beta\"}, {id: \"1\", tenant: \"alpha\"}]\n"),
|
||||
)
|
||||
if len(diagnostics) != 0 {
|
||||
t.Fatalf("compose normalized compound identities: %#v", diagnostics)
|
||||
}
|
||||
value, present := documentAtPath(composed.root, path)
|
||||
if !present || len(value.Sequence) != 4 {
|
||||
t.Fatalf("compound identity records = %#v, %v; want four distinct records", value, present)
|
||||
}
|
||||
|
||||
_, diagnostics = composeDocumentsWithCollectionPolicy(
|
||||
sequencePolicy{}, collectionPolicyScope{},
|
||||
[]sequenceDeclarationSpec{declaration("source-1", 2, "id")},
|
||||
parseCompositionDocument(t, "source-1", "records: [{id: 1}]\n"),
|
||||
parseCompositionDocument(t, "source-2", "records: [{id: 1.0}]\n"),
|
||||
)
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeComposeConflict || diagnostics[0].Path.String() != "/records" {
|
||||
t.Fatalf("equivalent numeric peer identities = %#v", diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
func TestComposeDocumentsReplacementDoesNotBorrowLowerYAMLIdentity(t *testing.T) {
|
||||
path := Keys("records")
|
||||
lower := collectionPolicyScope{collections: map[string]collectionPolicyEntry{
|
||||
path.String(): {
|
||||
destination: path,
|
||||
policy: collectionPolicy{identityFields: []string{"id"}, identityPresent: true},
|
||||
},
|
||||
}}
|
||||
declaration := sequenceDeclarationSpec{destination: path, mode: sequenceModeReplace, modePresent: true}
|
||||
_, diagnostics := composeDocumentsWithCollectionPolicy(
|
||||
sequencePolicy{}, lower, []sequenceDeclarationSpec{declaration},
|
||||
parseCompositionDocument(t, "source-1", "records: [{name: first}]\n"),
|
||||
parseCompositionDocument(t, "source-2", "records: [{name: second}]\n"),
|
||||
)
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeComposeConflict || diagnostics[0].Path.String() != "/records" {
|
||||
t.Fatalf("replacement peers borrowing lower identity = %#v", diagnostics)
|
||||
}
|
||||
|
||||
identityReplacement := sequenceDeclarationSpec{
|
||||
destination: path, identityFields: []string{"name"}, identityPresent: true,
|
||||
mode: sequenceModeReplace, modePresent: true,
|
||||
}
|
||||
composed, diagnostics := composeDocumentsWithCollectionPolicy(
|
||||
sequencePolicy{}, lower, []sequenceDeclarationSpec{identityReplacement},
|
||||
parseCompositionDocument(t, "source-1", "records: [{name: first}]\n"),
|
||||
parseCompositionDocument(t, "source-2", "records: [{name: second}]\n"),
|
||||
)
|
||||
if len(diagnostics) != 0 {
|
||||
t.Fatalf("replacement with a new identity declaration: %#v", diagnostics)
|
||||
}
|
||||
resolved := composed.collectionPolicies.collections[path.String()].policy
|
||||
if !reflect.DeepEqual(resolved.identityFields, []string{"name"}) || !resolved.identityPresent {
|
||||
t.Fatalf("replacement collection identity = %#v; want name", resolved)
|
||||
}
|
||||
|
||||
_, diagnostics = composeDocumentsWithCollectionPolicy(
|
||||
sequencePolicy{identityFields: map[string]string{path.String(): "id"}}, lower,
|
||||
[]sequenceDeclarationSpec{declaration},
|
||||
parseCompositionDocument(t, "source-1", "records: [{name: replacement}]\n"),
|
||||
)
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeComposeInvalid || diagnostics[0].Path.String() != "/records/0/id" {
|
||||
t.Fatalf("replacement ignored application identity constraint = %#v", diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
func TestComposeDocumentsReportsAssignedPathForMalformedRegisteredSequenceContribution(t *testing.T) {
|
||||
_, diagnostics := composeDocumentsWithPolicy(
|
||||
sequencePolicy{identityFields: map[string]string{"/records": "id"}},
|
||||
parseCompositionDocument(t, "source-1", "records: [{id: first}]\n"),
|
||||
parseCompositionDocument(t, "source-2", "records: [{name: malformed}]\n"),
|
||||
)
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeComposeInvalid || diagnostics[0].Path.String() != "/records/1" {
|
||||
t.Fatalf("diagnostics = %#v, want invalid item at /records/1", diagnostics)
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeComposeInvalid || diagnostics[0].Path.String() != "/records/1/id" {
|
||||
t.Fatalf("diagnostics = %#v, want invalid identity field at /records/1/id", diagnostics)
|
||||
}
|
||||
if diagnostics[0].Primary == nil || diagnostics[0].Primary.SourceID != "source-2" {
|
||||
t.Fatalf("malformed item location = %#v, want source-2", diagnostics[0].Primary)
|
||||
|
||||
Reference in New Issue
Block a user