Compare commits

...

8 Commits

Author SHA1 Message Date
Julien Neuhart
8260458f8f Revert "fix(chromium): regex only accepts tmp folder by default (#429)"
This reverts commit 27018fa8e2.
2022-03-22 10:48:01 +01:00
Julien Neuhart
0512dd1e86 fix(tests): add -buildvcs=false as a temporary fix for go 1.18 bug (see https://github.com/golang/go/issues/51723) 2022-03-21 17:13:35 +01:00
Julien Neuhart
4972019cb9 chore: update golang-ci-lint 2022-03-21 16:46:46 +01:00
Julien Neuhart
5e615cab52 chore: upgrade go to 1.18 and update Go dependencies 2022-03-21 16:46:15 +01:00
Julien Neuhart
64ea2b6d3b fix(libreoffice): start the long-running listener on the first conversion (fixes #420) 2022-03-21 16:39:52 +01:00
Gabor Szabad
27018fa8e2 fix(chromium): regex only accepts tmp folder by default (#429) 2022-02-25 13:52:27 +01:00
Julien Neuhart
263d634801 chore: rename MockContext to ContextMock and move it to a dedicated go file 2022-02-09 16:09:48 +01:00
Julien Neuhart
c61c33f71c chore: update LICENSE 2022-02-09 10:41:50 +01:00
18 changed files with 514 additions and 465 deletions

View File

@@ -19,7 +19,7 @@ jobs:
- name: Run linters - name: Run linters
uses: golangci/golangci-lint-action@v2 uses: golangci/golangci-lint-action@v2
with: with:
version: v1.44 version: v1.45
tests: tests:
needs: needs:

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2021 Julien Neuhart Copyright (c) 2022 Julien Neuhart
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -5,14 +5,14 @@ help: ## Show the help
.PHONY: it .PHONY: it
it: build build-tests ## Initialize the development environment it: build build-tests ## Initialize the development environment
GOLANG_VERSION=1.17 GOLANG_VERSION=1.18
DOCKER_REPOSITORY=gotenberg DOCKER_REPOSITORY=gotenberg
GOTENBERG_VERSION=snapshot GOTENBERG_VERSION=snapshot
GOTENBERG_USER_GID=1001 GOTENBERG_USER_GID=1001
GOTENBERG_USER_UID=1001 GOTENBERG_USER_UID=1001
NOTO_COLOR_EMOJI_VERSION=v2.034 # See https://github.com/googlefonts/noto-emoji/releases. NOTO_COLOR_EMOJI_VERSION=v2.034 # See https://github.com/googlefonts/noto-emoji/releases.
PDFTK_VERSION=v3.3.2 # See https://gitlab.com/pdftk-java/pdftk/-/releases - Binary package. PDFTK_VERSION=v3.3.2 # See https://gitlab.com/pdftk-java/pdftk/-/releases - Binary package.
GOLANGCI_LINT_VERSION=v1.44.0 # See https://github.com/golangci/golangci-lint/releases. GOLANGCI_LINT_VERSION=v1.45.0 # See https://github.com/golangci/golangci-lint/releases.
.PHONY: build .PHONY: build
build: ## Build the Gotenberg's Docker image build: ## Build the Gotenberg's Docker image

24
go.mod
View File

@@ -1,38 +1,38 @@
module github.com/gotenberg/gotenberg/v7 module github.com/gotenberg/gotenberg/v7
go 1.17 go 1.18
require ( require (
github.com/alexliesenfeld/health v0.6.0 github.com/alexliesenfeld/health v0.6.0
github.com/andybalholm/brotli v1.0.4 // indirect github.com/andybalholm/brotli v1.0.4 // indirect
github.com/chromedp/cdproto v0.0.0-20220204211718-0109d952cae2 github.com/chromedp/cdproto v0.0.0-20220321060548-7bc2623472b3
github.com/chromedp/chromedp v0.7.7 github.com/chromedp/chromedp v0.8.0
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 github.com/hashicorp/go-retryablehttp v0.7.0
github.com/klauspost/compress v1.14.2 // indirect github.com/klauspost/compress v1.15.1 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect github.com/klauspost/pgzip v1.2.5 // indirect
github.com/labstack/echo/v4 v4.6.3 github.com/labstack/echo/v4 v4.7.2
github.com/labstack/gommon v0.3.1 github.com/labstack/gommon v0.3.1
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mholt/archiver/v3 v3.5.1 github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.18 github.com/microcosm-cc/bluemonday v1.0.18
github.com/nwaples/rardecode v1.1.2 // indirect github.com/nwaples/rardecode v1.1.3 // indirect
github.com/pdfcpu/pdfcpu v0.3.12 github.com/pdfcpu/pdfcpu v0.3.13
github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/prometheus/client_golang v1.12.1 github.com/prometheus/client_golang v1.12.1
github.com/russross/blackfriday/v2 v2.1.0 github.com/russross/blackfriday/v2 v2.1.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/ulikunitz/xz v0.5.10 // indirect github.com/ulikunitz/xz v0.5.10 // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 go.uber.org/multierr v1.8.0
go.uber.org/zap v1.21.0 go.uber.org/zap v1.21.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect golang.org/x/image v0.0.0-20220321031419-a8550c1d254a // indirect
golang.org/x/net v0.0.0-20210913180222-943fd674d43e golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/text v0.3.7 golang.org/x/text v0.3.7
) )

51
go.sum
View File

@@ -55,11 +55,10 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chromedp/cdproto v0.0.0-20220131204822-e6abebe7b8cd/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/cdproto v0.0.0-20220321060548-7bc2623472b3 h1:ilF7R875ORf246k6nU2/6fRIbtAFYjPOOtwZJTQvusM=
github.com/chromedp/cdproto v0.0.0-20220204211718-0109d952cae2 h1:vr9QO2FB/MkXEv8BUja99AUwbJ32TuA+l64bAEmLqQI= github.com/chromedp/cdproto v0.0.0-20220321060548-7bc2623472b3/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
github.com/chromedp/cdproto v0.0.0-20220204211718-0109d952cae2/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/chromedp v0.8.0 h1:+Cufl+QWWfbvyylGCtAUt34A2EI/kqxRM3wGHXMabU4=
github.com/chromedp/chromedp v0.7.7 h1:kRN7G7v4cGpTV2Nth218YR2VOsbpHBN3qClYCb6CBnI= github.com/chromedp/chromedp v0.8.0/go.mod h1:odCVV9o9i7HUKwHMFz9Y7T6s4Kbcz4GOyPlwKWopI9Q=
github.com/chromedp/chromedp v0.7.7/go.mod h1:cqexhZWjEbF8/cETF57b5dQ3rqrY6q71HcfYQ5oAy3k=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -94,7 +93,6 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -184,8 +182,8 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw= github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
@@ -197,8 +195,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labstack/echo/v4 v4.6.3 h1:VhPuIZYxsbPmo4m9KAkMU/el2442eB7EBFFhNTTT9ac= github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
github.com/labstack/echo/v4 v4.6.3/go.mod h1:Hk5OiHj0kDqmFq7aHe7eDqI7CUhuCrfpupQtLGGLm7A= github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@@ -222,12 +220,11 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/nwaples/rardecode v1.1.2 h1:Cj0yZY6T1Zx1R7AhTbyGSALm44/Mmq+BAPc4B/p/d3M= github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
github.com/nwaples/rardecode v1.1.2/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc= github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pdfcpu/pdfcpu v0.3.13 h1:VFon2Yo1PJt+sA57vPAeXWGLSZ7Ux3Jl4h02M0+s3dg=
github.com/pdfcpu/pdfcpu v0.3.12 h1:B+MdKisilWNSk5OCO58Z9U6H93usH73xqk6hMOaZCls= github.com/pdfcpu/pdfcpu v0.3.13/go.mod h1:UJc5xsXg0fpmjp1zOPdyYcAQArc/Zf3V0nv5URe+9fg=
github.com/pdfcpu/pdfcpu v0.3.12/go.mod h1:8XVBtVxuuIuSZL4Ez15Q4QoC+H8zeAaGnuiOEwAk8jA=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
@@ -300,8 +297,8 @@ go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -310,8 +307,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -325,9 +322,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20190823064033-3a9bac650e44/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190823064033-3a9bac650e44/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20220321031419-a8550c1d254a h1:LnH9RNcpPv5Kzi15lXg42lYMPUf0x8CuPv1YnvBWZAg=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= golang.org/x/image v0.0.0-20220321031419-a8550c1d254a/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -375,12 +371,11 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210913180222-943fd674d43e h1:+b/22bPvDYt4NPDcy4xAGCmON713ONAWFeY3Z7I3tR8= golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -436,13 +431,12 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -457,7 +451,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=

View File

@@ -276,73 +276,3 @@ func (ctx Context) OutputFilename(outputPath string) string {
return fmt.Sprintf("%s%s", filename, filepath.Ext(outputPath)) return fmt.Sprintf("%s%s", filename, filepath.Ext(outputPath))
} }
// TODO: move MockContext to mocks.go (and rename it ContextMock).
// MockContext is a helper for tests.
//
// ctx := &api.MockContext{Context: &api.Context{}}
type MockContext struct {
*Context
}
// SetDirPath sets the context's working directory path.
//
// ctx := &api.MockContext{Context: &api.Context{}}
// ctx.SetDirPath("/foo")
func (ctx *MockContext) SetDirPath(path string) {
ctx.dirPath = path
}
// SetValues sets the values.
//
// ctx := &api.MockContext{Context: &api.Context{}}
// ctx.SetValues(map[string][]string{
// "url": {
// "foo",
// },
// })
func (ctx *MockContext) SetValues(values map[string][]string) {
ctx.values = values
}
// SetFiles sets the files.
//
// ctx := &api.MockContext{Context: &api.Context{}}
// ctx.SetFiles(map[string]string{
// "foo": "/foo",
// })
func (ctx *MockContext) SetFiles(files map[string]string) {
ctx.files = files
}
// SetCancelled sets if the context is cancelled or not.
//
// ctx := &api.MockContext{Context: &api.Context{}}
// ctx.SetCancelled(true)
func (ctx *MockContext) SetCancelled(cancelled bool) {
ctx.cancelled = cancelled
}
// OutputPaths returns the registered output paths.
// ctx := &api.MockContext{Context: &api.Context{}}
// outputPaths := ctx.OutputPaths()
func (ctx MockContext) OutputPaths() []string {
return ctx.outputPaths
}
// SetLogger sets the logger.
//
// ctx := &api.MockContext{Context: &api.Context{}}
// ctx.SetLogger(zap.NewNop())
func (ctx *MockContext) SetLogger(logger *zap.Logger) {
ctx.logger = logger
}
// SetEchoContext sets the echo.Context.
//
// ctx := &api.MockContext{Context: &api.Context{}}
// ctx.setEchoContext(c)
func (ctx *MockContext) SetEchoContext(c echo.Context) {
ctx.Context.echoCtx = c
}

View File

@@ -334,99 +334,3 @@ func TestContext_OutputFilename(t *testing.T) {
} }
} }
} }
func TestMockContext_SetDirPath(t *testing.T) {
mock := &MockContext{&Context{}}
mock.SetDirPath("/foo")
actual := mock.dirPath
expect := "/foo"
if actual != expect {
t.Errorf("expected '%s' but got '%s'", expect, actual)
}
}
func TestMockContext_SetValues(t *testing.T) {
mock := &MockContext{&Context{}}
mock.SetValues(map[string][]string{
"foo": {"foo"},
})
actual := mock.values
expect := map[string][]string{
"foo": {"foo"},
}
if !reflect.DeepEqual(actual, expect) {
t.Errorf("expected %+v but got: %+v", expect, actual)
}
}
func TestMockContext_SetFiles(t *testing.T) {
mock := &MockContext{&Context{}}
mock.SetFiles(map[string]string{
"foo": "/foo",
})
actual := mock.files
expect := map[string]string{
"foo": "/foo",
}
if !reflect.DeepEqual(actual, expect) {
t.Errorf("expected %+v but got: %+v", expect, actual)
}
}
func TestMockContext_SetCancelled(t *testing.T) {
mock := &MockContext{&Context{}}
mock.SetCancelled(true)
actual := mock.cancelled
if !actual {
t.Errorf("expected %t but got %t", true, actual)
}
}
func TestMockContext_OutputPaths(t *testing.T) {
mock := MockContext{
&Context{
outputPaths: []string{"/foo"},
},
}
actual := mock.OutputPaths()
expect := []string{"/foo"}
if !reflect.DeepEqual(actual, expect) {
t.Errorf("expected %+v but got: %+v", expect, actual)
}
}
func TestMockContext_SetLogger(t *testing.T) {
mock := MockContext{&Context{}}
expect := zap.NewNop()
mock.SetLogger(expect)
actual := mock.logger
if actual != expect {
t.Errorf("expected %v but got %v", expect, actual)
}
}
func TestMockContext_SetEchoContext(t *testing.T) {
mock := MockContext{&Context{}}
expect := echo.New().NewContext(nil, nil)
mock.SetEchoContext(expect)
actual := mock.echoCtx
if actual != expect {
t.Errorf("expected %v but got %v", expect, actual)
}
}

74
pkg/modules/api/mocks.go Normal file
View File

@@ -0,0 +1,74 @@
package api
import (
"github.com/labstack/echo/v4"
"go.uber.org/zap"
)
// ContextMock is a helper for tests.
//
// ctx := &api.ContextMock{Context: &api.Context{}}
type ContextMock struct {
*Context
}
// SetDirPath sets the context's working directory path.
//
// ctx := &api.ContextMock{Context: &api.Context{}}
// ctx.SetDirPath("/foo")
func (ctx *ContextMock) SetDirPath(path string) {
ctx.dirPath = path
}
// SetValues sets the values.
//
// ctx := &api.ContextMock{Context: &api.Context{}}
// ctx.SetValues(map[string][]string{
// "url": {
// "foo",
// },
// })
func (ctx *ContextMock) SetValues(values map[string][]string) {
ctx.values = values
}
// SetFiles sets the files.
//
// ctx := &api.ContextMock{Context: &api.Context{}}
// ctx.SetFiles(map[string]string{
// "foo": "/foo",
// })
func (ctx *ContextMock) SetFiles(files map[string]string) {
ctx.files = files
}
// SetCancelled sets if the context is cancelled or not.
//
// ctx := &api.ContextMock{Context: &api.Context{}}
// ctx.SetCancelled(true)
func (ctx *ContextMock) SetCancelled(cancelled bool) {
ctx.cancelled = cancelled
}
// OutputPaths returns the registered output paths.
// ctx := &api.ContextMock{Context: &api.Context{}}
// outputPaths := ctx.OutputPaths()
func (ctx ContextMock) OutputPaths() []string {
return ctx.outputPaths
}
// SetLogger sets the logger.
//
// ctx := &api.ContextMock{Context: &api.Context{}}
// ctx.SetLogger(zap.NewNop())
func (ctx *ContextMock) SetLogger(logger *zap.Logger) {
ctx.logger = logger
}
// SetEchoContext sets the echo.Context.
//
// ctx := &api.ContextMock{Context: &api.Context{}}
// ctx.setEchoContext(c)
func (ctx *ContextMock) SetEchoContext(c echo.Context) {
ctx.Context.echoCtx = c
}

View File

@@ -0,0 +1,105 @@
package api
import (
"reflect"
"testing"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
)
func TestContextMock_SetDirPath(t *testing.T) {
mock := &ContextMock{&Context{}}
mock.SetDirPath("/foo")
actual := mock.dirPath
expect := "/foo"
if actual != expect {
t.Errorf("expected '%s' but got '%s'", expect, actual)
}
}
func TestContextMock_SetValues(t *testing.T) {
mock := &ContextMock{&Context{}}
mock.SetValues(map[string][]string{
"foo": {"foo"},
})
actual := mock.values
expect := map[string][]string{
"foo": {"foo"},
}
if !reflect.DeepEqual(actual, expect) {
t.Errorf("expected %+v but got: %+v", expect, actual)
}
}
func TestContextMock_SetFiles(t *testing.T) {
mock := &ContextMock{&Context{}}
mock.SetFiles(map[string]string{
"foo": "/foo",
})
actual := mock.files
expect := map[string]string{
"foo": "/foo",
}
if !reflect.DeepEqual(actual, expect) {
t.Errorf("expected %+v but got: %+v", expect, actual)
}
}
func TestContextMock_SetCancelled(t *testing.T) {
mock := &ContextMock{&Context{}}
mock.SetCancelled(true)
actual := mock.cancelled
if !actual {
t.Errorf("expected %t but got %t", true, actual)
}
}
func TestContextMock_OutputPaths(t *testing.T) {
mock := ContextMock{
&Context{
outputPaths: []string{"/foo"},
},
}
actual := mock.OutputPaths()
expect := []string{"/foo"}
if !reflect.DeepEqual(actual, expect) {
t.Errorf("expected %+v but got: %+v", expect, actual)
}
}
func TestContextMock_SetLogger(t *testing.T) {
mock := ContextMock{&Context{}}
expect := zap.NewNop()
mock.SetLogger(expect)
actual := mock.logger
if actual != expect {
t.Errorf("expected %v but got %v", expect, actual)
}
}
func TestContextMock_SetEchoContext(t *testing.T) {
mock := ContextMock{&Context{}}
expect := echo.New().NewContext(nil, nil)
mock.SetEchoContext(expect)
actual := mock.echoCtx
if actual != expect {
t.Errorf("expected %v but got %v", expect, actual)
}
}

View File

@@ -16,16 +16,16 @@ import (
func TestFormDataChromiumPDFOptions(t *testing.T) { func TestFormDataChromiumPDFOptions(t *testing.T) {
for i, tc := range []struct { for i, tc := range []struct {
ctx *api.MockContext ctx *api.ContextMock
options Options options Options
}{ }{
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
options: DefaultOptions(), options: DefaultOptions(),
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"extraHttpHeaders": { "extraHttpHeaders": {
"foo", "foo",
@@ -37,8 +37,8 @@ func TestFormDataChromiumPDFOptions(t *testing.T) {
options: DefaultOptions(), options: DefaultOptions(),
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"extraHttpHeaders": { "extraHttpHeaders": {
`{"foo":"bar"}`, `{"foo":"bar"}`,
@@ -57,8 +57,8 @@ func TestFormDataChromiumPDFOptions(t *testing.T) {
}(), }(),
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"extraHttpHeaders": { "extraHttpHeaders": {
"foo", "foo",
@@ -70,8 +70,8 @@ func TestFormDataChromiumPDFOptions(t *testing.T) {
options: DefaultOptions(), options: DefaultOptions(),
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"emulatedMediaType": { "emulatedMediaType": {
"foo", "foo",
@@ -83,8 +83,8 @@ func TestFormDataChromiumPDFOptions(t *testing.T) {
options: DefaultOptions(), options: DefaultOptions(),
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"emulatedMediaType": { "emulatedMediaType": {
"screen", "screen",
@@ -111,7 +111,7 @@ func TestFormDataChromiumPDFOptions(t *testing.T) {
func TestConvertURLHandler(t *testing.T) { func TestConvertURLHandler(t *testing.T) {
for i, tc := range []struct { for i, tc := range []struct {
ctx *api.MockContext ctx *api.ContextMock
api API api API
expectErr bool expectErr bool
expectHTTPErr bool expectHTTPErr bool
@@ -119,14 +119,14 @@ func TestConvertURLHandler(t *testing.T) {
expectOutputPathsCount int expectOutputPathsCount int
}{ }{
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
expectErr: true, expectErr: true,
expectHTTPErr: true, expectHTTPErr: true,
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"url": { "url": {
"", "",
@@ -140,8 +140,8 @@ func TestConvertURLHandler(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"url": { "url": {
"foo", "foo",
@@ -161,8 +161,8 @@ func TestConvertURLHandler(t *testing.T) {
expectErr: true, expectErr: true,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"url": { "url": {
"foo", "foo",
@@ -182,8 +182,8 @@ func TestConvertURLHandler(t *testing.T) {
expectOutputPathsCount: 1, expectOutputPathsCount: 1,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"url": { "url": {
"foo", "foo",
@@ -208,8 +208,8 @@ func TestConvertURLHandler(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"url": { "url": {
"foo", "foo",
@@ -234,8 +234,8 @@ func TestConvertURLHandler(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"url": { "url": {
"foo", "foo",
@@ -300,7 +300,7 @@ func TestConvertURLHandler(t *testing.T) {
func TestConvertHTMLHandler(t *testing.T) { func TestConvertHTMLHandler(t *testing.T) {
for i, tc := range []struct { for i, tc := range []struct {
ctx *api.MockContext ctx *api.ContextMock
api API api API
expectErr bool expectErr bool
expectHTTPErr bool expectHTTPErr bool
@@ -308,14 +308,14 @@ func TestConvertHTMLHandler(t *testing.T) {
expectOutputPathsCount int expectOutputPathsCount int
}{ }{
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
expectErr: true, expectErr: true,
expectHTTPErr: true, expectHTTPErr: true,
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.html": "/foo/foo.html", "foo.html": "/foo/foo.html",
}) })
@@ -327,8 +327,8 @@ func TestConvertHTMLHandler(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"index.html": "/foo/foo.html", "index.html": "/foo/foo.html",
}) })
@@ -346,8 +346,8 @@ func TestConvertHTMLHandler(t *testing.T) {
expectErr: true, expectErr: true,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"index.html": "/foo/foo.html", "index.html": "/foo/foo.html",
}) })
@@ -404,7 +404,7 @@ func TestConvertHTMLHandler(t *testing.T) {
func TestConvertMarkdownHandler(t *testing.T) { func TestConvertMarkdownHandler(t *testing.T) {
for i, tc := range []struct { for i, tc := range []struct {
ctx *api.MockContext ctx *api.ContextMock
api API api API
outputDir string outputDir string
expectErr bool expectErr bool
@@ -413,14 +413,14 @@ func TestConvertMarkdownHandler(t *testing.T) {
expectOutputPathsCount int expectOutputPathsCount int
}{ }{
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
expectErr: true, expectErr: true,
expectHTTPErr: true, expectHTTPErr: true,
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.html": "/foo/foo.html", "foo.html": "/foo/foo.html",
}) })
@@ -432,8 +432,8 @@ func TestConvertMarkdownHandler(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"index.html": "/foo/foo.html", "index.html": "/foo/foo.html",
}) })
@@ -445,8 +445,8 @@ func TestConvertMarkdownHandler(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"index.html": "/foo/foo.html", "index.html": "/foo/foo.html",
"markdown.md": "/foo/markdown.md", "markdown.md": "/foo/markdown.md",
@@ -457,8 +457,8 @@ func TestConvertMarkdownHandler(t *testing.T) {
expectErr: true, expectErr: true,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"index.html": "/tests/test/testdata/chromium/markdown/sample2/index.html", "index.html": "/tests/test/testdata/chromium/markdown/sample2/index.html",
"markdown1.md": "/foo/markdown1.md", "markdown1.md": "/foo/markdown1.md",
@@ -471,8 +471,8 @@ func TestConvertMarkdownHandler(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"index.html": "/tests/test/testdata/chromium/markdown/sample1/index.html", "index.html": "/tests/test/testdata/chromium/markdown/sample1/index.html",
"markdown1.md": "/foo/markdown1.md", "markdown1.md": "/foo/markdown1.md",
@@ -491,8 +491,8 @@ func TestConvertMarkdownHandler(t *testing.T) {
expectErr: true, expectErr: true,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"index.html": "/tests/test/testdata/chromium/markdown/sample1/index.html", "index.html": "/tests/test/testdata/chromium/markdown/sample1/index.html",
"markdown1.md": "/tests/test/testdata/chromium/markdown/sample1/markdown1.md", "markdown1.md": "/tests/test/testdata/chromium/markdown/sample1/markdown1.md",
@@ -513,8 +513,8 @@ func TestConvertMarkdownHandler(t *testing.T) {
expectErr: true, expectErr: true,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetDirPath("/tmp/foo") ctx.SetDirPath("/tmp/foo")
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
@@ -538,8 +538,8 @@ func TestConvertMarkdownHandler(t *testing.T) {
expectErr: true, expectErr: true,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetDirPath("/tmp/foo") ctx.SetDirPath("/tmp/foo")
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
@@ -563,8 +563,8 @@ func TestConvertMarkdownHandler(t *testing.T) {
expectOutputPathsCount: 1, expectOutputPathsCount: 1,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetDirPath("/tmp/foo") ctx.SetDirPath("/tmp/foo")
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
@@ -642,7 +642,7 @@ func TestConvertMarkdownHandler(t *testing.T) {
func TestConvertURL(t *testing.T) { func TestConvertURL(t *testing.T) {
for i, tc := range []struct { for i, tc := range []struct {
ctx *api.MockContext ctx *api.ContextMock
api API api API
engine gotenberg.PDFEngine engine gotenberg.PDFEngine
PDFformat string PDFformat string
@@ -653,7 +653,7 @@ func TestConvertURL(t *testing.T) {
expectOutputPathsCount int expectOutputPathsCount int
}{ }{
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
@@ -668,7 +668,7 @@ func TestConvertURL(t *testing.T) {
expectHTTPStatus: http.StatusForbidden, expectHTTPStatus: http.StatusForbidden,
}, },
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
@@ -681,7 +681,7 @@ func TestConvertURL(t *testing.T) {
expectErr: true, expectErr: true,
}, },
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
@@ -701,7 +701,7 @@ func TestConvertURL(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
@@ -716,7 +716,7 @@ func TestConvertURL(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
@@ -731,7 +731,7 @@ func TestConvertURL(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
@@ -746,7 +746,7 @@ func TestConvertURL(t *testing.T) {
expectHTTPStatus: http.StatusConflict, expectHTTPStatus: http.StatusConflict,
}, },
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
@@ -759,7 +759,7 @@ func TestConvertURL(t *testing.T) {
expectErr: true, expectErr: true,
}, },
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
@@ -782,7 +782,7 @@ func TestConvertURL(t *testing.T) {
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
@@ -803,7 +803,7 @@ func TestConvertURL(t *testing.T) {
expectErr: true, expectErr: true,
}, },
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
@@ -824,8 +824,8 @@ func TestConvertURL(t *testing.T) {
expectOutputPathsCount: 1, expectOutputPathsCount: 1,
}, },
{ {
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetCancelled(true) ctx.SetCancelled(true)
return ctx return ctx
@@ -842,7 +842,7 @@ func TestConvertURL(t *testing.T) {
expectErr: true, expectErr: true,
}, },
{ {
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {
chromiumAPI := struct{ ProtoAPI }{} chromiumAPI := struct{ ProtoAPI }{}
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {

View File

@@ -16,7 +16,7 @@ import (
func TestConvertHandler(t *testing.T) { func TestConvertHandler(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
ctx *api.MockContext ctx *api.ContextMock
unoAPI uno.API unoAPI uno.API
engine gotenberg.PDFEngine engine gotenberg.PDFEngine
expectErr bool expectErr bool
@@ -26,8 +26,8 @@ func TestConvertHandler(t *testing.T) {
}{ }{
{ {
name: "nominal behavior", name: "nominal behavior",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })
@@ -48,8 +48,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "nominal behavior, but with 3 documents", name: "nominal behavior, but with 3 documents",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
"bar.docx": "/bar/bar.docx", "bar.docx": "/bar/bar.docx",
@@ -72,8 +72,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "cannot add output paths", name: "cannot add output paths",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })
@@ -95,7 +95,7 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "invalid form data: no documents", name: "invalid form data: no documents",
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
unoAPI: uno.APIMock{ unoAPI: uno.APIMock{
ExtensionsMock: func() []string { ExtensionsMock: func() []string {
return []string{ return []string{
@@ -109,8 +109,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "invalid form data: both nativePdfA1aFormat and nativePdfFormat are set", name: "invalid form data: both nativePdfA1aFormat and nativePdfFormat are set",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })
@@ -139,8 +139,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "invalid form data: both nativePdfA1aFormat and pdfFormat are set", name: "invalid form data: both nativePdfA1aFormat and pdfFormat are set",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })
@@ -169,8 +169,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "invalid form data: both nativePdfFormat and pdfFormat are set", name: "invalid form data: both nativePdfFormat and pdfFormat are set",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })
@@ -198,8 +198,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "convert to PDF fail", name: "convert to PDF fail",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })
@@ -220,8 +220,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "invalid page ranges", name: "invalid page ranges",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })
@@ -244,8 +244,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "convert 3 documents and merge them", name: "convert 3 documents and merge them",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
"bar.docx": "/bar/bar.docx", "bar.docx": "/bar/bar.docx",
@@ -278,8 +278,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "merge fail", name: "merge fail",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
"bar.docx": "/bar/bar.docx", "bar.docx": "/bar/bar.docx",
@@ -312,8 +312,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "convert 3 documents, merge them, and convert them to a PDF format", name: "convert 3 documents, merge them, and convert them to a PDF format",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
"bar.docx": "/bar/bar.docx", "bar.docx": "/bar/bar.docx",
@@ -352,8 +352,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "convert 3 documents, merge them, but convert them to PDF format fail", name: "convert 3 documents, merge them, but convert them to PDF format fail",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
"bar.docx": "/bar/bar.docx", "bar.docx": "/bar/bar.docx",
@@ -392,8 +392,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "convert 3 documents, merge them, but PDF format not available", name: "convert 3 documents, merge them, but PDF format not available",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
"bar.docx": "/bar/bar.docx", "bar.docx": "/bar/bar.docx",
@@ -434,8 +434,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "convert 3 documents and merge them, but cannot add output paths", name: "convert 3 documents and merge them, but cannot add output paths",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
"bar.docx": "/bar/bar.docx", "bar.docx": "/bar/bar.docx",
@@ -469,8 +469,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "convert to PDF format", name: "convert to PDF format",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })
@@ -501,8 +501,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "convert to PDF format using nativePdfA1aFormat", name: "convert to PDF format using nativePdfA1aFormat",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })
@@ -534,8 +534,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "convert to PDF format fail", name: "convert to PDF format fail",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })
@@ -566,8 +566,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "PDF format not available", name: "PDF format not available",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.docx": "/foo/foo.docx", "foo.docx": "/foo/foo.docx",
}) })

View File

@@ -23,6 +23,7 @@ type listener interface {
healthy() bool healthy() bool
} }
// TODO: this implementation, even if it's working, is way too complex.
type libreOfficeListener struct { type libreOfficeListener struct {
binPath string binPath string
startTimeout time.Duration startTimeout time.Duration
@@ -33,13 +34,15 @@ type libreOfficeListener struct {
cmd gotenberg.Cmd cmd gotenberg.Cmd
cfgMu sync.RWMutex cfgMu sync.RWMutex
usage int usage int
restarting bool hadFirstStart bool
restartingMu sync.RWMutex hadFirstStartMu sync.RWMutex
queueLength int restarting bool
queueLengthMu sync.RWMutex restartingMu sync.RWMutex
lockChan chan struct{} queueLength int
logger *zap.Logger queueLengthMu sync.RWMutex
lockChan chan struct{}
logger *zap.Logger
} }
func newLibreOfficeListener(logger *zap.Logger, binPath string, startTimeout time.Duration, threshold int) listener { func newLibreOfficeListener(logger *zap.Logger, binPath string, startTimeout time.Duration, threshold int) listener {
@@ -53,14 +56,17 @@ func newLibreOfficeListener(logger *zap.Logger, binPath string, startTimeout tim
} }
func (listener *libreOfficeListener) start(logger *zap.Logger) error { func (listener *libreOfficeListener) start(logger *zap.Logger) error {
listener.hadFirstStartMu.Lock()
listener.hadFirstStart = true
listener.hadFirstStartMu.Unlock()
port, err := freePort(logger) port, err := freePort(logger)
if err != nil { if err != nil {
return fmt.Errorf("get free port: %w", err) return fmt.Errorf("get free port: %w", err)
} }
// Good to know: when the supervisor manages the LibreOffice listener, // Good to know: the garbage collector might delete the next directory
// the garbage collector might delete the next directory while it is // while it is still running. It does seem to cause any issue though.
// still running. It does seem to cause any issue though.
userProfileDirPath := gotenberg.NewDirPath() userProfileDirPath := gotenberg.NewDirPath()
args := []string{ args := []string{
@@ -100,34 +106,77 @@ func (listener *libreOfficeListener) start(logger *zap.Logger) error {
return fmt.Errorf("start LibreOffice listener: %w", err) return fmt.Errorf("start LibreOffice listener: %w", err)
} }
// As the LibreOffice socket may take some time to be available, we have to waitChan := make(chan error, 1)
// ensure that it is indeed accepting connections.
logger.Debug("waiting for the LibreOffice listener socket to be available...")
for { go func() {
if ctx.Err() != nil { // By waiting the process, we avoid the creation of a zombie process
return fmt.Errorf("waiting for the LibreOffice listener socket to be available: %w", ctx.Err()) // and make sure we catch an early exit if any.
} waitChan <- cmd.Wait()
}()
conn, err := net.DialTimeout("tcp", fmt.Sprintf("127.0.0.1:%d", port), time.Duration(1)*time.Second) connChan := make(chan error, 1)
if err == nil {
go func() {
// As the LibreOffice socket may take some time to be available, we
// have to ensure that it is indeed accepting connections.
for {
if ctx.Err() != nil {
connChan <- ctx.Err()
break
}
conn, err := net.DialTimeout("tcp", fmt.Sprintf("127.0.0.1:%d", port), time.Duration(1)*time.Second)
if err != nil {
continue
}
connChan <- nil
err = conn.Close() err = conn.Close()
if err != nil { if err != nil {
logger.Debug(fmt.Sprintf("close connection after health checking the LibreOffice listener: %v", err)) logger.Debug(fmt.Sprintf("close connection after health checking the LibreOffice listener: %v", err))
} }
break break
} }
}()
var success bool
defer func() {
if success {
listener.cfgMu.Lock()
listener.socketPort = port
listener.userProfileDirPath = userProfileDirPath
listener.cmd = cmd
listener.cfgMu.Unlock()
return
}
// Let's make sure the process is killed.
err = cmd.Kill()
if err != nil {
logger.Debug(fmt.Sprintf("kill LibreOffice listener process: %v", err))
}
}()
logger.Debug("waiting for the LibreOffice listener socket to be available...")
for {
select {
case err = <-connChan:
if err != nil {
return fmt.Errorf("LibreOffice listener socket not available: %w", err)
}
logger.Debug("LibreOffice listener socket available")
success = true
return nil
case err = <-waitChan:
return fmt.Errorf("LibreOffice listener process exited: %w", err)
}
} }
logger.Debug("LibreOffice listener socket available")
listener.cfgMu.Lock()
listener.socketPort = port
listener.userProfileDirPath = userProfileDirPath
listener.cmd = cmd
listener.cfgMu.Unlock()
return nil
} }
func (listener *libreOfficeListener) stop(logger *zap.Logger) error { func (listener *libreOfficeListener) stop(logger *zap.Logger) error {
@@ -147,12 +196,6 @@ func (listener *libreOfficeListener) stop(logger *zap.Logger) error {
return fmt.Errorf("kill LibreOffice listener process: %w", err) return fmt.Errorf("kill LibreOffice listener process: %w", err)
} }
// Let's wait to make sure the process is no more.
err = listener.cmd.Wait()
if err != nil {
logger.Debug(fmt.Sprintf("wait for the LibreOffice listener: %v", err))
}
return nil return nil
} }
@@ -187,33 +230,71 @@ func (listener *libreOfficeListener) lock(ctx context.Context, logger *zap.Logge
listener.queueLength += 1 listener.queueLength += 1
listener.queueLengthMu.Unlock() listener.queueLengthMu.Unlock()
defer func() {
listener.queueLengthMu.Lock()
listener.queueLength -= 1
listener.queueLengthMu.Unlock()
}()
doWithContext := func(ctx context.Context, do func() error) error {
doChan := make(chan error, 1)
go func() {
doChan <- do()
}()
for {
select {
case err := <-doChan:
return err
case <-ctx.Done():
return ctx.Err()
}
}
}
select { select {
case listener.lockChan <- struct{}{}: case listener.lockChan <- struct{}{}:
logger.Debug("LibreOffice listener lock acquired") logger.Debug("LibreOffice listener lock acquired")
listener.queueLengthMu.Lock() listener.hadFirstStartMu.RLock()
listener.queueLength -= 1
listener.queueLengthMu.Unlock()
if !listener.healthy() { if !listener.hadFirstStart {
logger.Debug("LibreOffice listener is unhealthy, restarting it...") listener.hadFirstStartMu.RUnlock()
logger.Debug("starting LibreOffice listener...")
err := doWithContext(ctx, func() error {
return listener.start(logger)
})
err := listener.restart(logger)
if err == nil { if err == nil {
return nil return nil
} }
return fmt.Errorf("restart LibreOffice listener: %w", err) return fmt.Errorf("start long-running LibreOffice listener: %w", err)
}
listener.hadFirstStartMu.RUnlock()
if !listener.healthy() {
logger.Debug("LibreOffice listener is unhealthy, restarting it...")
err := doWithContext(ctx, func() error {
return listener.restart(logger)
})
if err == nil {
return nil
}
return fmt.Errorf("restart long-running LibreOffice listener: %w", err)
} }
return nil return nil
case <-ctx.Done(): case <-ctx.Done():
logger.Debug("failed to acquire LibreOffice listener lock before deadline") logger.Debug("failed to acquire LibreOffice listener lock before deadline")
listener.queueLengthMu.Lock()
listener.queueLength -= 1
listener.queueLengthMu.Unlock()
return fmt.Errorf("acquire LibreOffice listener lock: %w", ctx.Err()) return fmt.Errorf("acquire LibreOffice listener lock: %w", ctx.Err())
} }
} }
@@ -265,6 +346,13 @@ func (listener *libreOfficeListener) queue() int {
} }
func (listener *libreOfficeListener) healthy() bool { func (listener *libreOfficeListener) healthy() bool {
listener.hadFirstStartMu.RLock()
defer listener.hadFirstStartMu.RUnlock()
if !listener.hadFirstStart {
return true
}
listener.restartingMu.RLock() listener.restartingMu.RLock()
defer listener.restartingMu.RUnlock() defer listener.restartingMu.RUnlock()

View File

@@ -121,6 +121,14 @@ func TestListener_lock(t *testing.T) {
return listener.stop(zap.NewNop()) return listener.stop(zap.NewNop())
}, },
}, },
{
name: "first start",
listener: newLibreOfficeListener(zap.NewNop(), os.Getenv("LIBREOFFICE_BIN_PATH"), time.Duration(10)*time.Second, 10),
ctx: context.Background(),
teardown: func(listener listener) error {
return listener.stop(zap.NewNop())
},
},
{ {
name: "unhealthy listener", name: "unhealthy listener",
listener: func() listener { listener: func() listener {
@@ -390,6 +398,11 @@ func TestListener_healthy(t *testing.T) {
logger: zap.NewNop(), logger: zap.NewNop(),
} }
// i.e., first start.
if !listener.healthy() {
t.Error("expected an healthy LibreOffice listener")
}
err := listener.start(zap.NewNop()) err := listener.start(zap.NewNop())
if err != nil { if err != nil {
t.Fatalf("expected no error from listener.start(), but got: %v", err) t.Fatalf("expected no error from listener.start(), but got: %v", err)
@@ -404,6 +417,8 @@ func TestListener_healthy(t *testing.T) {
t.Fatalf("expected no error from listener.stop(), but got: %v", err) t.Fatalf("expected no error from listener.stop(), but got: %v", err)
} }
time.Sleep(time.Duration(1) * time.Second)
if listener.healthy() { if listener.healthy() {
t.Errorf("expected a non-healthy LibreOffice listener") t.Errorf("expected a non-healthy LibreOffice listener")
} }

View File

@@ -81,7 +81,7 @@ func (UNO) Descriptor() gotenberg.ModuleDescriptor {
ID: "uno", ID: "uno",
FlagSet: func() *flag.FlagSet { FlagSet: func() *flag.FlagSet {
fs := flag.NewFlagSet("uno", flag.ExitOnError) fs := flag.NewFlagSet("uno", flag.ExitOnError)
fs.Duration("uno-listener-start-timeout", time.Duration(10)*time.Second, "Time limit for starting the LibreOffice listener") fs.Duration("uno-listener-start-timeout", time.Duration(10)*time.Second, "Time limit for restarting the LibreOffice listener")
fs.Int("uno-listener-restart-threshold", 10, "Conversions limit after which the LibreOffice listener is restarted - 0 means no long-running LibreOffice listener") fs.Int("uno-listener-restart-threshold", 10, "Conversions limit after which the LibreOffice listener is restarted - 0 means no long-running LibreOffice listener")
fs.Bool("unoconv-disable-listener", false, "Do not start a long-running listener - save resources in detriment of unitary performance") fs.Bool("unoconv-disable-listener", false, "Do not start a long-running listener - save resources in detriment of unitary performance")
@@ -161,19 +161,11 @@ func (mod UNO) Validate() error {
return err return err
} }
// Start starts the long-running LibreOffice listener if the threshold is // Start does nothing: it is here to validate the contract from the
// superior to zero. // gotenberg.App interface. The long-running LibreOffice Listener will be
// started on the first call to PDF.
func (mod UNO) Start() error { func (mod UNO) Start() error {
if mod.libreOfficeRestartThreshold == 0 { return nil
return nil
}
err := mod.listener.start(mod.logger)
if err == nil {
return nil
}
return fmt.Errorf("start long-running LibreOffice listener: %w", err)
} }
// StartupMessage returns a custom startup message. // StartupMessage returns a custom startup message.
@@ -182,7 +174,7 @@ func (mod UNO) StartupMessage() string {
return "long-running LibreOffice listener disabled" return "long-running LibreOffice listener disabled"
} }
return "long-running LibreOffice listener started" return "long-running LibreOffice listener ready to start"
} }
// Stop stops the long-running LibreOffice Listener if it exists. // Stop stops the long-running LibreOffice Listener if it exists.
@@ -202,7 +194,7 @@ func (mod UNO) Stop(ctx context.Context) error {
return nil return nil
} }
return fmt.Errorf("stop long-running LibreOffice supervisor") return fmt.Errorf("stop long-running LibreOffice listener")
} }
// Metrics returns the metrics. // Metrics returns the metrics.

View File

@@ -196,55 +196,7 @@ func TestUNO_Validate(t *testing.T) {
} }
func TestUNO_Start(t *testing.T) { 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) { func TestUNO_StartupMessage(t *testing.T) {
@@ -254,11 +206,11 @@ func TestUNO_StartupMessage(t *testing.T) {
expectMessage string expectMessage string
}{ }{
{ {
name: "long-running LibreOffice listener started", name: "long-running LibreOffice listener ready to start",
mod: UNO{ mod: UNO{
libreOfficeRestartThreshold: 10, libreOfficeRestartThreshold: 10,
}, },
expectMessage: "long-running LibreOffice listener started", expectMessage: "long-running LibreOffice listener ready to start",
}, },
{ {
name: "long-running LibreOffice listener disabled", name: "long-running LibreOffice listener disabled",
@@ -549,11 +501,6 @@ func TestUNO_PDF(t *testing.T) {
mod.libreOfficeRestartThreshold, mod.libreOfficeRestartThreshold,
) )
err := mod.Start()
if err != nil {
t.Fatalf("expected no error from mod.Start(), but got: %v", err)
}
return mod return mod
}(), }(),
ctx: context.Background(), ctx: context.Background(),

View File

@@ -15,7 +15,7 @@ import (
func TestMergeHandler(t *testing.T) { func TestMergeHandler(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
ctx *api.MockContext ctx *api.ContextMock
engine gotenberg.PDFEngine engine gotenberg.PDFEngine
expectErr bool expectErr bool
expectHTTPErr bool expectHTTPErr bool
@@ -24,8 +24,8 @@ func TestMergeHandler(t *testing.T) {
}{ }{
{ {
name: "nominal behavior", name: "nominal behavior",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })
@@ -41,15 +41,15 @@ func TestMergeHandler(t *testing.T) {
}, },
{ {
name: "invalid form data: no PDF", name: "invalid form data: no PDF",
ctx: &api.MockContext{Context: &api.Context{}}, ctx: &api.ContextMock{Context: &api.Context{}},
expectErr: true, expectErr: true,
expectHTTPErr: true, expectHTTPErr: true,
expectHTTPStatus: http.StatusBadRequest, expectHTTPStatus: http.StatusBadRequest,
}, },
{ {
name: "merge fail", name: "merge fail",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })
@@ -65,8 +65,8 @@ func TestMergeHandler(t *testing.T) {
}, },
{ {
name: "nominal behavior with a PDF format", name: "nominal behavior with a PDF format",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })
@@ -90,8 +90,8 @@ func TestMergeHandler(t *testing.T) {
}, },
{ {
name: "convert to PDF format fail", name: "convert to PDF format fail",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })
@@ -115,8 +115,8 @@ func TestMergeHandler(t *testing.T) {
}, },
{ {
name: "invalid PDF format", name: "invalid PDF format",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })
@@ -142,8 +142,8 @@ func TestMergeHandler(t *testing.T) {
}, },
{ {
name: "cannot add output paths", name: "cannot add output paths",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })
@@ -203,7 +203,7 @@ func TestMergeHandler(t *testing.T) {
func TestConvertHandler(t *testing.T) { func TestConvertHandler(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
ctx *api.MockContext ctx *api.ContextMock
engine gotenberg.PDFEngine engine gotenberg.PDFEngine
expectErr bool expectErr bool
expectHTTPErr bool expectHTTPErr bool
@@ -212,8 +212,8 @@ func TestConvertHandler(t *testing.T) {
}{ }{
{ {
name: "nominal behavior", name: "nominal behavior",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })
@@ -234,8 +234,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "nominal behavior, but with 3 PDFs", name: "nominal behavior, but with 3 PDFs",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
"bar.pdf": "/bar/bar.pdf", "bar.pdf": "/bar/bar.pdf",
@@ -258,8 +258,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "invalid form data: no PDF", name: "invalid form data: no PDF",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"pdfFormat": { "pdfFormat": {
gotenberg.FormatPDFA1a, gotenberg.FormatPDFA1a,
@@ -274,8 +274,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "invalid form data: no PDF format", name: "invalid form data: no PDF format",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })
@@ -288,8 +288,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "convert to PDF format fail", name: "convert to PDF format fail",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })
@@ -310,8 +310,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "PDF format not available", name: "PDF format not available",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })
@@ -334,8 +334,8 @@ func TestConvertHandler(t *testing.T) {
}, },
{ {
name: "cannot add output paths", name: "cannot add output paths",
ctx: func() *api.MockContext { ctx: func() *api.ContextMock {
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetFiles(map[string]string{ ctx.SetFiles(map[string]string{
"foo.pdf": "/foo/foo.pdf", "foo.pdf": "/foo/foo.pdf",
}) })

View File

@@ -252,7 +252,7 @@ func TestWebhookMiddlewareGuards(t *testing.T) {
c := srv.NewContext(tc.request, httptest.NewRecorder()) c := srv.NewContext(tc.request, httptest.NewRecorder())
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetEchoContext(c) ctx.SetEchoContext(c)
c.Set("context", ctx.Context) c.Set("context", ctx.Context)
@@ -399,7 +399,7 @@ func TestWebhookMiddlewareAsynchronousProcess(t *testing.T) {
c.Set("trace", "foo") c.Set("trace", "foo")
c.Set("startTime", time.Now()) c.Set("startTime", time.Now())
ctx := &api.MockContext{Context: &api.Context{}} ctx := &api.ContextMock{Context: &api.Context{}}
ctx.SetLogger(zap.NewNop()) ctx.SetLogger(zap.NewNop())
ctx.SetEchoContext(c) ctx.SetEchoContext(c)

View File

@@ -2,5 +2,6 @@
set -x set -x
go test -race -covermode=atomic -coverprofile=/tests/coverage.txt ./... # TODO: remove -buildvcs=false when fix for https://github.com/golang/go/issues/51723 is live.
go test -buildvcs=false -race -covermode=atomic -coverprofile=/tests/coverage.txt ./...
go tool cover -html=coverage.txt -o /tests/coverage.html go tool cover -html=coverage.txt -o /tests/coverage.html