190 lines
8.2 KiB
Go
190 lines
8.2 KiB
Go
package engine
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestResolveCollectionPolicyReconcilesDeclarationsBeforeComposition(t *testing.T) {
|
|
declarations := extractSequenceDeclarationsYAML(t, `configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
key: [namespace, id]
|
|
mode: append
|
|
- destination: [prompts]
|
|
key: [id, namespace, id]
|
|
- destination: [prompts]
|
|
mode: append
|
|
`, rootDirectiveContextSource).sequences
|
|
|
|
resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), declarations, nil, nil)
|
|
if len(diagnostics) != 0 {
|
|
t.Fatalf("policy diagnostics = %#v", diagnostics)
|
|
}
|
|
if !resolved.modeDeclarationPresent {
|
|
t.Fatalf("mode declaration was lost: %#v", resolved)
|
|
}
|
|
wantFields := []string{"id", "namespace"}
|
|
if !reflect.DeepEqual(resolved.policy.identityFields, wantFields) || !reflect.DeepEqual(resolved.effectiveIdentityFields, wantFields) {
|
|
t.Fatalf("effective identity = %#v / %#v, want %#v", resolved.policy.identityFields, resolved.effectiveIdentityFields, wantFields)
|
|
}
|
|
if !resolved.policy.identityPresent || !resolved.policy.explicitModePresent || resolved.policy.explicitMode != sequenceModeAppend || resolved.operation != sequenceModeAppend {
|
|
t.Fatalf("resolved explicit policy = %#v, operation %d", resolved.policy, resolved.operation)
|
|
}
|
|
}
|
|
|
|
func TestResolveCollectionPolicyRejectsConflictingPeersAtBothSites(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
body string
|
|
}{
|
|
{
|
|
name: "identity fields",
|
|
body: `configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
key: id
|
|
- destination: [prompts]
|
|
key: name
|
|
`,
|
|
},
|
|
{
|
|
name: "explicit modes",
|
|
body: `configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
mode: append
|
|
- destination: [prompts]
|
|
mode: replace
|
|
`,
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
declarations := extractSequenceDeclarationsYAML(t, test.body, rootDirectiveContextSource).sequences
|
|
resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), declarations, nil, nil)
|
|
if !reflect.DeepEqual(resolved, collectionPolicyResolution{}) || len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceConflict {
|
|
t.Fatalf("resolution/diagnostics = %#v / %#v", resolved, diagnostics)
|
|
}
|
|
diagnostic := diagnostics[0]
|
|
if diagnostic.Path.String() != "/prompts" || diagnostic.Primary == nil || len(diagnostic.Related) != 1 {
|
|
t.Fatalf("conflict does not identify both declaration sites: %#v", diagnostic)
|
|
}
|
|
if diagnostic.Primary.SourceID != "sequence-declarations" || diagnostic.Related[0].SourceID != "sequence-declarations" || diagnostic.Primary.Line == diagnostic.Related[0].Line {
|
|
t.Fatalf("conflict locations = %#v and %#v", diagnostic.Primary, diagnostic.Related)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResolveCollectionPolicySelectsCurrentThenRetainedExplicitMode(t *testing.T) {
|
|
lower := &collectionPolicy{
|
|
identityFields: []string{"id"},
|
|
identityPresent: true,
|
|
explicitMode: sequenceModeAppend,
|
|
explicitModePresent: true,
|
|
modeLocation: &Location{SourceID: "lower", Line: 2},
|
|
}
|
|
current := extractSequenceDeclarationsYAML(t, `configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
mode: upsert
|
|
`, rootDirectiveContextSource).sequences
|
|
resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), current, nil, lower)
|
|
if len(diagnostics) != 0 || resolved.operation != sequenceModeUpsert || resolved.policy.explicitMode != sequenceModeUpsert || !resolved.policy.explicitModePresent {
|
|
t.Fatalf("current mode did not override retained mode: %#v, %#v", resolved, diagnostics)
|
|
}
|
|
|
|
resolved, diagnostics = resolveCollectionPolicy(Keys("prompts"), nil, nil, lower)
|
|
if len(diagnostics) != 0 || resolved.operation != sequenceModeAppend || resolved.policy.explicitMode != sequenceModeAppend || !resolved.policy.explicitModePresent {
|
|
t.Fatalf("omitted current mode did not retain lower explicit mode: %#v, %#v", resolved, diagnostics)
|
|
}
|
|
if !reflect.DeepEqual(resolved.effectiveIdentityFields, []string{"id"}) {
|
|
t.Fatalf("retained identity = %#v", resolved.effectiveIdentityFields)
|
|
}
|
|
}
|
|
|
|
func TestResolveCollectionPolicyInfersWithoutPersistingMode(t *testing.T) {
|
|
keyOnly := extractSequenceDeclarationsYAML(t, `configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
key: id
|
|
`, rootDirectiveContextSource).sequences
|
|
resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), keyOnly, nil, nil)
|
|
if len(diagnostics) != 0 || resolved.operation != sequenceModeUpsert || resolved.policy.explicitModePresent {
|
|
t.Fatalf("identity-based mode inference = %#v, %#v", resolved, diagnostics)
|
|
}
|
|
|
|
resolved, diagnostics = resolveCollectionPolicy(Keys("prompts"), nil, []string{"id"}, nil)
|
|
if len(diagnostics) != 0 || resolved.operation != sequenceModeUpsert || resolved.policy.identityPresent || !resolved.applicationIdentityPresent {
|
|
t.Fatalf("application identity was not kept distinct from YAML policy: %#v, %#v", resolved, diagnostics)
|
|
}
|
|
|
|
noIdentity := extractSequenceDeclarationsYAML(t, `configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
`, rootDirectiveContextSource).sequences
|
|
resolved, diagnostics = resolveCollectionPolicy(Keys("prompts"), noIdentity, nil, nil)
|
|
if len(diagnostics) != 0 || resolved.operation != sequenceModeReplace || resolved.policy.explicitModePresent {
|
|
t.Fatalf("unkeyed mode inference = %#v, %#v", resolved, diagnostics)
|
|
}
|
|
|
|
explicitDefault := extractSequenceDeclarationsYAML(t, `configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
mode: replace
|
|
`, rootDirectiveContextSource).sequences
|
|
resolved, diagnostics = resolveCollectionPolicy(Keys("prompts"), explicitDefault, nil, nil)
|
|
if len(diagnostics) != 0 || resolved.operation != sequenceModeReplace || !resolved.policy.explicitModePresent {
|
|
t.Fatalf("explicit default mode lost its presence: %#v, %#v", resolved, diagnostics)
|
|
}
|
|
}
|
|
|
|
func TestResolveCollectionPolicyChecksKeyOnlyAgainstApplicationConstraint(t *testing.T) {
|
|
declarations := extractSequenceDeclarationsYAML(t, `configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
key: [namespace, id]
|
|
`, rootDirectiveContextSource).sequences
|
|
resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), declarations, []string{"id", "namespace", "id"}, nil)
|
|
if len(diagnostics) != 0 || resolved.operation != sequenceModeUpsert || !reflect.DeepEqual(resolved.effectiveIdentityFields, []string{"id", "namespace"}) {
|
|
t.Fatalf("equivalent key-only declaration was rejected: %#v, %#v", resolved, diagnostics)
|
|
}
|
|
|
|
resolved, diagnostics = resolveCollectionPolicy(Keys("prompts"), declarations, []string{"slug"}, nil)
|
|
if len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceConflict {
|
|
t.Fatalf("conflicting key-only declaration = %#v, %#v", resolved, diagnostics)
|
|
}
|
|
if diagnostics[0].Primary == nil || diagnostics[0].Path.String() != "/prompts" || len(diagnostics[0].Related) != 0 {
|
|
t.Fatalf("application conflict diagnostic = %#v", diagnostics[0])
|
|
}
|
|
}
|
|
|
|
func TestResolveCollectionPolicyChecksRetainedIdentityAgainstApplicationConstraint(t *testing.T) {
|
|
lower := &collectionPolicy{identityFields: []string{"id"}, identityPresent: true}
|
|
resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), nil, []string{"name"}, lower)
|
|
if len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceConflict || diagnostics[0].Path.String() != "/prompts" {
|
|
t.Fatalf("retained/application conflict = %#v, %#v", resolved, diagnostics)
|
|
}
|
|
}
|
|
|
|
func TestResolveCollectionPolicyRequiresCurrentIdentityToAgreeWithRetainedIdentity(t *testing.T) {
|
|
declarations := extractSequenceDeclarationsYAML(t, `configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
key: name
|
|
`, rootDirectiveContextSource).sequences
|
|
lower := &collectionPolicy{
|
|
identityFields: []string{"id"},
|
|
identityPresent: true,
|
|
identityLocation: &Location{SourceID: "lower", Line: 4},
|
|
}
|
|
resolved, diagnostics := resolveCollectionPolicy(Keys("prompts"), declarations, nil, lower)
|
|
if len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceConflict || diagnostics[0].Path.String() != "/prompts" {
|
|
t.Fatalf("current/retained identity conflict = %#v, %#v", resolved, diagnostics)
|
|
}
|
|
if diagnostics[0].Primary == nil || len(diagnostics[0].Related) != 1 || diagnostics[0].Related[0].SourceID != "lower" {
|
|
t.Fatalf("current/retained conflict locations = %#v", diagnostics[0])
|
|
}
|
|
}
|