Files
narratio/internal/config/artifact_dependencies_test.go

113 lines
3.9 KiB
Go

package config
import (
"reflect"
"strings"
"testing"
)
func TestFinalizeArtifactDependenciesUnionsNormalizesAndIsIdempotent(t *testing.T) {
cfg := dependencyTestPipeline([]string{" beta ", "alpha", "beta"})
artifact := cfg.Scriptorium.Artifacts["result"]
artifact.Inputs["gamma"] = ScriptoriumInputConfig{Source: "narratio.artifact.gamma"}
artifact.Inputs["alpha"] = ScriptoriumInputConfig{Source: "narratio.artifact.alpha"}
cfg.Scriptorium.Artifacts["result"] = artifact
cfg.Scriptorium.Artifacts["gamma"] = ScriptoriumArtifactConfig{}
finalizeArtifactDependencies(cfg)
want := []string{"alpha", "beta", "gamma"}
got := cfg.Scriptorium.Artifacts["result"]
if !reflect.DeepEqual(got.DependsOn, want) {
t.Fatalf("dependencies = %#v, want %#v", got.DependsOn, want)
}
if len(got.dependencyOrigins["alpha"]) != 2 {
t.Fatalf("alpha origins = %#v, want explicit and input origins", got.dependencyOrigins["alpha"])
}
firstOrigins := cloneDependencyOrigins(got.dependencyOrigins)
finalizeArtifactDependencies(cfg)
got = cfg.Scriptorium.Artifacts["result"]
if !reflect.DeepEqual(got.DependsOn, want) {
t.Fatalf("dependencies after second finalization = %#v, want %#v", got.DependsOn, want)
}
if !reflect.DeepEqual(got.dependencyOrigins, firstOrigins) {
t.Fatalf("origins changed after second finalization: %#v != %#v", got.dependencyOrigins, firstOrigins)
}
}
func TestInferredArtifactDependencyDiagnosticsPointToInputs(t *testing.T) {
for _, test := range []struct {
name string
artifacts map[string]ScriptoriumArtifactConfig
want []string
}{
{
name: "missing",
artifacts: map[string]ScriptoriumArtifactConfig{
"result": {Inputs: map[string]ScriptoriumInputConfig{"missing": {Source: "narratio.artifact.unknown"}}},
},
want: []string{"pipeline.scriptorium.artifacts.result.inputs.missing.source", "not configured"},
},
{
name: "self",
artifacts: map[string]ScriptoriumArtifactConfig{
"result": {Inputs: map[string]ScriptoriumInputConfig{"self": {Source: "narratio.artifact.result"}}},
},
want: []string{"pipeline.scriptorium.artifacts.result.inputs.self.source", "itself"},
},
{
name: "cycle",
artifacts: map[string]ScriptoriumArtifactConfig{
"alpha": {Inputs: map[string]ScriptoriumInputConfig{"beta": {Source: "narratio.artifact.beta"}}},
"beta": {Inputs: map[string]ScriptoriumInputConfig{"alpha": {Source: "narratio.artifact.alpha"}}},
},
want: []string{".inputs.", "dependencies must not contain cycles"},
},
} {
t.Run(test.name, func(t *testing.T) {
cfg := &PipelineConfig{Scriptorium: &ScriptoriumConfig{Artifacts: test.artifacts}}
finalizeArtifactDependencies(cfg)
err := ValidateScriptoriumArtifactDependencies(cfg.Scriptorium.Artifacts)
if err == nil {
t.Fatal("expected dependency validation error")
}
for _, fragment := range test.want {
if !strings.Contains(err.Error(), fragment) {
t.Fatalf("error = %q, want fragment %q", err, fragment)
}
}
})
}
}
func TestExplicitAndInferredDependencyGraphsHaveEqualDigests(t *testing.T) {
explicit := dependencyTestPipeline([]string{"alpha"})
inferred := dependencyTestPipeline(nil)
for _, cfg := range []*PipelineConfig{explicit, inferred} {
finalizeArtifactDependencies(cfg)
cfg.resolution = &pipelineResolutionMetadata{}
if err := recomputePipelineEffectiveDigest(cfg); err != nil {
t.Fatal(err)
}
}
if got, want := EffectivePipelineDigest(explicit), EffectivePipelineDigest(inferred); got != want {
t.Fatalf("equivalent dependency graph digests differ: %s != %s", got, want)
}
}
func dependencyTestPipeline(dependsOn []string) *PipelineConfig {
return &PipelineConfig{Scriptorium: &ScriptoriumConfig{
Binary: "scriptorium",
Artifacts: map[string]ScriptoriumArtifactConfig{
"alpha": {},
"beta": {},
"result": {
DependsOn: dependsOn,
Inputs: map[string]ScriptoriumInputConfig{
"alpha": {Source: "narratio.artifact.alpha"},
},
},
},
}}
}