mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-15 03:42:15 +01:00
feat: add more PDF formats, drastically improve LibreOffice long-running instance management
This commit is contained in:
865
pkg/modules/libreoffice/uno/uno_test.go
Normal file
865
pkg/modules/libreoffice/uno/uno_test.go
Normal file
@@ -0,0 +1,865 @@
|
||||
package uno
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/alexliesenfeld/health"
|
||||
"github.com/gotenberg/gotenberg/v7/pkg/gotenberg"
|
||||
flag "github.com/spf13/pflag"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func TestUNO_Descriptor(t *testing.T) {
|
||||
descriptor := UNO{}.Descriptor()
|
||||
|
||||
actual := reflect.TypeOf(descriptor.New())
|
||||
expect := reflect.TypeOf(new(UNO))
|
||||
|
||||
if actual != expect {
|
||||
t.Errorf("expected '%s' but got '%s'", expect, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNO_Provision(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx *gotenberg.Context
|
||||
expectProvisionErr bool
|
||||
}{
|
||||
{
|
||||
name: "nominal behavior",
|
||||
ctx: func() *gotenberg.Context {
|
||||
provider := struct {
|
||||
gotenberg.ModuleMock
|
||||
gotenberg.LoggerProviderMock
|
||||
}{}
|
||||
provider.DescriptorMock = func() gotenberg.ModuleDescriptor {
|
||||
return gotenberg.ModuleDescriptor{ID: "foo", New: func() gotenberg.Module {
|
||||
return provider
|
||||
}}
|
||||
}
|
||||
provider.LoggerMock = func(mod gotenberg.Module) (*zap.Logger, error) {
|
||||
return zap.NewNop(), nil
|
||||
}
|
||||
|
||||
return gotenberg.NewContext(
|
||||
gotenberg.ParsedFlags{
|
||||
FlagSet: new(UNO).Descriptor().FlagSet,
|
||||
},
|
||||
[]gotenberg.ModuleDescriptor{
|
||||
provider.Descriptor(),
|
||||
},
|
||||
)
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "threshold from deprecated flag --unoconv-disable-listener",
|
||||
ctx: func() *gotenberg.Context {
|
||||
provider := struct {
|
||||
gotenberg.ModuleMock
|
||||
gotenberg.LoggerProviderMock
|
||||
}{}
|
||||
provider.DescriptorMock = func() gotenberg.ModuleDescriptor {
|
||||
return gotenberg.ModuleDescriptor{ID: "foo", New: func() gotenberg.Module {
|
||||
return provider
|
||||
}}
|
||||
}
|
||||
provider.LoggerMock = func(mod gotenberg.Module) (*zap.Logger, error) {
|
||||
return zap.NewNop(), nil
|
||||
}
|
||||
|
||||
return gotenberg.NewContext(
|
||||
gotenberg.ParsedFlags{
|
||||
FlagSet: func() *flag.FlagSet {
|
||||
fs := new(UNO).Descriptor().FlagSet
|
||||
err := fs.Parse([]string{"--unoconv-disable-listener=true"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error from fs.Parse(), but got: %v", err)
|
||||
}
|
||||
|
||||
return fs
|
||||
}(),
|
||||
},
|
||||
[]gotenberg.ModuleDescriptor{
|
||||
provider.Descriptor(),
|
||||
},
|
||||
)
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "no logger provider",
|
||||
ctx: func() *gotenberg.Context {
|
||||
return gotenberg.NewContext(
|
||||
gotenberg.ParsedFlags{
|
||||
FlagSet: new(UNO).Descriptor().FlagSet,
|
||||
},
|
||||
[]gotenberg.ModuleDescriptor{},
|
||||
)
|
||||
}(),
|
||||
expectProvisionErr: true,
|
||||
},
|
||||
{
|
||||
name: "no logger from logger provider",
|
||||
ctx: func() *gotenberg.Context {
|
||||
provider := struct {
|
||||
gotenberg.ModuleMock
|
||||
gotenberg.LoggerProviderMock
|
||||
}{}
|
||||
provider.DescriptorMock = func() gotenberg.ModuleDescriptor {
|
||||
return gotenberg.ModuleDescriptor{ID: "foo", New: func() gotenberg.Module {
|
||||
return provider
|
||||
}}
|
||||
}
|
||||
provider.LoggerMock = func(mod gotenberg.Module) (*zap.Logger, error) {
|
||||
return nil, errors.New("foo")
|
||||
}
|
||||
|
||||
return gotenberg.NewContext(
|
||||
gotenberg.ParsedFlags{
|
||||
FlagSet: new(UNO).Descriptor().FlagSet,
|
||||
},
|
||||
[]gotenberg.ModuleDescriptor{
|
||||
provider.Descriptor(),
|
||||
},
|
||||
)
|
||||
}(),
|
||||
expectProvisionErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
mod := new(UNO)
|
||||
err := mod.Provision(tc.ctx)
|
||||
|
||||
if tc.expectProvisionErr && err == nil {
|
||||
t.Errorf("expected mod.Provision() error, but got none")
|
||||
}
|
||||
|
||||
if !tc.expectProvisionErr && err != nil {
|
||||
t.Errorf("expected no error from mod.Provision(), but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNO_Validate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
unoconvBinPath string
|
||||
libreOfficeBinPath string
|
||||
expectValidateErr bool
|
||||
}{
|
||||
{
|
||||
name: "nominal behavior",
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
},
|
||||
{
|
||||
name: "unoconv bin path does not exist",
|
||||
unoconvBinPath: "/foo",
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
expectValidateErr: true,
|
||||
},
|
||||
{
|
||||
name: "LibreOffice bin path does not exist",
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: "/foo",
|
||||
expectValidateErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
mod := UNO{
|
||||
unoconvBinPath: tc.unoconvBinPath,
|
||||
libreOfficeBinPath: tc.libreOfficeBinPath,
|
||||
}
|
||||
|
||||
err := mod.Validate()
|
||||
|
||||
if tc.expectValidateErr && err == nil {
|
||||
t.Errorf("expected mod.Validate() error, but got none")
|
||||
}
|
||||
|
||||
if !tc.expectValidateErr && err != nil {
|
||||
t.Errorf("expected no error from mod.Validate(), but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNO_Start(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mod UNO
|
||||
expectStartErr bool
|
||||
}{
|
||||
{
|
||||
name: "nominal behavior",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 10,
|
||||
listener: listenerMock{
|
||||
startMock: func(logger *zap.Logger) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "start error",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 10,
|
||||
listener: listenerMock{
|
||||
startMock: func(logger *zap.Logger) error {
|
||||
return errors.New("foo")
|
||||
},
|
||||
},
|
||||
},
|
||||
expectStartErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := tc.mod.Start()
|
||||
|
||||
if tc.expectStartErr && err == nil {
|
||||
t.Errorf("expected mod.Start() error, but got none")
|
||||
}
|
||||
|
||||
if !tc.expectStartErr && err != nil {
|
||||
t.Errorf("expected no error from mod.Start(), but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNO_StartupMessage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mod UNO
|
||||
expectMessage string
|
||||
}{
|
||||
{
|
||||
name: "long-running LibreOffice listener started",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 10,
|
||||
},
|
||||
expectMessage: "Long-running LibreOffice listener started",
|
||||
},
|
||||
{
|
||||
name: "long-running LibreOffice listener disabled",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
expectMessage: "Long-running LibreOffice listener disabled",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actual := tc.mod.StartupMessage()
|
||||
|
||||
if tc.expectMessage != actual {
|
||||
t.Errorf("expected '%s' from mod.StartupMessage(), but got '%s'", tc.expectMessage, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNO_Stop(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mod UNO
|
||||
expectStopErr bool
|
||||
}{
|
||||
{
|
||||
name: "nominal behavior",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 10,
|
||||
listener: listenerMock{
|
||||
stopMock: func(logger *zap.Logger) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
logger: zap.NewNop(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 0,
|
||||
logger: zap.NewNop(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "stop error",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 10,
|
||||
listener: listenerMock{
|
||||
stopMock: func(logger *zap.Logger) error {
|
||||
return errors.New("foo")
|
||||
},
|
||||
},
|
||||
logger: zap.NewNop(),
|
||||
},
|
||||
expectStopErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(10)*time.Second)
|
||||
cancel()
|
||||
|
||||
err := tc.mod.Stop(ctx)
|
||||
|
||||
if tc.expectStopErr && err == nil {
|
||||
t.Errorf("expected mod.Stop() error, but got none")
|
||||
}
|
||||
|
||||
if !tc.expectStopErr && err != nil {
|
||||
t.Errorf("expected no error from mod.Stop(), but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNO_Metrics(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mod UNO
|
||||
expectUnoconvActiveInstancesCount float64
|
||||
expectLibreOfficeListenerActiveInstancesCount float64
|
||||
expectLibreOfficeListenerQueueLength float64
|
||||
}{
|
||||
{
|
||||
name: "with healthy long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 10,
|
||||
listener: listenerMock{
|
||||
queueMock: func() int {
|
||||
return 0
|
||||
},
|
||||
healthyMock: func() bool {
|
||||
return true
|
||||
},
|
||||
},
|
||||
},
|
||||
expectLibreOfficeListenerActiveInstancesCount: 1,
|
||||
},
|
||||
{
|
||||
name: "with unhealthy long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 10,
|
||||
listener: listenerMock{
|
||||
queueMock: func() int {
|
||||
return 0
|
||||
},
|
||||
healthyMock: func() bool {
|
||||
return false
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with no long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 0,
|
||||
listener: listenerMock{
|
||||
queueMock: func() int {
|
||||
return 0
|
||||
},
|
||||
healthyMock: func() bool {
|
||||
return false
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with a queue of 3",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 0,
|
||||
listener: listenerMock{
|
||||
queueMock: func() int {
|
||||
return 3
|
||||
},
|
||||
healthyMock: func() bool {
|
||||
return true
|
||||
},
|
||||
},
|
||||
},
|
||||
expectLibreOfficeListenerQueueLength: 3,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
metrics, err := tc.mod.Metrics()
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error from mod.Metrics(), but got: %v", err)
|
||||
}
|
||||
|
||||
for _, metric := range metrics {
|
||||
switch metric.Name {
|
||||
case "unoconv_active_instances_count":
|
||||
actual := metric.Read()
|
||||
if actual != tc.expectUnoconvActiveInstancesCount {
|
||||
t.Errorf("expected 'unoconv_active_instances_count' to be %.0f, but got %.0f", tc.expectUnoconvActiveInstancesCount, actual)
|
||||
}
|
||||
case "libreoffice_listener_active_instances_count":
|
||||
actual := metric.Read()
|
||||
if actual != tc.expectLibreOfficeListenerActiveInstancesCount {
|
||||
t.Errorf("expected 'libreoffice_listener_active_instances_count' to be %.0f, but got %.0f", tc.expectLibreOfficeListenerActiveInstancesCount, actual)
|
||||
}
|
||||
case "unoconv_listener_active_instances_count":
|
||||
actual := metric.Read()
|
||||
if actual != tc.expectLibreOfficeListenerActiveInstancesCount {
|
||||
t.Errorf("expected 'unoconv_listener_active_instances_count' to be %.0f, but got %.0f", tc.expectLibreOfficeListenerActiveInstancesCount, actual)
|
||||
}
|
||||
case "libreoffice_listener_queue_length":
|
||||
actual := metric.Read()
|
||||
if actual != tc.expectLibreOfficeListenerQueueLength {
|
||||
t.Errorf("expected 'libreoffice_listener_queue_length' to be %.0f, but got %.0f", tc.expectLibreOfficeListenerQueueLength, actual)
|
||||
}
|
||||
case "unoconv_listener_queue_length":
|
||||
actual := metric.Read()
|
||||
if actual != tc.expectLibreOfficeListenerQueueLength {
|
||||
t.Errorf("expected 'unoconv_listener_queue_length' to be %.0f, but got %.0f", tc.expectLibreOfficeListenerQueueLength, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNO_Checks(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mod UNO
|
||||
expectAvailabilityStatus health.AvailabilityStatus
|
||||
}{
|
||||
{
|
||||
name: "no long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with healthy long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 10,
|
||||
listener: listenerMock{
|
||||
healthyMock: func() bool {
|
||||
return true
|
||||
},
|
||||
},
|
||||
},
|
||||
expectAvailabilityStatus: health.StatusUp,
|
||||
},
|
||||
{
|
||||
name: "with unhealthy long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
libreOfficeRestartThreshold: 10,
|
||||
listener: listenerMock{
|
||||
healthyMock: func() bool {
|
||||
return false
|
||||
},
|
||||
},
|
||||
},
|
||||
expectAvailabilityStatus: health.StatusDown,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
checks, err := tc.mod.Checks()
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error from mod.Checks(), but got: %v", err)
|
||||
}
|
||||
|
||||
if len(checks) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if len(checks) != 1 {
|
||||
t.Fatalf("expected 1 check from mod.Checks(), but got %d", len(checks))
|
||||
}
|
||||
|
||||
checker := health.NewChecker(checks...)
|
||||
result := checker.Check(context.Background())
|
||||
|
||||
if result.Status != tc.expectAvailabilityStatus {
|
||||
t.Errorf("expected '%s' as availability status, but got '%s'", tc.expectAvailabilityStatus, result.Status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNO_PDF(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mod UNO
|
||||
ctx context.Context
|
||||
logger *zap.Logger
|
||||
inputPath string
|
||||
options Options
|
||||
expectPDFErr bool
|
||||
teardown func(mod UNO) error
|
||||
}{
|
||||
{
|
||||
name: "nominal behavior with no long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
},
|
||||
{
|
||||
name: "nominal behavior with a long-running LibreOffice listener",
|
||||
mod: func() UNO {
|
||||
mod := UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 10,
|
||||
logger: zap.NewNop(),
|
||||
}
|
||||
mod.listener = newLibreOfficeListener(
|
||||
mod.logger,
|
||||
mod.libreOfficeBinPath,
|
||||
mod.libreOfficeStartTimeout,
|
||||
mod.libreOfficeRestartThreshold,
|
||||
)
|
||||
|
||||
err := mod.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error from mod.Start(), but got: %v", err)
|
||||
}
|
||||
|
||||
return mod
|
||||
}(),
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
teardown: func(mod UNO) error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
return mod.Stop(ctx)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "convert with a debug logger",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewExample(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
},
|
||||
{
|
||||
name: "convert with landscape",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
options: Options{
|
||||
Landscape: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "convert with page ranges",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
options: Options{
|
||||
PageRanges: "1-2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "convert with invalid page ranges",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
options: Options{
|
||||
PageRanges: "foo",
|
||||
},
|
||||
expectPDFErr: true,
|
||||
},
|
||||
{
|
||||
name: "convert to PDF/A-1a",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
options: Options{
|
||||
PDFformat: gotenberg.FormatPDFA1a,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "convert to PDF/A-2b",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
options: Options{
|
||||
PDFformat: gotenberg.FormatPDFA2b,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "convert to PDF/A-3b",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
options: Options{
|
||||
PDFformat: gotenberg.FormatPDFA3b,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "convert to invalid PDF format",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
options: Options{
|
||||
PDFformat: "foo",
|
||||
},
|
||||
expectPDFErr: true,
|
||||
},
|
||||
{
|
||||
name: "nil context",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: nil,
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
expectPDFErr: true,
|
||||
},
|
||||
{
|
||||
name: "expired context",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 0,
|
||||
},
|
||||
ctx: func() context.Context {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
return ctx
|
||||
}(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
expectPDFErr: true,
|
||||
},
|
||||
{
|
||||
name: "cannot lock long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 10,
|
||||
listener: listenerMock{
|
||||
lockMock: func(ctx context.Context, logger *zap.Logger) error {
|
||||
return errors.New("foo")
|
||||
},
|
||||
},
|
||||
logger: zap.NewNop(),
|
||||
},
|
||||
ctx: context.Background(),
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
expectPDFErr: true,
|
||||
},
|
||||
{
|
||||
name: "cannot unlock long-running LibreOffice listener",
|
||||
mod: UNO{
|
||||
unoconvBinPath: os.Getenv("UNOCONV_BIN_PATH"),
|
||||
libreOfficeBinPath: os.Getenv("LIBREOFFICE_BIN_PATH"),
|
||||
libreOfficeStartTimeout: time.Duration(10) * time.Second,
|
||||
libreOfficeRestartThreshold: 10,
|
||||
listener: listenerMock{
|
||||
lockMock: func(ctx context.Context, logger *zap.Logger) error {
|
||||
return nil
|
||||
},
|
||||
unlockMock: func(logger *zap.Logger) error {
|
||||
return errors.New("foo")
|
||||
},
|
||||
portMock: func() int {
|
||||
return 2002
|
||||
},
|
||||
},
|
||||
logger: zap.NewNop(),
|
||||
},
|
||||
ctx: nil,
|
||||
logger: zap.NewNop(),
|
||||
inputPath: "/tests/test/testdata/libreoffice/sample1.docx",
|
||||
expectPDFErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
if tc.teardown == nil {
|
||||
return
|
||||
}
|
||||
|
||||
err := tc.teardown(tc.mod)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error from tc.teardown(), but got: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
outputDir, err := gotenberg.MkdirAll()
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error from gotenberg.MkdirAll(), but got: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := os.RemoveAll(outputDir)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error from os.RemoveAll(), but got: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = tc.mod.PDF(tc.ctx, tc.logger, tc.inputPath, outputDir+"/foo.pdf", tc.options)
|
||||
|
||||
if tc.expectPDFErr && err == nil {
|
||||
t.Fatalf("expected mod.PDF() error, but got none")
|
||||
}
|
||||
|
||||
if !tc.expectPDFErr && err != nil {
|
||||
t.Fatalf("expected no error from mod.PDF(), but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNO_Extensions(t *testing.T) {
|
||||
mod := new(UNO)
|
||||
extensions := mod.Extensions()
|
||||
|
||||
actual := len(extensions)
|
||||
expect := 76
|
||||
|
||||
if actual != expect {
|
||||
t.Errorf("expected %d extensions, but got %d", expect, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNO_UNO(t *testing.T) {
|
||||
mod := new(UNO)
|
||||
|
||||
_, err := mod.UNO()
|
||||
if err != nil {
|
||||
t.Errorf("expected no error from mod.UNO(), but got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type listenerMock struct {
|
||||
startMock func(logger *zap.Logger) error
|
||||
stopMock func(logger *zap.Logger) error
|
||||
lockMock func(ctx context.Context, logger *zap.Logger) error
|
||||
unlockMock func(logger *zap.Logger) error
|
||||
portMock func() int
|
||||
queueMock func() int
|
||||
healthyMock func() bool
|
||||
}
|
||||
|
||||
func (listener listenerMock) start(logger *zap.Logger) error {
|
||||
return listener.startMock(logger)
|
||||
}
|
||||
|
||||
func (listener listenerMock) stop(logger *zap.Logger) error {
|
||||
return listener.stopMock(logger)
|
||||
}
|
||||
|
||||
func (listener listenerMock) lock(ctx context.Context, logger *zap.Logger) error {
|
||||
return listener.lockMock(ctx, logger)
|
||||
}
|
||||
|
||||
func (listener listenerMock) unlock(logger *zap.Logger) error {
|
||||
return listener.unlockMock(logger)
|
||||
}
|
||||
|
||||
func (listener listenerMock) port() int {
|
||||
return listener.portMock()
|
||||
}
|
||||
|
||||
func (listener listenerMock) queue() int {
|
||||
return listener.queueMock()
|
||||
}
|
||||
|
||||
func (listener listenerMock) healthy() bool {
|
||||
return listener.healthyMock()
|
||||
}
|
||||
|
||||
// Interface guards.
|
||||
var (
|
||||
_ listener = (*listenerMock)(nil)
|
||||
)
|
||||
Reference in New Issue
Block a user