process load balancing: broken but in progress

This commit is contained in:
Julien Neuhart
2019-09-19 17:28:29 +02:00
parent c5429f7efa
commit 171f93662f
33 changed files with 1681 additions and 117 deletions

View File

@@ -9,7 +9,9 @@ import (
"github.com/thecodingmachine/gotenberg/internal/app/xhttp/pkg/context"
"github.com/thecodingmachine/gotenberg/internal/app/xhttp/pkg/resource"
"github.com/thecodingmachine/gotenberg/internal/pkg/pm2"
"github.com/thecodingmachine/gotenberg/internal/pkg/printer"
"github.com/thecodingmachine/gotenberg/internal/pkg/prinery"
"github.com/thecodingmachine/gotenberg/internal/pkg/print"
"github.com/thecodingmachine/gotenberg/internal/pkg/xcontext"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
"github.com/thecodingmachine/gotenberg/internal/pkg/xrand"
@@ -39,6 +41,7 @@ func pingHandler(c echo.Context) error {
if logger.Level() != xlog.DebugLevel {
return nil
}
// TODO
list, err := pm2.List()
if err != nil {
return err
@@ -59,17 +62,18 @@ func mergeHandler(c echo.Context) error {
ctx := context.MustCastFromEchoContext(c)
logger := ctx.XLogger()
logger.DebugOp(op, "handling merge request...")
config := ctx.Config()
r := ctx.MustResource()
opts, err := mergePrinterOptions(r, ctx.Config())
timeout, err := resource.WaitTimeoutAndWaitDelayArg(r, config)
if err != nil {
return xerror.New(op, err)
return err
}
fpaths, err := r.Fpaths(".pdf")
if err != nil {
return err
}
p := printer.NewMergePrinter(logger, fpaths, opts)
return convert(ctx, p)
p := print.NewMergePrint(logger, fpaths)
return convert(ctx, nil, p, timeout)
}
if err := resolver(); err != nil {
return xerror.New(op, err)
@@ -83,10 +87,16 @@ func htmlHandler(c echo.Context) error {
const op string = "xhttp.htmlHandler"
resolver := func() error {
ctx := context.MustCastFromEchoContext(c)
prinry := ctx.MustChromePrinery()
logger := ctx.XLogger()
logger.DebugOp(op, "handling HTML request...")
config := ctx.Config()
r := ctx.MustResource()
opts, err := chromePrinterOptions(r, ctx.Config())
timeout, err := resource.WaitTimeoutAndWaitDelayArg(r, config)
if err != nil {
return err
}
opts, err := chromePrintOptions(r, config)
if err != nil {
return err
}
@@ -94,8 +104,8 @@ func htmlHandler(c echo.Context) error {
if err != nil {
return err
}
p := printer.NewHTMLPrinter(logger, fpath, opts)
return convert(ctx, p)
p := print.NewHTMLPrint(logger, fpath, opts)
return convert(ctx, prinry, p, timeout)
}
if err := resolver(); err != nil {
return xerror.New(op, err)
@@ -109,10 +119,16 @@ func urlHandler(c echo.Context) error {
const op string = "xhttp.urlHandler"
resolver := func() error {
ctx := context.MustCastFromEchoContext(c)
prinry := ctx.MustChromePrinery()
logger := ctx.XLogger()
logger.DebugOp(op, "handling URL request...")
config := ctx.Config()
r := ctx.MustResource()
opts, err := chromePrinterOptions(r, ctx.Config())
timeout, err := resource.WaitTimeoutAndWaitDelayArg(r, config)
if err != nil {
return err
}
opts, err := chromePrintOptions(r, config)
if err != nil {
return err
}
@@ -127,8 +143,8 @@ func urlHandler(c echo.Context) error {
if err != nil {
return err
}
p := printer.NewURLPrinter(logger, remoteURL, opts)
return convert(ctx, p)
p := print.NewURLPrint(logger, remoteURL, opts)
return convert(ctx, prinry, p, timeout)
}
if err := resolver(); err != nil {
return xerror.New(op, err)
@@ -142,10 +158,16 @@ func markdownHandler(c echo.Context) error {
const op string = "xhttp.markdownHandler"
resolver := func() error {
ctx := context.MustCastFromEchoContext(c)
prinry := ctx.MustChromePrinery()
logger := ctx.XLogger()
logger.DebugOp(op, "handling Markdown request...")
config := ctx.Config()
r := ctx.MustResource()
opts, err := chromePrinterOptions(r, ctx.Config())
timeout, err := resource.WaitTimeoutAndWaitDelayArg(r, config)
if err != nil {
return err
}
opts, err := chromePrintOptions(r, config)
if err != nil {
return err
}
@@ -153,11 +175,11 @@ func markdownHandler(c echo.Context) error {
if err != nil {
return err
}
p, err := printer.NewMarkdownPrinter(logger, fpath, opts)
p, err := print.NewMarkdownPrint(logger, fpath, opts)
if err != nil {
return err
}
return convert(ctx, p)
return convert(ctx, prinry, p, timeout)
}
if err := resolver(); err != nil {
return xerror.New(op, err)
@@ -171,10 +193,16 @@ func officeHandler(c echo.Context) error {
const op string = "xhttp.officeHandler"
resolver := func() error {
ctx := context.MustCastFromEchoContext(c)
prinry := ctx.MustSofficePrinery()
logger := ctx.XLogger()
logger.DebugOp(op, "handling Office request...")
config := ctx.Config()
r := ctx.MustResource()
opts, err := officePrinterOptions(r, ctx.Config())
timeout, err := resource.WaitTimeoutAndWaitDelayArg(r, config)
if err != nil {
return err
}
opts, err := officePrintOptions(r, config)
if err != nil {
return err
}
@@ -195,8 +223,8 @@ func officeHandler(c echo.Context) error {
if err != nil {
return err
}
p := printer.NewOfficePrinter(logger, fpaths, opts)
return convert(ctx, p)
p := print.NewOfficePrint(logger, fpaths, opts)
return convert(ctx, prinry, p, timeout)
}
if err := resolver(); err != nil {
return xerror.New(op, err)
@@ -204,7 +232,7 @@ func officeHandler(c echo.Context) error {
return nil
}
func convert(ctx context.Context, p printer.Printer) error {
func convert(ctx context.Context, prinry *prinery.Prinery, prnt print.Print, timeout float64) error {
const op string = "xhttp.convert"
resolver := func() error {
logger := ctx.XLogger()
@@ -217,13 +245,13 @@ func convert(ctx context.Context, p printer.Printer) error {
// or an error.
if !r.HasArg(resource.WebhookURLArgKey) {
logger.DebugfOp(op, "no '%s' found, converting synchronously", resource.WebhookURLArgKey)
return convertSync(ctx, p, filename, fpath)
return convertSync(ctx, prinry, prnt, timeout, filename, fpath)
}
// as a webhook URL has been given, we
// run the following lines in a goroutine so that
// it doesn't block.
logger.DebugfOp(op, "'%s' found, converting asynchronously", resource.WebhookURLArgKey)
return convertAsync(ctx, p, filename, fpath)
return convertAsync(ctx, prinry, prnt, timeout, filename, fpath)
}
if err := resolver(); err != nil {
return xerror.New(op, err)
@@ -231,13 +259,19 @@ func convert(ctx context.Context, p printer.Printer) error {
return nil
}
func convertSync(ctx context.Context, p printer.Printer, filename, fpath string) error {
func convertSync(ctx context.Context, prinry *prinery.Prinery, prnt print.Print, timeout float64, filename, fpath string) error {
const op = "xhttp.convertSync"
logger := ctx.XLogger()
r := ctx.MustResource()
timeoutCtx, cancel := xcontext.WithTimeout(logger, timeout)
defer cancel()
resolver := func() error {
logger := ctx.XLogger()
r := ctx.MustResource()
if err := p.Print(fpath); err != nil {
if prinry == nil {
// case: merge.
if err := prnt.Print(timeoutCtx, fpath, nil); err != nil {
return err
}
} else if err := prinry.PrintRequest(timeoutCtx, logger, prnt, fpath); err != nil {
return err
}
if !r.HasArg(resource.ResultFilenameArgKey) {
@@ -267,12 +301,15 @@ func convertSync(ctx context.Context, p printer.Printer, filename, fpath string)
return nil
}
if err := resolver(); err != nil {
return xerror.New(op, err)
return xcontext.MustHandleError(
timeoutCtx,
xerror.New(op, err),
)
}
return nil
}
func convertAsync(ctx context.Context, p printer.Printer, filename, fpath string) error {
func convertAsync(ctx context.Context, prinry *prinery.Prinery, prnt print.Print, timeout float64, filename, fpath string) error {
const op = "xhttp.convertAsync"
logger := ctx.XLogger()
r := ctx.MustResource()
@@ -286,7 +323,16 @@ func convertAsync(ctx context.Context, p printer.Printer, filename, fpath string
}
go func() {
defer r.Close() // nolint: errcheck
if err := p.Print(fpath); err != nil {
timeoutCtx, cancel := xcontext.WithTimeout(logger, timeout)
defer cancel()
if prinry == nil {
// case: merge.
if err := prnt.Print(timeoutCtx, fpath, nil); err != nil {
xerr := xerror.New(op, err)
logger.ErrorOp(xerror.Op(xerr), xerr)
return
}
} else if err := prinry.PrintRequest(timeoutCtx, logger, prnt, fpath); err != nil {
xerr := xerror.New(op, err)
logger.ErrorOp(xerror.Op(xerr), xerr)
return

View File

@@ -19,8 +19,8 @@ import (
func TestPingHandler(t *testing.T) {
// should return 200.
config := conf.DefaultConfig()
srv := New(config)
srv = New(config)
// TODO
srv := New(config, nil, nil)
req := httptest.NewRequest(http.MethodGet, pingEndpoint, nil)
test.AssertStatusCode(t, http.StatusOK, srv, req)
// should returns a JSON as
@@ -28,7 +28,8 @@ func TestPingHandler(t *testing.T) {
os.Setenv(conf.LogLevelEnvVar, "DEBUG")
config, err := conf.FromEnv()
assert.Nil(t, err)
srv = New(config)
// TODO
srv = New(config, nil, nil)
req = httptest.NewRequest(http.MethodGet, pingEndpoint, nil)
rec := httptest.NewRecorder()
srv.ServeHTTP(rec, req)
@@ -39,7 +40,8 @@ func TestPingHandler(t *testing.T) {
func TestMergeHandler(t *testing.T) {
config := conf.DefaultConfig()
srv := New(config)
// TODO
srv := New(config, nil, nil)
// should return 200.
body, contentType := test.MergeMultipartForm(t, nil)
req := httptest.NewRequest(http.MethodPost, mergeEndpoint, body)
@@ -72,7 +74,8 @@ func TestMergeHandler(t *testing.T) {
func TestHTMLHandler(t *testing.T) {
config := conf.DefaultConfig()
srv := New(config)
// TODO
srv := New(config, nil, nil)
endpoint := fmt.Sprintf("%s%s", convertGroupEndpoint, htmlEndpoint)
// should return 200.
body, contentType := test.HTMLMultipartForm(t, nil)
@@ -202,7 +205,8 @@ func TestHTMLHandler(t *testing.T) {
func TestURLHandler(t *testing.T) {
config := conf.DefaultConfig()
srv := New(config)
// TODO
srv := New(config, nil, nil)
endpoint := fmt.Sprintf("%s%s", convertGroupEndpoint, urlEndpoint)
// should return 200.
body, contentType := test.URLMultipartForm(t, nil)
@@ -332,7 +336,8 @@ func TestURLHandler(t *testing.T) {
func TestMarkdownHandler(t *testing.T) {
config := conf.DefaultConfig()
srv := New(config)
// TODO
srv := New(config, nil, nil)
endpoint := fmt.Sprintf("%s%s", convertGroupEndpoint, markdownEndpoint)
// should return 200.
body, contentType := test.MarkdownMultipartForm(t, nil)
@@ -462,7 +467,8 @@ func TestMarkdownHandler(t *testing.T) {
func TestOfficeHandler(t *testing.T) {
config := conf.DefaultConfig()
srv := New(config)
// TODO
srv := New(config, nil, nil)
endpoint := fmt.Sprintf("%s%s", convertGroupEndpoint, officeEndpoint)
// should return 200.
body, contentType := test.OfficeMultipartForm(t, nil)
@@ -524,7 +530,8 @@ func TestWebhook(t *testing.T) {
rcv.Start(":3001")
}()
config := conf.DefaultConfig()
srv := New(config)
// TODO
srv := New(config, nil, nil)
// our custom server should receive the PDF.
body, contentType := test.MergeMultipartForm(t, map[string]string{string(resource.WebhookURLArgKey): "http://localhost:3001/foo"})
req := httptest.NewRequest(http.MethodPost, mergeEndpoint, body)
@@ -536,7 +543,8 @@ func TestWebhook(t *testing.T) {
func TestResultFilename(t *testing.T) {
config := conf.DefaultConfig()
srv := New(config)
// TODO
srv := New(config, nil, nil)
body, contentType := test.MergeMultipartForm(t, map[string]string{string(resource.ResultFilenameArgKey): "foo.pdf"})
req := httptest.NewRequest(http.MethodPost, mergeEndpoint, body)
req.Header.Set(echo.HeaderContentType, contentType)

View File

@@ -7,7 +7,8 @@ import (
"github.com/thecodingmachine/gotenberg/internal/app/xhttp/pkg/context"
"github.com/thecodingmachine/gotenberg/internal/app/xhttp/pkg/resource"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/pm2"
"github.com/thecodingmachine/gotenberg/internal/pkg/prinery"
"github.com/thecodingmachine/gotenberg/internal/pkg/process"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
"github.com/thecodingmachine/gotenberg/internal/pkg/xrand"
@@ -15,7 +16,12 @@ import (
// contextMiddleware extends the default echo.Context with
// our custom context.Context.
func contextMiddleware(config conf.Config, processes ...pm2.Process) echo.MiddlewareFunc {
func contextMiddleware(
config conf.Config,
manager process.Manager,
chromePrinery *prinery.Prinery,
sofficePrinery *prinery.Prinery,
) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// generate a unique identifier for the request.
@@ -25,7 +31,7 @@ func contextMiddleware(config conf.Config, processes ...pm2.Process) echo.Middle
logger := xlog.New(config.LogLevel(), trace)
// extend the current echo context with our custom
// context.
ctx := context.New(c, logger, config, processes...)
ctx := context.New(c, logger, config, manager, chromePrinery, sofficePrinery)
// if its an healthcheck request, there
// is no need to create a Resource.
if ctx.Path() == pingEndpoint {

View File

@@ -3,53 +3,37 @@ package xhttp
import (
"github.com/thecodingmachine/gotenberg/internal/app/xhttp/pkg/resource"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/printer"
"github.com/thecodingmachine/gotenberg/internal/pkg/print"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
)
func mergePrinterOptions(r resource.Resource, config conf.Config) (printer.MergePrinterOptions, error) {
const op string = "xhttp.mergePrinterOptions"
waitTimeout, err := resource.WaitTimeoutArg(r, config)
if err != nil {
return printer.MergePrinterOptions{}, xerror.New(op, err)
}
return printer.MergePrinterOptions{
WaitTimeout: waitTimeout,
}, nil
}
func chromePrinterOptions(r resource.Resource, config conf.Config) (printer.ChromePrinterOptions, error) {
const op string = "xhttp.chromePrinterOptions"
resolver := func() (printer.ChromePrinterOptions, error) {
waitTimeout, err := resource.WaitTimeoutArg(r, config)
if err != nil {
return printer.ChromePrinterOptions{}, err
}
func chromePrintOptions(r resource.Resource, config conf.Config) (print.ChromePrintOptions, error) {
const op string = "xhttp.chromePrintOptions"
resolver := func() (print.ChromePrintOptions, error) {
waitDelay, err := resource.WaitDelayArg(r, config)
if err != nil {
return printer.ChromePrinterOptions{}, err
return print.ChromePrintOptions{}, err
}
headerHTML, footerHTML,
err := resource.HeaderFooterContents(r, config)
if err != nil {
return printer.ChromePrinterOptions{}, err
return print.ChromePrintOptions{}, err
}
paperWidth, paperHeight,
err := resource.PaperSizeArgs(r, config)
if err != nil {
return printer.ChromePrinterOptions{}, err
return print.ChromePrintOptions{}, err
}
marginTop, marginBottom, marginLeft, marginRight,
err := resource.MarginArgs(r, config)
if err != nil {
return printer.ChromePrinterOptions{}, err
return print.ChromePrintOptions{}, err
}
landscape, err := r.BoolArg(resource.LandscapeArgKey, false)
if err != nil {
return printer.ChromePrinterOptions{}, err
return print.ChromePrintOptions{}, err
}
return printer.ChromePrinterOptions{
WaitTimeout: waitTimeout,
return print.ChromePrintOptions{
WaitDelay: waitDelay,
HeaderHTML: headerHTML,
FooterHTML: footerHTML,
@@ -69,20 +53,15 @@ func chromePrinterOptions(r resource.Resource, config conf.Config) (printer.Chro
return opts, nil
}
func officePrinterOptions(r resource.Resource, config conf.Config) (printer.OfficePrinterOptions, error) {
const op string = "xhttp.officePrinterOptions"
resolver := func() (printer.OfficePrinterOptions, error) {
waitTimeout, err := resource.WaitTimeoutArg(r, config)
if err != nil {
return printer.OfficePrinterOptions{}, err
}
func officePrintOptions(r resource.Resource, config conf.Config) (print.OfficePrintOptions, error) {
const op string = "xhttp.officePrintOptions"
resolver := func() (print.OfficePrintOptions, error) {
landscape, err := r.BoolArg(resource.LandscapeArgKey, false)
if err != nil {
return printer.OfficePrinterOptions{}, err
return print.OfficePrintOptions{}, err
}
return printer.OfficePrinterOptions{
WaitTimeout: waitTimeout,
Landscape: landscape,
return print.OfficePrintOptions{
Landscape: landscape,
}, nil
}
opts, err := resolver()

View File

@@ -13,7 +13,8 @@ import (
"github.com/thecodingmachine/gotenberg/internal/app/xhttp/pkg/resource"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/normalize"
"github.com/thecodingmachine/gotenberg/internal/pkg/pm2"
"github.com/thecodingmachine/gotenberg/internal/pkg/prinery"
"github.com/thecodingmachine/gotenberg/internal/pkg/process"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
)
@@ -21,20 +22,31 @@ import (
// Context extends the default echo.Context.
type Context struct {
echo.Context
logger xlog.Logger
config conf.Config
processes []pm2.Process
resource resource.Resource
startTime time.Time
logger xlog.Logger
config conf.Config
manager process.Manager
chromePrinery *prinery.Prinery
sofficePrinery *prinery.Prinery
resource resource.Resource
startTime time.Time
}
// New creates a new Context.
func New(c echo.Context, logger xlog.Logger, config conf.Config, processes ...pm2.Process) Context {
func New(
c echo.Context,
logger xlog.Logger,
config conf.Config,
manager process.Manager,
chromePrinery *prinery.Prinery,
sofficePrinery *prinery.Prinery,
) Context {
return Context{
c,
logger,
config,
processes,
manager,
chromePrinery,
sofficePrinery,
resource.Resource{},
time.Now(),
}
@@ -77,17 +89,52 @@ func (ctx Context) Config() conf.Config {
// one of the processes is not viable.
func (ctx Context) ProcessesHealthcheck() error {
const op string = "context.Context.ProcessesHealthcheck"
for _, process := range ctx.processes {
if !process.IsViable() {
processes := ctx.manager.All()
for _, p := range processes {
if !ctx.manager.IsViable(p) {
return xerror.New(
op,
fmt.Errorf("'%s' is not viable", process.Fullname()),
fmt.Errorf("'%s' is not viable", p.ID()),
)
}
}
return nil
}
/*
MustChromePrinery returns the instance of
prinery.Prinery associated with the Context.
This prinery.Prinery handles Google Chrome
headless.
It panics if no instance of prinery.Prinery.
*/
func (ctx Context) MustChromePrinery() *prinery.Prinery {
const op string = "context.Context.MustChromePrinery"
if ctx.chromePrinery == nil {
panic(fmt.Sprintf("%s: unable to retrieve the instance of Google Chrome Headless prinery.Prinery from our custom context.Context", op))
}
return ctx.chromePrinery
}
/*
MustSofficePrinery returns the instance of
prinery.Prinery associated with the Context.
This prinery.Prinery handles LibreOffice
headless.
It panics if no instance of prinery.Prinery.
*/
func (ctx Context) MustSofficePrinery() *prinery.Prinery {
const op string = "context.Context.MustSofficePrinery"
if ctx.sofficePrinery == nil {
panic(fmt.Sprintf("%s: unable to retrieve the instance of LibreOffice Headless prinery.Prinery from our custom context.Context", op))
}
return ctx.sofficePrinery
}
// WithResource creates a resource.Resource and
// adds it to the Context.
func (ctx *Context) WithResource(directoryName string) error {

View File

@@ -76,6 +76,34 @@ func ArgKeys() []ArgKey {
}
}
/*
WaitTimeoutAndWaitDelayArg is a helper for retrieving
the sum of "waitTimeout" and "waitDelay" arguments
as float64.
It also validates them against the application
configuration.
*/
func WaitTimeoutAndWaitDelayArg(r Resource, config conf.Config) (float64, error) {
const op string = "resource.WaitTimeoutAndWaitDelayArg"
resolver := func() (float64, error) {
waitTimeout, err := WaitTimeoutArg(r, config)
if err != nil {
return waitTimeout, err
}
waitDelay, err := WaitDelayArg(r, config)
if err != nil {
return waitDelay, err
}
return waitTimeout + waitDelay, nil
}
combined, err := resolver()
if err != nil {
return combined, xerror.New(op, err)
}
return combined, nil
}
/*
WaitTimeoutArg is a helper for retrieving
the "waitTimeout" argument as float64.

View File

@@ -3,15 +3,21 @@ package xhttp
import (
"github.com/labstack/echo/v4"
"github.com/thecodingmachine/gotenberg/internal/pkg/conf"
"github.com/thecodingmachine/gotenberg/internal/pkg/pm2"
"github.com/thecodingmachine/gotenberg/internal/pkg/prinery"
"github.com/thecodingmachine/gotenberg/internal/pkg/process"
)
// New returns a custom echo.Echo.
func New(config conf.Config, processes ...pm2.Process) *echo.Echo {
func New(
config conf.Config,
manager process.Manager,
chromePrinery *prinery.Prinery,
sofficePrinery *prinery.Prinery,
) *echo.Echo {
srv := echo.New()
srv.HideBanner = true
srv.HidePort = true
srv.Use(contextMiddleware(config, processes...))
srv.Use(contextMiddleware(config, manager, chromePrinery, sofficePrinery))
srv.Use(loggerMiddleware())
srv.Use(cleanupMiddleware())
srv.Use(errorMiddleware())

View File

@@ -17,7 +17,8 @@ func TestDisableChromeEndpoints(t *testing.T) {
os.Setenv(conf.DisableGoogleChromeEnvVar, "1")
config, err := conf.FromEnv()
assert.Nil(t, err)
srv := New(config)
// TODO
srv := New(config, nil, nil)
// Ping endpoint should return 200.
req := httptest.NewRequest(http.MethodGet, pingEndpoint, nil)
test.AssertStatusCode(t, http.StatusOK, srv, req)
@@ -54,7 +55,8 @@ func TestDisableUnoconvEndpoints(t *testing.T) {
os.Setenv(conf.DisableUnoconvEnvVar, "1")
config, err := conf.FromEnv()
assert.Nil(t, err)
srv := New(config)
// TODO
srv := New(config, nil, nil)
// Ping endpoint should return 200.
req := httptest.NewRequest(http.MethodGet, pingEndpoint, nil)
test.AssertStatusCode(t, http.StatusOK, srv, req)
@@ -91,7 +93,8 @@ func TestDisableChromeAndUnoconvEndpoints(t *testing.T) {
os.Setenv(conf.DisableUnoconvEnvVar, "1")
config, err := conf.FromEnv()
assert.Nil(t, err)
srv := New(config)
// TODO
srv := New(config, nil, nil)
// Ping endpoint should return 200.
req := httptest.NewRequest(http.MethodGet, pingEndpoint, nil)
test.AssertStatusCode(t, http.StatusOK, srv, req)