feat(pdfengines): one flag per PDF engine method for a more granular selection of PDF engines

This commit is contained in:
Julien Neuhart
2024-10-13 11:29:38 +02:00
parent 8ff9d3bcf1
commit 249745f256
5 changed files with 370 additions and 158 deletions
+8
View File
@@ -72,6 +72,10 @@ LOG_LEVEL=info
LOG_FORMAT=auto
LOG_FIELDS_PREFIX=
PDFENGINES_ENGINES=
PDFENGINES_MERGE_ENGINES=qpdf,pdfcpu,pdftk
PDFENGINES_CONVERT_ENGINES=libreoffice-pdfengine
PDFENGINES_READ_METADATA_ENGINES=exiftool
PDFENGINES_WRITE_METADATA_ENGINES=exiftool
PDFENGINES_DISABLE_ROUTES=false
PROMETHEUS_NAMESPACE=gotenberg
PROMETHEUS_COLLECT_INTERVAL=1s
@@ -136,6 +140,10 @@ run: ## Start a Gotenberg container
--log-format=$(LOG_FORMAT) \
--log-fields-prefix=$(LOG_FIELDS_PREFIX) \
--pdfengines-engines=$(PDFENGINES_ENGINES) \
--pdfengines-merge-engines=$(PDFENGINES_MERGE_ENGINES) \
--pdfengines-convert-engines=$(PDFENGINES_CONVERT_ENGINES) \
--pdfengines-read-metadata-engines=$(PDFENGINES_READ_METADATA_ENGINES) \
--pdfengines-write-metadata-engines=$(PDFENGINES_WRITE_METADATA_ENGINES) \
--pdfengines-disable-routes=$(PDFENGINES_DISABLE_ROUTES) \
--prometheus-namespace=$(PROMETHEUS_NAMESPACE) \
--prometheus-collect-interval=$(PROMETHEUS_COLLECT_INTERVAL) \
+20 -9
View File
@@ -12,12 +12,23 @@ import (
)
type multiPdfEngines struct {
engines []gotenberg.PdfEngine
mergeEngines []gotenberg.PdfEngine
convertEngines []gotenberg.PdfEngine
readMedataEngines []gotenberg.PdfEngine
writeMedataEngines []gotenberg.PdfEngine
}
func newMultiPdfEngines(engines ...gotenberg.PdfEngine) *multiPdfEngines {
func newMultiPdfEngines(
mergeEngines,
convertEngines,
readMetadataEngines,
writeMedataEngines []gotenberg.PdfEngine,
) *multiPdfEngines {
return &multiPdfEngines{
engines: engines,
mergeEngines: mergeEngines,
convertEngines: convertEngines,
readMedataEngines: readMetadataEngines,
writeMedataEngines: writeMedataEngines,
}
}
@@ -27,7 +38,7 @@ func (multi *multiPdfEngines) Merge(ctx context.Context, logger *zap.Logger, inp
var err error
errChan := make(chan error, 1)
for _, engine := range multi.engines {
for _, engine := range multi.mergeEngines {
go func(engine gotenberg.PdfEngine) {
errChan <- engine.Merge(ctx, logger, inputPaths, outputPath)
}(engine)
@@ -52,7 +63,7 @@ func (multi *multiPdfEngines) Convert(ctx context.Context, logger *zap.Logger, f
var err error
errChan := make(chan error, 1)
for _, engine := range multi.engines {
for _, engine := range multi.convertEngines {
go func(engine gotenberg.PdfEngine) {
errChan <- engine.Convert(ctx, logger, formats, inputPath, outputPath)
}(engine)
@@ -80,16 +91,16 @@ func (multi *multiPdfEngines) ReadMetadata(ctx context.Context, logger *zap.Logg
var err error
var mu sync.Mutex // to safely append errors.
resultChan := make(chan readMetadataResult, len(multi.engines))
resultChan := make(chan readMetadataResult, len(multi.readMedataEngines))
for _, engine := range multi.engines {
for _, engine := range multi.readMedataEngines {
go func(engine gotenberg.PdfEngine) {
metadata, err := engine.ReadMetadata(ctx, logger, inputPath)
resultChan <- readMetadataResult{metadata: metadata, err: err}
}(engine)
}
for range multi.engines {
for range multi.readMedataEngines {
select {
case result := <-resultChan:
if result.err != nil {
@@ -111,7 +122,7 @@ func (multi *multiPdfEngines) WriteMetadata(ctx context.Context, logger *zap.Log
var err error
errChan := make(chan error, 1)
for _, engine := range multi.engines {
for _, engine := range multi.writeMedataEngines {
go func(engine gotenberg.PdfEngine) {
errChan <- engine.WriteMetadata(ctx, logger, metadata, inputPath)
}(engine)
+166 -86
View File
@@ -20,11 +20,16 @@ func TestMultiPdfEngines_Merge(t *testing.T) {
{
scenario: "nominal behavior",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return nil
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return nil
},
},
},
nil,
nil,
nil,
),
ctx: context.Background(),
expectError: false,
@@ -32,16 +37,21 @@ func TestMultiPdfEngines_Merge(t *testing.T) {
{
scenario: "at least one engine does not return an error",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return nil
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return nil
},
},
},
nil,
nil,
nil,
),
ctx: context.Background(),
expectError: false,
@@ -49,16 +59,21 @@ func TestMultiPdfEngines_Merge(t *testing.T) {
{
scenario: "all engines return an error",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return errors.New("foo")
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return errors.New("foo")
},
},
},
nil,
nil,
nil,
),
ctx: context.Background(),
expectError: true,
@@ -66,11 +81,16 @@ func TestMultiPdfEngines_Merge(t *testing.T) {
{
scenario: "context expired",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return nil
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
return nil
},
},
},
nil,
nil,
nil,
),
ctx: func() context.Context {
ctx, cancel := context.WithCancel(context.Background())
@@ -105,43 +125,58 @@ func TestMultiPdfEngines_Convert(t *testing.T) {
{
scenario: "nominal behavior",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return nil
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return nil
},
},
},
nil,
nil,
),
ctx: context.Background(),
},
{
scenario: "at least one engine does not return an error",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return nil
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return nil
},
},
},
nil,
nil,
),
ctx: context.Background(),
},
{
scenario: "all engines return an error",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return errors.New("foo")
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return errors.New("foo")
},
},
},
nil,
nil,
),
ctx: context.Background(),
expectError: true,
@@ -149,11 +184,16 @@ func TestMultiPdfEngines_Convert(t *testing.T) {
{
scenario: "context expired",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return nil
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
ConvertMock: func(ctx context.Context, logger *zap.Logger, formats gotenberg.PdfFormats, inputPath, outputPath string) error {
return nil
},
},
},
nil,
nil,
),
ctx: func() context.Context {
ctx, cancel := context.WithCancel(context.Background())
@@ -188,43 +228,58 @@ func TestMultiPdfEngines_ReadMetadata(t *testing.T) {
{
scenario: "nominal behavior",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return make(map[string]interface{}), nil
nil,
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return make(map[string]interface{}), nil
},
},
},
nil,
),
ctx: context.Background(),
},
{
scenario: "at least one engine does not return an error",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return nil, errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return make(map[string]interface{}), nil
nil,
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return nil, errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return make(map[string]interface{}), nil
},
},
},
nil,
),
ctx: context.Background(),
},
{
scenario: "all engines return an error",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return nil, errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return nil, errors.New("foo")
nil,
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return nil, errors.New("foo")
},
},
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return nil, errors.New("foo")
},
},
},
nil,
),
ctx: context.Background(),
expectError: true,
@@ -232,11 +287,16 @@ func TestMultiPdfEngines_ReadMetadata(t *testing.T) {
{
scenario: "context expired",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return make(map[string]interface{}), nil
nil,
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
ReadMetadataMock: func(ctx context.Context, logger *zap.Logger, inputPath string) (map[string]interface{}, error) {
return make(map[string]interface{}), nil
},
},
},
nil,
),
ctx: func() context.Context {
ctx, cancel := context.WithCancel(context.Background())
@@ -271,9 +331,14 @@ func TestMultiPdfEngines_WriteMetadata(t *testing.T) {
{
scenario: "nominal behavior",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return nil
nil,
nil,
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return nil
},
},
},
),
@@ -282,14 +347,19 @@ func TestMultiPdfEngines_WriteMetadata(t *testing.T) {
{
scenario: "at least one engine does not return an error",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return errors.New("foo")
nil,
nil,
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return errors.New("foo")
},
},
},
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return nil
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return nil
},
},
},
),
@@ -298,14 +368,19 @@ func TestMultiPdfEngines_WriteMetadata(t *testing.T) {
{
scenario: "all engines return an error",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return errors.New("foo")
nil,
nil,
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return errors.New("foo")
},
},
},
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return errors.New("foo")
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return errors.New("foo")
},
},
},
),
@@ -315,9 +390,14 @@ func TestMultiPdfEngines_WriteMetadata(t *testing.T) {
{
scenario: "context expired",
engine: newMultiPdfEngines(
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return nil
nil,
nil,
nil,
[]gotenberg.PdfEngine{
&gotenberg.PdfEngineMock{
WriteMetadataMock: func(ctx context.Context, logger *zap.Logger, metadata map[string]interface{}, inputPath string) error {
return nil
},
},
},
),
+96 -41
View File
@@ -27,9 +27,12 @@ func init() {
// the [api.Router] interface to expose relevant PDF processing routes if
// enabled.
type PdfEngines struct {
names []string
engines []gotenberg.PdfEngine
disableRoutes bool
mergeNames []string
convertNames []string
readMetadataNames []string
writeMedataNames []string
engines []gotenberg.PdfEngine
disableRoutes bool
}
// Descriptor returns a PdfEngines' module descriptor.
@@ -38,9 +41,18 @@ func (mod *PdfEngines) Descriptor() gotenberg.ModuleDescriptor {
ID: "pdfengines",
FlagSet: func() *flag.FlagSet {
fs := flag.NewFlagSet("pdfengines", flag.ExitOnError)
fs.StringSlice("pdfengines-engines", make([]string, 0), "Set the PDF engines and their order - all by default")
fs.StringSlice("pdfengines-merge-engines", []string{"qpdf", "pdfcpu", "pdftk"}, "Set the PDF engines and their order for the merge feature")
fs.StringSlice("pdfengines-convert-engines", []string{"libreoffice-pdfengine"}, "Set the PDF engines and their order for the convert feature")
fs.StringSlice("pdfengines-read-metadata-engines", []string{"exiftool"}, "Set the PDF engines and their order for the read metadata feature")
fs.StringSlice("pdfengines-write-metadata-engines", []string{"exiftool"}, "Set the PDF engines and their order for the write metadata feature")
fs.Bool("pdfengines-disable-routes", false, "Disable the routes")
fs.StringSlice("pdfengines-engines", make([]string, 0), "Set the default PDF engines and their default order - all by default")
err := fs.MarkDeprecated("pdfengines-engines", "use other flags for a more granular selection of PDF engines per method")
if err != nil {
panic(err)
}
return fs
}(),
New: func() gotenberg.Module { return new(PdfEngines) },
@@ -51,7 +63,10 @@ func (mod *PdfEngines) Descriptor() gotenberg.ModuleDescriptor {
// selected by the user thanks to the "engines" flag.
func (mod *PdfEngines) Provision(ctx *gotenberg.Context) error {
flags := ctx.ParsedFlags()
names := flags.MustStringSlice("pdfengines-engines")
mergeNames := flags.MustStringSlice("pdfengines-merge-engines")
convertNames := flags.MustStringSlice("pdfengines-convert-engines")
readMetadataNames := flags.MustStringSlice("pdfengines-read-metadata-engines")
writeMetadataNames := flags.MustStringSlice("pdfengines-write-metadata-engines")
mod.disableRoutes = flags.MustBool("pdfengines-disable-routes")
engines, err := ctx.Modules(new(gotenberg.PdfEngine))
@@ -65,26 +80,37 @@ func (mod *PdfEngines) Provision(ctx *gotenberg.Context) error {
mod.engines[i] = engine.(gotenberg.PdfEngine)
}
if len(names) > 0 {
// Selection from user.
mod.names = names
// Example in case of deprecated module name.
//for i, name := range names {
// if name == "unoconv-pdfengine" || name == "uno-pdfengine" {
// logger.Warn(fmt.Sprintf("%s is deprecated; prefer libreoffice-pdfengine instead", name))
// mod.names[i] = "libreoffice-pdfengine"
// }
//}
return nil
defaultNames := make([]string, len(mod.engines))
for i, engine := range mod.engines {
defaultNames[i] = engine.(gotenberg.Module).Descriptor().ID
}
// No selection from user, use all PDF engines available.
mod.names = make([]string, len(mod.engines))
// Example in case of deprecated module name.
//for i, name := range defaultNames {
// if name == "unoconv-pdfengine" || name == "uno-pdfengine" {
// logger.Warn(fmt.Sprintf("%s is deprecated; prefer libreoffice-pdfengine instead", name))
// mod.defaultNames[i] = "libreoffice-pdfengine"
// }
//}
for i, engine := range mod.engines {
mod.names[i] = engine.(gotenberg.Module).Descriptor().ID
mod.mergeNames = defaultNames
if len(mergeNames) > 0 {
mod.mergeNames = mergeNames
}
mod.convertNames = defaultNames
if len(convertNames) > 0 {
mod.convertNames = convertNames
}
mod.readMetadataNames = defaultNames
if len(readMetadataNames) > 0 {
mod.readMetadataNames = readMetadataNames
}
mod.writeMedataNames = defaultNames
if len(writeMetadataNames) > 0 {
mod.writeMedataNames = writeMetadataNames
}
return nil
@@ -105,22 +131,40 @@ func (mod *PdfEngines) Validate() error {
}
nonExistingEngines := make([]string, 0)
findNonExistingEngines := func(names []string) {
for _, name := range names {
engineExists := false
for _, name := range mod.names {
engineExists := false
for _, engine := range mod.engines {
if name == engine.(gotenberg.Module).Descriptor().ID {
engineExists = true
break
}
}
for _, engine := range mod.engines {
if name == engine.(gotenberg.Module).Descriptor().ID {
engineExists = true
break
if engineExists {
continue
}
alreadyInSlice := false
for _, engine := range nonExistingEngines {
if engine == name {
alreadyInSlice = true
break
}
}
if !alreadyInSlice {
nonExistingEngines = append(nonExistingEngines, name)
}
}
if !engineExists {
nonExistingEngines = append(nonExistingEngines, name)
}
}
findNonExistingEngines(mod.mergeNames)
findNonExistingEngines(mod.convertNames)
findNonExistingEngines(mod.readMetadataNames)
findNonExistingEngines(mod.writeMedataNames)
if len(nonExistingEngines) == 0 {
return nil
}
@@ -132,24 +176,35 @@ func (mod *PdfEngines) Validate() error {
// modules.
func (mod *PdfEngines) SystemMessages() []string {
return []string{
strings.Join(mod.names[:], " "),
fmt.Sprintf("merge engines - %s", strings.Join(mod.mergeNames[:], " ")),
fmt.Sprintf("convert engines - %s", strings.Join(mod.convertNames[:], " ")),
fmt.Sprintf("read metadata engines - %s", strings.Join(mod.readMetadataNames[:], " ")),
fmt.Sprintf("write medata engines - %s", strings.Join(mod.writeMedataNames[:], " ")),
}
}
// PdfEngine returns a [gotenberg.PdfEngine].
func (mod *PdfEngines) PdfEngine() (gotenberg.PdfEngine, error) {
engines := make([]gotenberg.PdfEngine, len(mod.names))
for i, name := range mod.names {
for _, engine := range mod.engines {
if name == engine.(gotenberg.Module).Descriptor().ID {
engines[i] = engine
break
engines := func(names []string) []gotenberg.PdfEngine {
list := make([]gotenberg.PdfEngine, len(names))
for i, name := range names {
for _, engine := range mod.engines {
if name == engine.(gotenberg.Module).Descriptor().ID {
list[i] = engine
break
}
}
}
return list
}
return newMultiPdfEngines(engines...), nil
return newMultiPdfEngines(
engines(mod.mergeNames),
engines(mod.convertNames),
engines(mod.readMetadataNames),
engines(mod.writeMedataNames),
), nil
}
// Routes returns the HTTP routes.
+80 -22
View File
@@ -2,6 +2,7 @@ package pdfengines
import (
"errors"
"fmt"
"reflect"
"strings"
"testing"
@@ -22,10 +23,13 @@ func TestPdfEngines_Descriptor(t *testing.T) {
func TestPdfEngines_Provision(t *testing.T) {
for _, tc := range []struct {
scenario string
ctx *gotenberg.Context
expectedPdfEngines []string
expectError bool
scenario string
ctx *gotenberg.Context
expectedMergePdfEngines []string
expectedConvertPdfEngines []string
expectedReadMetadataPdfEngines []string
expectedWriteMetadataPdfEngines []string
expectError bool
}{
{
scenario: "no selection from user",
@@ -61,8 +65,11 @@ func TestPdfEngines_Provision(t *testing.T) {
},
)
}(),
expectedPdfEngines: []string{"bar"},
expectError: false,
expectedMergePdfEngines: []string{"qpdf", "pdfcpu", "pdftk"},
expectedConvertPdfEngines: []string{"libreoffice-pdfengine"},
expectedReadMetadataPdfEngines: []string{"exiftool"},
expectedWriteMetadataPdfEngines: []string{"exiftool"},
expectError: false,
},
{
scenario: "selection from user",
@@ -100,7 +107,7 @@ func TestPdfEngines_Provision(t *testing.T) {
}
fs := new(PdfEngines).Descriptor().FlagSet
err := fs.Parse([]string{"--pdfengines-engines=b", "--pdfengines-engines=a"})
err := fs.Parse([]string{"--pdfengines-merge-engines=b", "--pdfengines-convert-engines=b", "--pdfengines-read-metadata-engines=a", "--pdfengines-write-metadata-engines=a"})
if err != nil {
t.Fatalf("expected no error but got: %v", err)
}
@@ -116,8 +123,12 @@ func TestPdfEngines_Provision(t *testing.T) {
},
)
}(),
expectedPdfEngines: []string{"b", "a"},
expectError: false,
expectedMergePdfEngines: []string{"b"},
expectedConvertPdfEngines: []string{"b"},
expectedReadMetadataPdfEngines: []string{"a"},
expectedWriteMetadataPdfEngines: []string{"a"},
expectError: false,
},
{
scenario: "no valid PDF engine",
@@ -167,13 +178,43 @@ func TestPdfEngines_Provision(t *testing.T) {
t.Fatal("expected error but got none")
}
if len(tc.expectedPdfEngines) != len(mod.names) {
t.Fatalf("expected %d names but got %d", len(tc.expectedPdfEngines), len(mod.names))
if len(tc.expectedMergePdfEngines) != len(mod.mergeNames) {
t.Fatalf("expected %d merge names but got %d", len(tc.expectedMergePdfEngines), len(mod.mergeNames))
}
for index, name := range mod.names {
if name != tc.expectedPdfEngines[index] {
t.Fatalf("expected scenario at index %d to be %s, but got: %s", index, name, tc.expectedPdfEngines[index])
if len(tc.expectedConvertPdfEngines) != len(mod.convertNames) {
t.Fatalf("expected %d convert names but got %d", len(tc.expectedConvertPdfEngines), len(mod.convertNames))
}
if len(tc.expectedReadMetadataPdfEngines) != len(mod.readMetadataNames) {
t.Fatalf("expected %d read metadata names but got %d", len(tc.expectedReadMetadataPdfEngines), len(mod.readMetadataNames))
}
if len(tc.expectedWriteMetadataPdfEngines) != len(mod.writeMedataNames) {
t.Fatalf("expected %d write metadata names but got %d", len(tc.expectedWriteMetadataPdfEngines), len(mod.writeMedataNames))
}
for index, name := range mod.mergeNames {
if name != tc.expectedMergePdfEngines[index] {
t.Fatalf("expected merge name at index %d to be %s, but got: %s", index, name, tc.expectedMergePdfEngines[index])
}
}
for index, name := range mod.convertNames {
if name != tc.expectedConvertPdfEngines[index] {
t.Fatalf("expected convert name at index %d to be %s, but got: %s", index, name, tc.expectedConvertPdfEngines[index])
}
}
for index, name := range mod.readMetadataNames {
if name != tc.expectedReadMetadataPdfEngines[index] {
t.Fatalf("expected read metadata name at index %d to be %s, but got: %s", index, name, tc.expectedReadMetadataPdfEngines[index])
}
}
for index, name := range mod.writeMedataNames {
if name != tc.expectedWriteMetadataPdfEngines[index] {
t.Fatalf("expected write metadat name at index %d to be %s, but got: %s", index, name, tc.expectedWriteMetadataPdfEngines[index])
}
}
})
@@ -239,8 +280,11 @@ func TestPdfEngines_Validate(t *testing.T) {
} {
t.Run(tc.scenario, func(t *testing.T) {
mod := PdfEngines{
names: tc.names,
engines: tc.engines,
mergeNames: tc.names,
convertNames: tc.names,
readMetadataNames: tc.names,
writeMedataNames: tc.names,
engines: tc.engines,
}
err := mod.Validate()
@@ -258,22 +302,36 @@ func TestPdfEngines_Validate(t *testing.T) {
func TestPdfEngines_SystemMessages(t *testing.T) {
mod := new(PdfEngines)
mod.names = []string{"foo", "bar"}
mod.mergeNames = []string{"foo", "bar"}
mod.convertNames = []string{"foo", "bar"}
mod.readMetadataNames = []string{"foo", "bar"}
mod.writeMedataNames = []string{"foo", "bar"}
messages := mod.SystemMessages()
if len(messages) != 1 {
if len(messages) != 4 {
t.Errorf("expected one and only one message, but got %d", len(messages))
}
expect := strings.Join(mod.names[:], " ")
if messages[0] != expect {
t.Errorf("expected message '%s', but got '%s'", expect, messages[0])
expect := []string{
fmt.Sprintf("merge engines - %s", strings.Join(mod.mergeNames[:], " ")),
fmt.Sprintf("convert engines - %s", strings.Join(mod.convertNames[:], " ")),
fmt.Sprintf("read metadata engines - %s", strings.Join(mod.readMetadataNames[:], " ")),
fmt.Sprintf("write medata engines - %s", strings.Join(mod.writeMedataNames[:], " ")),
}
for i, message := range messages {
if message != expect[i] {
t.Errorf("expected message at index %d to be %s, but got %s", i, message, expect[i])
}
}
}
func TestPdfEngines_PdfEngine(t *testing.T) {
mod := PdfEngines{
names: []string{"foo", "bar"},
mergeNames: []string{"foo", "bar"},
convertNames: []string{"foo", "bar"},
readMetadataNames: []string{"foo", "bar"},
writeMedataNames: []string{"foo", "bar"},
engines: func() []gotenberg.PdfEngine {
engine1 := &struct {
gotenberg.ModuleMock