refactoring process tests + adding lock on run function

This commit is contained in:
Julien Neuhart
2018-04-11 14:25:04 +02:00
parent 2e03070618
commit 76f120d6f6
2 changed files with 117 additions and 99 deletions

View File

@@ -5,6 +5,7 @@ import (
"bytes"
"fmt"
"os/exec"
"sync"
"text/template"
"time"
@@ -12,11 +13,60 @@ import (
gfile "github.com/thecodingmachine/gotenberg/app/converter/file"
)
var commandsConfig *config.CommandsConfig
type runner struct {
mu sync.Mutex
commandsConfig *config.CommandsConfig
}
var forest = &runner{}
type commandTimeoutError struct {
command string
timeout int
}
func (e *commandTimeoutError) Error() string {
return fmt.Sprintf("The command '%s' has reached the %d second(s) timeout", e.command, e.timeout)
}
// run runs the given command. If timeout is reached or
// something bad happened, returns an error.
func (r *runner) run(command string, timeout int) error {
r.mu.Lock()
defer r.mu.Unlock()
cmd := exec.Command("/bin/sh", "-c", command)
if err := cmd.Start(); err != nil {
return err
}
done := make(chan error, 1)
go func() {
done <- cmd.Wait()
}()
// wait for the process to finish or kill it after a timeout.
select {
case <-time.After(time.Duration(timeout) * time.Second):
if err := cmd.Process.Kill(); err != nil {
return err
}
return &commandTimeoutError{
command: command,
timeout: timeout,
}
case err := <-done:
if err != nil {
return err
}
return nil
}
}
// Load loads the commands configuration coming from the application configuration.
func Load(config *config.CommandsConfig) {
commandsConfig = config
forest.commandsConfig = config
}
// conversionData will be applied to the data-driven templates of conversions commands.
@@ -47,16 +97,16 @@ func Unconv(workingDir string, file *gfile.File) (string, error) {
switch file.Type {
case gfile.MarkdownType:
cmdTimeout = commandsConfig.Markdown.Timeout
cmdTemplate = commandsConfig.Markdown.Template
cmdTimeout = forest.commandsConfig.Markdown.Timeout
cmdTemplate = forest.commandsConfig.Markdown.Template
break
case gfile.HTMLType:
cmdTimeout = commandsConfig.HTML.Timeout
cmdTemplate = commandsConfig.HTML.Template
cmdTimeout = forest.commandsConfig.HTML.Timeout
cmdTemplate = forest.commandsConfig.HTML.Template
break
case gfile.OfficeType:
cmdTimeout = commandsConfig.Office.Timeout
cmdTemplate = commandsConfig.Office.Template
cmdTimeout = forest.commandsConfig.Office.Timeout
cmdTemplate = forest.commandsConfig.Office.Template
break
default:
return "", &impossibleConversionError{}
@@ -67,7 +117,7 @@ func Unconv(workingDir string, file *gfile.File) (string, error) {
return "", err
}
err := run(data.String(), cmdTimeout)
err := forest.run(data.String(), cmdTimeout)
if err != nil {
return "", err
}
@@ -88,59 +138,18 @@ func Merge(workingDir string, filesPaths []string) (string, error) {
ResultFilePath: gfile.MakeFilePath(workingDir, ".pdf"),
}
cmdTimeout := commandsConfig.Merge.Timeout
cmdTemplate := commandsConfig.Merge.Template
cmdTimeout := forest.commandsConfig.Merge.Timeout
cmdTemplate := forest.commandsConfig.Merge.Template
var data bytes.Buffer
if err := cmdTemplate.Execute(&data, cmdData); err != nil {
return "", err
}
err := run(data.String(), cmdTimeout)
err := forest.run(data.String(), cmdTimeout)
if err != nil {
return "", err
}
return cmdData.ResultFilePath, nil
}
type commandTimeoutError struct {
command string
timeout int
}
func (e *commandTimeoutError) Error() string {
return fmt.Sprintf("The command '%s' has reached the %d second(s) timeout", e.command, e.timeout)
}
// run runs the given command. If timeout is reached or
// something bad happened, returns an error.
func run(command string, timeout int) error {
cmd := exec.Command("/bin/sh", "-c", command)
if err := cmd.Start(); err != nil {
return err
}
done := make(chan error, 1)
go func() {
done <- cmd.Wait()
}()
// wait for the process to finish or kill it after a timeout.
select {
case <-time.After(time.Duration(timeout) * time.Second):
if err := cmd.Process.Kill(); err != nil {
return err
}
return &commandTimeoutError{
command: command,
timeout: timeout,
}
case err := <-done:
if err != nil {
return err
}
return nil
}
}