package publish import ( "context" "testing" "gitea.maximumdirect.net/eric/distributor/internal/bundle" "gitea.maximumdirect.net/eric/distributor/internal/config" "gitea.maximumdirect.net/eric/distributor/internal/storage/fake" "gitea.maximumdirect.net/eric/distributor/internal/testutil" "gitea.maximumdirect.net/eric/distributor/internal/transform" ) func TestPlanOutputsRejectsCollision(t *testing.T) { sourceBackend := fake.New() sourceBundle := testutil.WriteFakeSourceBundle(t, sourceBackend, "", testutil.BundleOptions{ Files: []testutil.SourceFile{ {Path: "report.md", Data: "# Report\n"}, {Path: "report.html", Data: "

source html

\n"}, }, }) _, err := PlanOutputs(context.Background(), Request{ SourceBackend: sourceBackend, SourceBundle: sourceBundle, Publish: config.PublishPolicy{Source: true, HTML: true}, Transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{Enabled: true, Mode: config.TransformModeSidecar}}, Transformers: testResolver{transform.MarkdownToHTML: testTransformer{outputs: []transform.Output{{ Path: "report.html", SourcePath: "report.md", Transform: transform.MarkdownToHTML, Data: []byte("

Report

\n"), SHA256: bundle.FileDigest([]byte("

Report

\n")), Size: int64(len("

Report

\n")), }}}}, }) if err == nil { t.Fatal("PlanSourceOutputs() error = nil, want collision") } } func TestPlanOutputsRejectsHTMLWithoutMarkdown(t *testing.T) { sourceBackend := fake.New() sourceBundle := testutil.WriteFakeSourceBundle(t, sourceBackend, "", testutil.BundleOptions{ Files: []testutil.SourceFile{{Path: "summary.txt", Data: "Summary\n"}}, }) _, err := PlanOutputs(context.Background(), Request{ SourceBackend: sourceBackend, SourceBundle: sourceBundle, Publish: config.PublishPolicy{HTML: true}, Transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{Enabled: true, Mode: config.TransformModeSidecar}}, Transformers: testResolver{ transform.MarkdownToHTML: testTransformer{}, }, }) if err == nil { t.Fatal("PlanOutputs() error = nil, want no markdown failure") } } func TestPlanOutputsRejectsHTMLWithoutTransformerResolver(t *testing.T) { _, err := PlanOutputs(context.Background(), Request{ Publish: config.PublishPolicy{HTML: true}, Transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{Enabled: true, Mode: config.TransformModeSidecar}}, }) if err == nil { t.Fatal("PlanOutputs() error = nil, want resolver failure") } } func TestPlanOutputsRejectsMissingMarkdownTransformer(t *testing.T) { _, err := PlanOutputs(context.Background(), Request{ Publish: config.PublishPolicy{HTML: true}, Transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{Enabled: true, Mode: config.TransformModeSidecar}}, Transformers: testResolver{}, }) if err == nil { t.Fatal("PlanOutputs() error = nil, want missing transformer failure") } } func TestPlanOutputsUsesRegisteredTransformer(t *testing.T) { data := []byte("

Generated

\n") outputs, err := PlanOutputs(context.Background(), Request{ Publish: config.PublishPolicy{HTML: true}, Transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{Enabled: true, Mode: config.TransformModeSidecar}}, Transformers: testResolver{transform.MarkdownToHTML: testTransformer{outputs: []transform.Output{{ Path: "report.html", SourcePath: "report.md", Transform: transform.MarkdownToHTML, Data: data, SHA256: bundle.FileDigest(data), Size: int64(len(data)), }}}}, }) if err != nil { t.Fatalf("PlanOutputs() error = %v", err) } if got, want := len(outputs), 1; got != want { t.Fatalf("output count = %d, want %d", got, want) } if outputs[0].DestinationPath != "report.html" || string(outputs[0].Data) != string(data) { t.Fatalf("output = %#v", outputs[0]) } } func TestBuildRejectsHTMLWithoutTransform(t *testing.T) { sourceBackend := fake.New() destinationBackend := fake.New() sourceBundle := testutil.WriteFakeSourceBundle(t, sourceBackend, "", testutil.BundleOptions{ Files: []testutil.SourceFile{{Path: "report.md", Data: "# Report\n"}}, }) _, err := Build(context.Background(), Request{ PipelineID: "reports", DestinationID: "archive", SourceBackend: sourceBackend, DestinationBackend: destinationBackend, DestinationBundlePath: "", SourceBundle: sourceBundle, Publish: config.PublishPolicy{HTML: true}, Transfer: config.TransferPolicy{ OnDestinationSame: config.TransferActionSkip, OnDestinationOlder: config.TransferActionReplace, OnDestinationNewer: config.TransferActionSkip, OnConflict: config.TransferActionFail, }, }) if err == nil { t.Fatal("Build() error = nil, want missing transform error") } } func TestValidateRequestChecksPublishTransformPolicy(t *testing.T) { tests := []struct { name string publish config.PublishPolicy transform config.Transform wantErr bool }{ { name: "source only allowed", publish: config.PublishPolicy{Source: true}, }, { name: "html only sidecar allowed", publish: config.PublishPolicy{HTML: true}, transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{ Enabled: true, Mode: config.TransformModeSidecar, }}, }, { name: "source and html sidecar allowed", publish: config.PublishPolicy{Source: true, HTML: true}, transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{ Enabled: true, Mode: config.TransformModeSidecar, }}, }, { name: "no outputs rejected", publish: config.PublishPolicy{}, wantErr: true, }, { name: "html without transform rejected", publish: config.PublishPolicy{HTML: true}, wantErr: true, }, { name: "html with disabled transform rejected", publish: config.PublishPolicy{HTML: true}, transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{ Enabled: false, Mode: config.TransformModeSidecar, }}, wantErr: true, }, { name: "html with wrong mode rejected", publish: config.PublishPolicy{HTML: true}, transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{ Enabled: true, Mode: "inline", }}, wantErr: true, }, { name: "enabled markdown wrong mode rejected", publish: config.PublishPolicy{Source: true}, transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{ Enabled: true, Mode: "inline", }}, wantErr: true, }, { name: "disabled markdown empty mode allowed", publish: config.PublishPolicy{Source: true}, transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{ Enabled: false, }}, }, { name: "disabled markdown sidecar mode allowed", publish: config.PublishPolicy{Source: true}, transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{ Enabled: false, Mode: config.TransformModeSidecar, }}, }, { name: "disabled markdown wrong mode rejected", publish: config.PublishPolicy{Source: true}, transform: config.Transform{MarkdownToHTML: &config.MarkdownToHTML{ Enabled: false, Mode: "inline", }}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := validateRequest(Request{ PipelineID: "reports", DestinationID: "archive", SourceBackend: fake.New(), DestinationBackend: fake.New(), Publish: tt.publish, Transform: tt.transform, }) if tt.wantErr && err == nil { t.Fatal("validateRequest() error = nil, want error") } if !tt.wantErr && err != nil { t.Fatalf("validateRequest() error = %v", err) } }) } } type testResolver map[string]transform.Transformer func (r testResolver) Get(name string) (transform.Transformer, bool) { transformer, ok := r[name] return transformer, ok } type testTransformer struct { outputs []transform.Output err error } func (t testTransformer) Generate(context.Context, transform.Request) ([]transform.Output, error) { return t.outputs, t.err }