104 lines
5.0 KiB
Go
104 lines
5.0 KiB
Go
package pipeline
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestResolvePipelineAppliesValidationPolicyFieldByField(t *testing.T) {
|
|
profile := baselineProfile()
|
|
profile.ValidationPolicy = validationPolicyOverride(
|
|
ProducerStructuralFailureRejectOutput,
|
|
SemanticRejectionRejectOutput,
|
|
ValidatorFailureFailRun,
|
|
)
|
|
profile.Chunk.ValidationPolicy = validationPolicyOverride("", "", ValidatorFailureWarnContinue)
|
|
lane := profile.Artifacts["events"]
|
|
lane.Extract.ValidationPolicy = validationPolicyOverride("", SemanticRejectionFailRun, "")
|
|
lane.Merge.ValidationPolicy = validationPolicyOverride("", "", ValidatorFailureWarnContinue)
|
|
profile.Artifacts["events"] = lane
|
|
|
|
resolved, err := ResolvePipeline(profile, ResolveOptions{}, newProfileCatalog(t))
|
|
if err != nil {
|
|
t.Fatalf("ResolvePipeline() error = %v", err)
|
|
}
|
|
if got, want := resolved.ChunkValidationPolicy, (ValidationPolicy{ProducerStructuralFailure: ProducerStructuralFailureRejectOutput, SemanticRejection: SemanticRejectionRejectOutput, ValidatorFailure: ValidatorFailureWarnContinue}); got != want {
|
|
t.Fatalf("chunk validation policy = %#v, want %#v", got, want)
|
|
}
|
|
resolvedLane := resolved.Steps[0].ArtifactLanes[0]
|
|
if got, want := resolvedLane.ExtractValidationPolicy, (ValidationPolicy{ProducerStructuralFailure: ProducerStructuralFailureRejectOutput, SemanticRejection: SemanticRejectionFailRun, ValidatorFailure: ValidatorFailureFailRun}); got != want {
|
|
t.Fatalf("extract validation policy = %#v, want %#v", got, want)
|
|
}
|
|
if got, want := resolvedLane.MergeValidationPolicy, (ValidationPolicy{ProducerStructuralFailure: ProducerStructuralFailureRejectOutput, SemanticRejection: SemanticRejectionRejectOutput, ValidatorFailure: ValidatorFailureWarnContinue}); got != want {
|
|
t.Fatalf("merge validation policy = %#v, want %#v", got, want)
|
|
}
|
|
if got, want := resolvedLane.NormalizeValidationPolicy, (ValidationPolicy{ProducerStructuralFailure: ProducerStructuralFailureRejectOutput, SemanticRejection: SemanticRejectionRejectOutput, ValidatorFailure: ValidatorFailureFailRun}); got != want {
|
|
t.Fatalf("normalize validation policy = %#v, want %#v", got, want)
|
|
}
|
|
|
|
*profile.ValidationPolicy.SemanticRejection = SemanticRejectionFailRun
|
|
if got := resolved.ConfiguredValidationPolicy.SemanticRejection; got == nil || *got != SemanticRejectionRejectOutput {
|
|
t.Fatalf("resolved configured policy aliases profile: %#v", resolved.ConfiguredValidationPolicy)
|
|
}
|
|
}
|
|
|
|
func TestResolvePipelineRejectsStructuralPolicyOverrideOnDeterministicProducer(t *testing.T) {
|
|
profile := baselineProfile()
|
|
profile.Chunk.ValidationPolicy = validationPolicyOverride(ProducerStructuralFailureRejectOutput, "", "")
|
|
_, err := ResolvePipeline(profile, ResolveOptions{}, newProfileCatalog(t))
|
|
if err == nil || !strings.Contains(err.Error(), "producer_structural_failure") || !strings.Contains(err.Error(), "deterministic") {
|
|
t.Fatalf("ResolvePipeline() error = %v, want deterministic structural-policy rejection", err)
|
|
}
|
|
}
|
|
|
|
func TestValidationPolicyChangesResolvedDigestAndRoundTripsBindings(t *testing.T) {
|
|
left := baselineProfile()
|
|
right := baselineProfile()
|
|
right.ValidationPolicy = validationPolicyOverride("", SemanticRejectionRejectOutput, "")
|
|
|
|
leftResolved, err := ResolvePipeline(left, ResolveOptions{}, newProfileCatalog(t))
|
|
if err != nil {
|
|
t.Fatalf("ResolvePipeline(left) error = %v", err)
|
|
}
|
|
rightResolved, err := ResolvePipeline(right, ResolveOptions{}, newProfileCatalog(t))
|
|
if err != nil {
|
|
t.Fatalf("ResolvePipeline(right) error = %v", err)
|
|
}
|
|
if leftResolved.Digest == rightResolved.Digest {
|
|
t.Fatal("validation policy change did not change resolved digest")
|
|
}
|
|
|
|
binding := ModuleBinding{Module: "producer", ValidationPolicy: validationPolicyOverride(ProducerStructuralFailureRejectOutput, SemanticRejectionRejectOutput, ValidatorFailureFailRun)}
|
|
encoded, err := json.Marshal(binding)
|
|
if err != nil {
|
|
t.Fatalf("marshal binding: %v", err)
|
|
}
|
|
var decoded ModuleBinding
|
|
if err := json.Unmarshal(encoded, &decoded); err != nil {
|
|
t.Fatalf("unmarshal binding: %v", err)
|
|
}
|
|
if decoded.ValidationPolicy == nil || *decoded.ValidationPolicy.ProducerStructuralFailure != ProducerStructuralFailureRejectOutput || *decoded.ValidationPolicy.SemanticRejection != SemanticRejectionRejectOutput || *decoded.ValidationPolicy.ValidatorFailure != ValidatorFailureFailRun {
|
|
t.Fatalf("round-tripped validation policy = %#v", decoded.ValidationPolicy)
|
|
}
|
|
cloned := cloneModuleBinding(binding)
|
|
*binding.ValidationPolicy.ValidatorFailure = ValidatorFailureWarnContinue
|
|
if got := *cloned.ValidationPolicy.ValidatorFailure; got != ValidatorFailureFailRun {
|
|
t.Fatalf("cloned validation policy aliases binding: %q", got)
|
|
}
|
|
}
|
|
|
|
func validationPolicyOverride(structural ProducerStructuralFailureAction, semantic SemanticRejectionAction, validator ValidatorFailureAction) *ValidationPolicyOverride {
|
|
policy := &ValidationPolicyOverride{}
|
|
if structural != "" {
|
|
policy.ProducerStructuralFailure = &structural
|
|
}
|
|
if semantic != "" {
|
|
policy.SemanticRejection = &semantic
|
|
}
|
|
if validator != "" {
|
|
policy.ValidatorFailure = &validator
|
|
}
|
|
return policy
|
|
}
|