216 lines
7.8 KiB
Go
216 lines
7.8 KiB
Go
package publish
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.maximumdirect.net/eric/distributor/internal/bundle"
|
|
"gitea.maximumdirect.net/eric/distributor/internal/config"
|
|
"gitea.maximumdirect.net/eric/distributor/internal/storage"
|
|
"gitea.maximumdirect.net/eric/distributor/internal/storage/fake"
|
|
"gitea.maximumdirect.net/eric/distributor/internal/testutil"
|
|
)
|
|
|
|
func TestBuildPlansSingleOwnerTakeoverByPolicy(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
takeover config.TakeoverPolicy
|
|
mutateState func(*bundle.Manifest, *testutil.DestinationStateOptions)
|
|
wantAction Action
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "default same pipeline different source",
|
|
takeover: config.TakeoverPolicy{},
|
|
mutateState: func(manifest *bundle.Manifest, opts *testutil.DestinationStateOptions) {
|
|
manifest.ID = "other.source"
|
|
},
|
|
wantAction: ActionReplaceTakeover,
|
|
},
|
|
{
|
|
name: "same pipeline different newer source",
|
|
takeover: config.TakeoverPolicy{Mode: config.TakeoverModeSamePipeline},
|
|
mutateState: func(manifest *bundle.Manifest, opts *testutil.DestinationStateOptions) {
|
|
manifest.ID = "other.source"
|
|
manifest.Created = manifest.Created.AddDate(0, 0, 1)
|
|
},
|
|
wantAction: ActionReplaceTakeover,
|
|
},
|
|
{
|
|
name: "default same pipeline different destination",
|
|
takeover: config.TakeoverPolicy{},
|
|
mutateState: func(manifest *bundle.Manifest, opts *testutil.DestinationStateOptions) {
|
|
opts.DestinationID = "web"
|
|
},
|
|
wantAction: ActionReplaceTakeover,
|
|
},
|
|
{
|
|
name: "same pipeline refuses different pipeline",
|
|
takeover: config.TakeoverPolicy{Mode: config.TakeoverModeSamePipeline},
|
|
mutateState: func(manifest *bundle.Manifest, opts *testutil.DestinationStateOptions) {
|
|
opts.PipelineID = "other"
|
|
},
|
|
wantErr: "fail_conflict",
|
|
},
|
|
{
|
|
name: "same source allows different pipeline",
|
|
takeover: config.TakeoverPolicy{Mode: config.TakeoverModeSameSource},
|
|
mutateState: func(manifest *bundle.Manifest, opts *testutil.DestinationStateOptions) {
|
|
opts.PipelineID = "other"
|
|
},
|
|
wantAction: ActionReplaceTakeover,
|
|
},
|
|
{
|
|
name: "same source refuses different source",
|
|
takeover: config.TakeoverPolicy{Mode: config.TakeoverModeSameSource},
|
|
mutateState: func(manifest *bundle.Manifest, opts *testutil.DestinationStateOptions) {
|
|
manifest.ID = "other.source"
|
|
},
|
|
wantErr: "fail_conflict",
|
|
},
|
|
{
|
|
name: "any managed allows different pipeline",
|
|
takeover: config.TakeoverPolicy{Mode: config.TakeoverModeAnyManaged},
|
|
mutateState: func(manifest *bundle.Manifest, opts *testutil.DestinationStateOptions) {
|
|
manifest.ID = "other.source"
|
|
opts.PipelineID = "other"
|
|
},
|
|
wantAction: ActionReplaceTakeover,
|
|
},
|
|
{
|
|
name: "never refuses different source",
|
|
takeover: config.TakeoverPolicy{Mode: config.TakeoverModeNever},
|
|
mutateState: func(manifest *bundle.Manifest, opts *testutil.DestinationStateOptions) {
|
|
manifest.ID = "other.source"
|
|
},
|
|
wantErr: "fail_conflict",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
sourceBackend := fake.New()
|
|
sourceBundle := testutil.WriteFakeSourceBundle(t, sourceBackend, "bundle", testutil.BundleOptions{})
|
|
destinationBackend := fake.New()
|
|
destinationManifest := sourceBundle.Manifest
|
|
destinationManifest.Files = append([]bundle.ManifestFile(nil), sourceBundle.Manifest.Files...)
|
|
opts := testutil.DestinationStateOptions{}
|
|
tt.mutateState(&destinationManifest, &opts)
|
|
testutil.WriteFakeDestinationState(t, destinationBackend, "bundle", destinationManifest, opts)
|
|
|
|
req := takeoverRequest(sourceBackend, destinationBackend, sourceBundle, tt.takeover, config.ReconciliationModeReplace)
|
|
plan, err := Build(context.Background(), req)
|
|
if tt.wantErr != "" {
|
|
if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
|
|
t.Fatalf("Build() error = %v, want %q", err, tt.wantErr)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("Build() error = %v", err)
|
|
}
|
|
if plan.Action != tt.wantAction {
|
|
t.Fatalf("plan action = %s, want %s", plan.Action, tt.wantAction)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildDoesNotTakeOverInvalidOrUnmanagedDestination(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
prepare func(t *testing.T, backend *fake.Backend)
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "invalid state",
|
|
prepare: func(t *testing.T, backend *fake.Backend) {
|
|
t.Helper()
|
|
statePath, err := storage.StatePath("bundle")
|
|
if err != nil {
|
|
t.Fatalf("state path: %v", err)
|
|
}
|
|
testutil.WriteFakeFile(t, backend, statePath, "{invalid")
|
|
},
|
|
wantErr: "fail_conflict",
|
|
},
|
|
{
|
|
name: "unmanaged content",
|
|
prepare: func(t *testing.T, backend *fake.Backend) {
|
|
t.Helper()
|
|
testutil.WriteFakeFile(t, backend, "bundle/old.txt", "old")
|
|
},
|
|
wantErr: "fail_unmanaged",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
sourceBackend := fake.New()
|
|
sourceBundle := testutil.WriteFakeSourceBundle(t, sourceBackend, "bundle", testutil.BundleOptions{})
|
|
destinationBackend := fake.New()
|
|
tt.prepare(t, destinationBackend)
|
|
|
|
req := takeoverRequest(sourceBackend, destinationBackend, sourceBundle, config.TakeoverPolicy{Mode: config.TakeoverModeAnyManaged}, config.ReconciliationModeReplace)
|
|
_, err := Build(context.Background(), req)
|
|
if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
|
|
t.Fatalf("Build() error = %v, want %q", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExecuteTakeoverMergeDoesNotRetainOldSourceOutputs(t *testing.T) {
|
|
sourceBackend := fake.New()
|
|
sourceBundle := testutil.WriteFakeSourceBundle(t, sourceBackend, "bundle", testutil.BundleOptions{
|
|
Files: []testutil.SourceFile{{Path: "report.md", Data: "# Report\nNew.\n"}},
|
|
})
|
|
destinationBackend := fake.New()
|
|
oldManifest := sourceBundle.Manifest
|
|
oldManifest.ID = "old.source"
|
|
oldManifest.Files = []bundle.ManifestFile{
|
|
{Path: "report.md", SHA256: bundle.FileDigest([]byte("old\n")), Size: int64(len("old\n"))},
|
|
{Path: "summary.txt", SHA256: bundle.FileDigest([]byte("old summary\n")), Size: int64(len("old summary\n"))},
|
|
}
|
|
oldManifest.Digest = bundle.BundleDigest(oldManifest.Files)
|
|
testutil.WriteFakeDestinationState(t, destinationBackend, "bundle", oldManifest, testutil.DestinationStateOptions{})
|
|
|
|
req := takeoverRequest(sourceBackend, destinationBackend, sourceBundle, config.TakeoverPolicy{Mode: config.TakeoverModeSamePipeline}, config.ReconciliationModeMerge)
|
|
plan, err := Build(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("Build() error = %v", err)
|
|
}
|
|
if plan.Action != ActionReplaceTakeover {
|
|
t.Fatalf("plan action = %s, want %s", plan.Action, ActionReplaceTakeover)
|
|
}
|
|
if err := Execute(context.Background(), req, plan); err != nil {
|
|
t.Fatalf("Execute() error = %v", err)
|
|
}
|
|
|
|
testutil.AssertFakeFile(t, destinationBackend, "bundle/report.md", "# Report\nNew.\n")
|
|
testutil.AssertFakeMissing(t, destinationBackend, "bundle/summary.txt")
|
|
destinationState := readFakeState(t, destinationBackend, "bundle")
|
|
if got, want := len(destinationState.Outputs), 1; got != want {
|
|
t.Fatalf("state output count = %d, want %d", got, want)
|
|
}
|
|
if got, want := destinationState.Source.Manifest.ID, sourceBundle.Manifest.ID; got != want {
|
|
t.Fatalf("state source id = %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func takeoverRequest(sourceBackend, destinationBackend *fake.Backend, sourceBundle bundle.Bundle, takeover config.TakeoverPolicy, reconciliationMode string) Request {
|
|
return Request{
|
|
PipelineID: "reports",
|
|
DestinationID: "archive",
|
|
SourceBundle: sourceBundle,
|
|
SourceBackend: sourceBackend,
|
|
DestinationBackend: destinationBackend,
|
|
DestinationBundlePath: sourceBundle.RootRelativePath,
|
|
Publish: config.PublishPolicy{Source: true},
|
|
Reconciliation: config.ReconciliationPolicy{Mode: reconciliationMode},
|
|
Takeover: takeover,
|
|
Transfer: defaultTransfer(),
|
|
DistributorVersion: "test",
|
|
}
|
|
}
|