adding test for printer package

This commit is contained in:
Julien Neuhart
2019-08-18 17:31:07 +02:00
parent 6964124c1b
commit 2fee966fc8
11 changed files with 346 additions and 79 deletions

View File

@@ -12,6 +12,7 @@ import (
"github.com/mafredri/cdp/protocol/page"
"github.com/mafredri/cdp/protocol/target"
"github.com/mafredri/cdp/rpcc"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/xcontext"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
@@ -26,7 +27,7 @@ type chromePrinter struct {
}
// ChromePrinterOptions helps customizing the
// Google Chrome printer behaviour.
// Google Chrome Printer behaviour.
type ChromePrinterOptions struct {
WaitTimeout float64
WaitDelay float64
@@ -41,6 +42,25 @@ type ChromePrinterOptions struct {
Landscape bool
}
// DefaultChromePrinterOptions returns the default
// Google Chrome Printer options.
func DefaultChromePrinterOptions(config conf.Config) ChromePrinterOptions {
const defaultHeaderFooterHTML string = "<html><head></head><body></body></html>"
return ChromePrinterOptions{
WaitTimeout: config.DefaultWaitTimeout(),
WaitDelay: 0.0,
HeaderHTML: defaultHeaderFooterHTML,
FooterHTML: defaultHeaderFooterHTML,
PaperWidth: 8.27,
PaperHeight: 11.7,
MarginTop: 1.0,
MarginBottom: 1.0,
MarginLeft: 1.0,
MarginRight: 1.0,
Landscape: false,
}
}
func (p chromePrinter) Print(destination string) error {
const op string = "printer.chromePrinter.Print"
logOptions(p.logger, p.opts)
@@ -83,21 +103,23 @@ func (p chromePrinter) Print(destination string) error {
closeTargetArgs := target.NewCloseTargetArgs(newTarget.TargetID)
// close the target when done.
defer targetClient.Target.CloseTarget(ctx, closeTargetArgs) // nolint: errcheck
if err := runBatch(
// enable all the domain events that we're interested in.
func() error { return targetClient.DOM.Enable(ctx) },
func() error { return targetClient.Network.Enable(ctx, network.NewEnableArgs()) },
func() error { return targetClient.Page.Enable(ctx) },
func() error {
return targetClient.Page.SetLifecycleEventsEnabled(ctx, page.NewSetLifecycleEventsEnabledArgs(true))
},
func() error { return targetClient.Runtime.Enable(ctx) },
); err != nil {
// enable all events.
if err := p.enableEvents(ctx, targetClient); err != nil {
return err
}
if err := p.navigate(ctx, targetClient); err != nil {
// listen for all events.
if err := p.listenEvents(ctx, targetClient); err != nil {
return err
}
// apply a wait delay (if any).
if p.opts.WaitDelay > 0.0 {
// wait for a given amount of time (useful for javascript delay).
p.logger.DebugfOp(op, "applying a wait delay of '%.2fs'...", p.opts.WaitDelay)
time.Sleep(xtime.Duration(p.opts.WaitDelay))
} else {
p.logger.DebugOp(op, "no wait delay to apply, moving on...")
}
// print the page to PDF.
print, err := targetClient.Page.PrintToPDF(
ctx,
page.NewPrintToPDFArgs().
@@ -130,8 +152,25 @@ func (p chromePrinter) Print(destination string) error {
return nil
}
func (p chromePrinter) navigate(ctx context.Context, client *cdp.Client) error {
const op string = "printer.chromePrinter.navigate"
func (p chromePrinter) enableEvents(ctx context.Context, client *cdp.Client) error {
const op string = "printer.chromePrinter.enableEvents"
// enable all the domain events that we're interested in.
if err := runBatch(
func() error { return client.DOM.Enable(ctx) },
func() error { return client.Network.Enable(ctx, network.NewEnableArgs()) },
func() error { return client.Page.Enable(ctx) },
func() error {
return client.Page.SetLifecycleEventsEnabled(ctx, page.NewSetLifecycleEventsEnabledArgs(true))
},
func() error { return client.Runtime.Enable(ctx) },
); err != nil {
return xerror.New(op, err)
}
return nil
}
func (p chromePrinter) listenEvents(ctx context.Context, client *cdp.Client) error {
const op string = "printer.chromePrinter.listenEvents"
resolver := func() error {
// make sure Page events are enabled.
if err := client.Page.Enable(ctx); err != nil {
@@ -165,10 +204,24 @@ func (p chromePrinter) navigate(ctx context.Context, client *cdp.Client) error {
if _, err := client.Page.Navigate(ctx, page.NewNavigateArgs(p.url)); err != nil {
return err
}
if err := runBatch(
// wait for all events.
func() error { _, err := domContentEventFired.Recv(); return err },
func() error { _, err := loadEventFired.Recv(); return err },
// wait for all events.
return runBatch(
func() error {
_, err := domContentEventFired.Recv()
if err != nil {
return err
}
p.logger.DebugOp(op, "event 'domContentEventFired' received")
return nil
},
func() error {
_, err := loadEventFired.Recv()
if err != nil {
return err
}
p.logger.DebugOp(op, "event 'loadEventFired' received")
return nil
},
func() error {
const networkIdleEventName string = "networkIdle"
for {
@@ -176,25 +229,22 @@ func (p chromePrinter) navigate(ctx context.Context, client *cdp.Client) error {
if err != nil {
return err
}
p.logger.DebugfOp(op, "event '%s' received", ev.Name)
if ev.Name == networkIdleEventName {
break
}
}
return nil
},
func() error { _, err := loadingFinished.Recv(); return err },
); err != nil {
return err
}
if p.opts.WaitDelay > 0.0 {
// wait for a given amount of time (useful for javascript delay).
p.logger.DebugfOp(op, "applying a wait delay of '%.2fs'...", p.opts.WaitDelay)
time.Sleep(xtime.Duration(p.opts.WaitDelay))
} else {
p.logger.DebugOp(op, "no wait delay to apply, moving on...")
}
return nil
func() error {
_, err := loadingFinished.Recv()
if err != nil {
return err
}
p.logger.DebugOp(op, "event 'loadingFinished' received")
return nil
},
)
}
if err := resolver(); err != nil {
return xerror.New(op, err)

View File

@@ -0,0 +1,52 @@
package printer
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
"github.com/thecodingmachine/gotenberg/test"
)
func TestHTMLPrinter(t *testing.T) {
var (
logger xlog.Logger = test.DebugLogger()
config conf.Config = conf.DefaultConfig()
fpath string = test.HTMLFpaths(t)[0]
opts ChromePrinterOptions
dest string
p Printer
err error
)
// default options.
opts = DefaultChromePrinterOptions(config)
p = NewHTMLPrinter(logger, fpath, opts)
dest = test.GenerateDestination()
err = p.Print(dest)
assert.Nil(t, err)
err = os.RemoveAll(dest)
assert.Nil(t, err)
// options with a wait delay.
opts = DefaultChromePrinterOptions(config)
opts.WaitDelay = 0.5
p = NewHTMLPrinter(logger, fpath, opts)
dest = test.GenerateDestination()
err = p.Print(dest)
assert.Nil(t, err)
err = os.RemoveAll(dest)
assert.Nil(t, err)
// should not be OK as context.Context
// should timeout.
opts = DefaultChromePrinterOptions(config)
opts.WaitTimeout = 0.0
p = NewHTMLPrinter(logger, fpath, opts)
dest = test.GenerateDestination()
err = p.Print(dest)
test.AssertError(t, err)
assert.Equal(t, xerror.TimeoutCode, xerror.Code(err))
err = os.RemoveAll(dest)
assert.Nil(t, err)
}

View File

@@ -35,7 +35,7 @@ func NewMarkdownPrinter(logger xlog.Logger, fpath string, opts ChromePrinterOpti
}
baseFilename := xrand.Get()
dst := fmt.Sprintf("%s/%s.html", dirPath, baseFilename)
logger.DebugOp(op, "writing the HTML from previous conversion into new file...")
logger.DebugOp(op, "writing the HTML from previous conversion(s) into new file...")
if err := ioutil.WriteFile(dst, buffer.Bytes(), 0644); err != nil {
return "", err
}

View File

@@ -0,0 +1,55 @@
package printer
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
"github.com/thecodingmachine/gotenberg/test"
)
func TestMarkdownPrinter(t *testing.T) {
var (
logger xlog.Logger = test.DebugLogger()
config conf.Config = conf.DefaultConfig()
fpath string = test.MarkdownFpaths(t)[0]
opts ChromePrinterOptions
dest string
p Printer
err error
)
// default options.
opts = DefaultChromePrinterOptions(config)
p, err = NewMarkdownPrinter(logger, fpath, opts)
assert.Nil(t, err)
dest = test.GenerateDestination()
err = p.Print(dest)
assert.Nil(t, err)
err = os.RemoveAll(dest)
assert.Nil(t, err)
// options with a wait delay.
opts = DefaultChromePrinterOptions(config)
opts.WaitDelay = 0.5
p, err = NewMarkdownPrinter(logger, fpath, opts)
assert.Nil(t, err)
dest = test.GenerateDestination()
err = p.Print(dest)
assert.Nil(t, err)
err = os.RemoveAll(dest)
assert.Nil(t, err)
// should not be OK as context.Context
// should timeout.
opts = DefaultChromePrinterOptions(config)
opts.WaitTimeout = 0.0
p, err = NewMarkdownPrinter(logger, fpath, opts)
assert.Nil(t, err)
dest = test.GenerateDestination()
err = p.Print(dest)
test.AssertError(t, err)
assert.Equal(t, xerror.TimeoutCode, xerror.Code(err))
err = os.RemoveAll(dest)
assert.Nil(t, err)
}

View File

@@ -3,6 +3,7 @@ package printer
import (
"context"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/xcontext"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xexec"
@@ -22,6 +23,14 @@ type MergePrinterOptions struct {
WaitTimeout float64
}
// DefaultMergePrinterOptions returns the default
// merge Printer options.
func DefaultMergePrinterOptions(config conf.Config) MergePrinterOptions {
return MergePrinterOptions{
WaitTimeout: config.DefaultWaitTimeout(),
}
}
// NewMergePrinter returns a Printer which
// is able to merge PDFs.
func NewMergePrinter(logger xlog.Logger, fpaths []string, opts MergePrinterOptions) Printer {

View File

@@ -5,6 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
"github.com/thecodingmachine/gotenberg/test"
@@ -13,6 +14,7 @@ import (
func TestMergePrinter(t *testing.T) {
var (
logger xlog.Logger = test.DebugLogger()
config conf.Config = conf.DefaultConfig()
fpaths []string = test.MergeFpaths(t)
opts MergePrinterOptions
dest string
@@ -20,9 +22,7 @@ func TestMergePrinter(t *testing.T) {
err error
)
// default options.
opts = MergePrinterOptions{
WaitTimeout: 10.0,
}
opts = DefaultMergePrinterOptions(config)
p = NewMergePrinter(logger, fpaths, opts)
dest = test.GenerateDestination()
err = p.Print(dest)
@@ -31,9 +31,8 @@ func TestMergePrinter(t *testing.T) {
assert.Nil(t, err)
// should not be OK as context.Context
// should timeout.
opts = MergePrinterOptions{
WaitTimeout: 0.0,
}
opts = DefaultMergePrinterOptions(config)
opts.WaitTimeout = 0.0
p = NewMergePrinter(logger, fpaths, opts)
dest = test.GenerateDestination()
err = p.Print(dest)

View File

@@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/xcontext"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xexec"
@@ -26,6 +27,15 @@ type OfficePrinterOptions struct {
Landscape bool
}
// DefaultOfficePrinterOptions returns the default
// Office Printer options.
func DefaultOfficePrinterOptions(config conf.Config) OfficePrinterOptions {
return OfficePrinterOptions{
WaitTimeout: config.DefaultWaitTimeout(),
Landscape: false,
}
}
// NewOfficePrinter returns a Printer which
// is able to convert Office documents to PDF.
func NewOfficePrinter(logger xlog.Logger, fpaths []string, opts OfficePrinterOptions) Printer {

View File

@@ -5,6 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
"github.com/thecodingmachine/gotenberg/test"
@@ -13,6 +14,7 @@ import (
func TestOfficePrinter(t *testing.T) {
var (
logger xlog.Logger = test.DebugLogger()
config conf.Config = conf.DefaultConfig()
fpaths []string = test.OfficeFpaths(t)
opts OfficePrinterOptions
dest string
@@ -20,10 +22,7 @@ func TestOfficePrinter(t *testing.T) {
err error
)
// default options.
opts = OfficePrinterOptions{
WaitTimeout: 10.0,
Landscape: false,
}
opts = DefaultOfficePrinterOptions(config)
p = NewOfficePrinter(logger, fpaths, opts)
dest = test.GenerateDestination()
err = p.Print(dest)
@@ -31,10 +30,7 @@ func TestOfficePrinter(t *testing.T) {
err = os.RemoveAll(dest)
assert.Nil(t, err)
// using one file.
opts = OfficePrinterOptions{
WaitTimeout: 10.0,
Landscape: false,
}
opts = DefaultOfficePrinterOptions(config)
p = NewOfficePrinter(logger, []string{fpaths[0]}, opts)
dest = test.GenerateDestination()
err = p.Print(dest)
@@ -42,10 +38,8 @@ func TestOfficePrinter(t *testing.T) {
err = os.RemoveAll(dest)
assert.Nil(t, err)
// options with landscape.
opts = OfficePrinterOptions{
WaitTimeout: 10.0,
Landscape: true,
}
opts = DefaultOfficePrinterOptions(config)
opts.Landscape = true
p = NewOfficePrinter(logger, fpaths, opts)
dest = test.GenerateDestination()
err = p.Print(dest)
@@ -54,10 +48,8 @@ func TestOfficePrinter(t *testing.T) {
assert.Nil(t, err)
// should not be OK as context.Context
// should timeout.
opts = OfficePrinterOptions{
WaitTimeout: 0.0,
Landscape: true,
}
opts = DefaultOfficePrinterOptions(config)
opts.WaitTimeout = 0.0
p = NewOfficePrinter(logger, fpaths, opts)
dest = test.GenerateDestination()
err = p.Print(dest)

View File

@@ -0,0 +1,52 @@
package printer
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
"github.com/thecodingmachine/gotenberg/test"
)
func TestURLPrinter(t *testing.T) {
var (
logger xlog.Logger = test.DebugLogger()
config conf.Config = conf.DefaultConfig()
URL = "https://google.com"
opts ChromePrinterOptions
dest string
p Printer
err error
)
// default options.
opts = DefaultChromePrinterOptions(config)
p = NewURLPrinter(logger, URL, opts)
dest = test.GenerateDestination()
err = p.Print(dest)
assert.Nil(t, err)
err = os.RemoveAll(dest)
assert.Nil(t, err)
// options with a wait delay.
opts = DefaultChromePrinterOptions(config)
opts.WaitDelay = 0.5
p = NewURLPrinter(logger, URL, opts)
dest = test.GenerateDestination()
err = p.Print(dest)
assert.Nil(t, err)
err = os.RemoveAll(dest)
assert.Nil(t, err)
// should not be OK as context.Context
// should timeout.
opts = DefaultChromePrinterOptions(config)
opts.WaitTimeout = 0.0
p = NewURLPrinter(logger, URL, opts)
dest = test.GenerateDestination()
err = p.Print(dest)
test.AssertError(t, err)
assert.Equal(t, xerror.TimeoutCode, xerror.Code(err))
err = os.RemoveAll(dest)
assert.Nil(t, err)
}

View File

@@ -11,41 +11,51 @@ import (
"github.com/stretchr/testify/require"
)
// MergeMultipartForm returns the body
// for a multipart/form-data request with all
// files under "pdf" folder.
/*
MergeMultipartForm returns the body
for a multipart/form-data request with all
files under "testdata/pdf" folder.
*/
func MergeMultipartForm(t *testing.T, formValues map[string]string) (*bytes.Buffer, string) {
fpaths := MergeFpaths(t)
return multipartForm(t, "pdf", formValues, fpaths)
}
// HTMLMultipartForm returns the body
// for a multipart/form-data request with all
// files under "html" folder.
/*
HTMLMultipartForm returns the body
for a multipart/form-data request with all
files under "testdata/html" folder.
*/
func HTMLMultipartForm(t *testing.T, formValues map[string]string) (*bytes.Buffer, string) {
// TODO
return multipartForm(t, "html", formValues, []string{})
fpaths := HTMLFpaths(t)
return multipartForm(t, "html", formValues, fpaths)
}
// URLMultipartForm returns the body
// for a multipart/form-data request with all
// files under "url" folder.
/*
URLMultipartForm returns the body
for a multipart/form-data request with all
files under "testdata/url" folder.
*/
func URLMultipartForm(t *testing.T, formValues map[string]string) (*bytes.Buffer, string) {
// TODO
return multipartForm(t, "url", formValues, []string{})
fpaths := URLFpaths(t)
return multipartForm(t, "url", formValues, fpaths)
}
// MarkdownMultipartForm returns the body
// for a multipart/form-data request with all
// files under "markdown" folder.
/*
MarkdownMultipartForm returns the body
for a multipart/form-data request with all
files under "testdata/markdown" folder.
*/
func MarkdownMultipartForm(t *testing.T, formValues map[string]string) (*bytes.Buffer, string) {
// TODO
return multipartForm(t, "markdown", formValues, []string{})
fpaths := MarkdownFpaths(t)
return multipartForm(t, "markdown", formValues, fpaths)
}
// OfficeMultipartForm returns the body
// for a multipart/form-data request with all
// files under "office" folder.
/*
OfficeMultipartForm returns the body
for a multipart/form-data request with all
files under "testdata/office" folder.
*/
func OfficeMultipartForm(t *testing.T, formValues map[string]string) (*bytes.Buffer, string) {
fpaths := OfficeFpaths(t)
return multipartForm(t, "office", formValues, fpaths)

View File

@@ -21,8 +21,8 @@ func GenerateDestination() string {
return fmt.Sprintf("/tmp/%s.pdf", xrand.Get())
}
// MergeFpaths return the paths
// of the PDF files used in tests.
// MergeFpaths return the paths of all
// files under "testdata/pdf" folder.
func MergeFpaths(t *testing.T) []string {
return []string{
fpath(t, "pdf", "gotenberg.pdf"),
@@ -30,8 +30,46 @@ func MergeFpaths(t *testing.T) []string {
}
}
// OfficeFpaths return the paths
// of the Office documents used in tests.
// HTMLFpaths return the paths of all
// files under "testdata/html" folder.
func HTMLFpaths(t *testing.T) []string {
return []string{
fpath(t, "html", "index.html"),
fpath(t, "html", "header.html"),
fpath(t, "html", "footer.html"),
fpath(t, "html", "style.css"),
fpath(t, "html", "img.gif"),
fpath(t, "html", "font.woff"),
}
}
// URLFpaths return the paths of all
// files under "testdata/url" folder.
func URLFpaths(t *testing.T) []string {
return []string{
fpath(t, "url", "header.html"),
fpath(t, "url", "footer.html"),
}
}
// MarkdownFpaths return the paths of all
// files under "testdata/markdown" folder.
func MarkdownFpaths(t *testing.T) []string {
return []string{
fpath(t, "markdown", "index.html"),
fpath(t, "markdown", "header.html"),
fpath(t, "markdown", "footer.html"),
fpath(t, "markdown", "style.css"),
fpath(t, "markdown", "img.gif"),
fpath(t, "markdown", "font.woff"),
fpath(t, "markdown", "paragraph1.md"),
fpath(t, "markdown", "paragraph2.md"),
fpath(t, "markdown", "paragraph3.md"),
}
}
// OfficeFpaths return the paths of all
// files under "testdata/office" folder.
func OfficeFpaths(t *testing.T) []string {
return []string{
fpath(t, "office", "document.docx"),