Add destination workflow config

This commit is contained in:
2026-06-19 15:18:14 +00:00
parent d23c624179
commit a95662226f
6 changed files with 101 additions and 652 deletions

View File

@@ -30,17 +30,8 @@ pipelines:
if got, want := cfg.Pipelines[0].Validation.OnDigestMismatch, ValidationActionFail; got != want {
t.Fatalf("validation default = %q, want %q", got, want)
}
if got, want := destination.Transfer.OnDestinationOlder, TransferActionReplace; got != want {
t.Fatalf("transfer default = %q, want %q", got, want)
}
if got, want := destination.Reconciliation.Mode, ReconciliationModeReplace; got != want {
t.Fatalf("reconciliation mode default = %q, want %q", got, want)
}
if got, want := destination.State.Mode, StateModeSingleOwner; got != want {
t.Fatalf("state mode default = %q, want %q", got, want)
}
if got, want := destination.Takeover.Mode, TakeoverModeSamePipeline; got != want {
t.Fatalf("takeover mode default = %q, want %q", got, want)
if got, want := destination.Workflow, WorkflowAdditive; got != want {
t.Fatalf("workflow default = %q, want %q", got, want)
}
if destination.Retention.Prune.Enabled {
t.Fatal("retention.prune.enabled default = true, want false")
@@ -176,7 +167,7 @@ pipelines:
}
}
func TestLoadFileAcceptsExplicitReconciliationModes(t *testing.T) {
func TestLoadFileAcceptsExplicitWorkflows(t *testing.T) {
cfg := loadConfig(t, `
pipelines:
- id: reports
@@ -187,94 +178,19 @@ pipelines:
- id: archive
backend: local
path: /archive
reconciliation:
mode: replace
workflow: additive
- id: web
backend: local
path: /web
reconciliation:
mode: merge
workflow: replacement
`)
destinations := cfg.Pipelines[0].Destinations
if got, want := destinations[0].Reconciliation.Mode, ReconciliationModeReplace; got != want {
t.Fatalf("archive reconciliation mode = %q, want %q", got, want)
if got, want := destinations[0].Workflow, WorkflowAdditive; got != want {
t.Fatalf("archive workflow = %q, want %q", got, want)
}
if got, want := destinations[1].Reconciliation.Mode, ReconciliationModeMerge; got != want {
t.Fatalf("web reconciliation mode = %q, want %q", got, want)
}
}
func TestLoadFileAcceptsExplicitStateModes(t *testing.T) {
cfg := loadConfig(t, `
pipelines:
- id: reports
source:
backend: local
path: /source
destinations:
- id: archive
backend: local
path: /archive
state:
mode: single_owner
- id: web
backend: local
path: /web
state:
mode: shared_root
`)
destinations := cfg.Pipelines[0].Destinations
if got, want := destinations[0].State.Mode, StateModeSingleOwner; got != want {
t.Fatalf("archive state mode = %q, want %q", got, want)
}
if got, want := destinations[1].State.Mode, StateModeSharedRoot; got != want {
t.Fatalf("web state mode = %q, want %q", got, want)
}
}
func TestLoadFileAcceptsExplicitTakeoverModes(t *testing.T) {
cfg := loadConfig(t, `
pipelines:
- id: reports
source:
backend: local
path: /source
destinations:
- id: same-pipeline
backend: local
path: /same-pipeline
takeover:
mode: same_pipeline
- id: same-source
backend: local
path: /same-source
takeover:
mode: same_source
- id: any-managed
backend: local
path: /any-managed
takeover:
mode: any_managed
- id: never
backend: local
path: /never
takeover:
mode: never
`)
destinations := cfg.Pipelines[0].Destinations
wants := []string{
TakeoverModeSamePipeline,
TakeoverModeSameSource,
TakeoverModeAnyManaged,
TakeoverModeNever,
}
for index, want := range wants {
if got := destinations[index].Takeover.Mode; got != want {
t.Fatalf("destinations[%d].takeover.mode = %q, want %q", index, got, want)
}
if got, want := destinations[1].Workflow, WorkflowReplacement; got != want {
t.Fatalf("web workflow = %q, want %q", got, want)
}
}
@@ -899,8 +815,63 @@ pipelines:
`, "backend ftp is unsupported")
}
func TestLoadFileRejectsInvalidTransferAction(t *testing.T) {
func TestLoadFileRejectsInvalidWorkflow(t *testing.T) {
assertLoadError(t, `
pipelines:
- id: reports
source:
backend: local
path: /source
destinations:
- id: archive
backend: local
path: /archive
workflow: append
`, "workflow must be additive or replacement")
}
func TestLoadFileRejectsLegacyDestinationPolicyFields(t *testing.T) {
tests := map[string]string{
"state": `
pipelines:
- id: reports
source:
backend: local
path: /source
destinations:
- id: archive
backend: local
path: /archive
state:
mode: single_owner
`,
"reconciliation": `
pipelines:
- id: reports
source:
backend: local
path: /source
destinations:
- id: archive
backend: local
path: /archive
reconciliation:
mode: replace
`,
"takeover": `
pipelines:
- id: reports
source:
backend: local
path: /source
destinations:
- id: archive
backend: local
path: /archive
takeover:
mode: same_pipeline
`,
"transfer": `
pipelines:
- id: reports
source:
@@ -911,40 +882,14 @@ pipelines:
backend: local
path: /archive
transfer:
on_destination_older: overwrite
`, "on_destination_older must be replace or fail")
}
func TestLoadFileRejectsInvalidTakeoverMode(t *testing.T) {
assertLoadError(t, `
pipelines:
- id: reports
source:
backend: local
path: /source
destinations:
- id: archive
backend: local
path: /archive
takeover:
mode: unmanaged
`, "takeover.mode must be same_pipeline, same_source, any_managed, or never")
}
func TestLoadFileRejectsUnknownTakeoverFields(t *testing.T) {
assertLoadError(t, `
pipelines:
- id: reports
source:
backend: local
path: /source
destinations:
- id: archive
backend: local
path: /archive
takeover:
surprise: true
`, "field surprise not found")
on_destination_older: replace
`,
}
for name, body := range tests {
t.Run(name, func(t *testing.T) {
assertLoadError(t, body, "field "+name+" not found")
})
}
}
func TestLoadFileRejectsInvalidValidationAction(t *testing.T) {
@@ -1020,8 +965,6 @@ func TestExampleConfigsLoad(t *testing.T) {
"../../examples/local-index.yml",
"../../examples/fan-out.yml",
"../../examples/archive-and-latest.yml",
"../../examples/merge-reconciliation.yml",
"../../examples/shared-root.yml",
"../../examples/http-upload-local.yml",
"../../examples/ssh-destination.yml",
"../../examples/s3-destination.yml",