github.com/dmaizel/tests@v0.0.0-20210728163746-cae6a2d9cee8/command.go (about) 1 // Copyright (c) 2018 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package tests 6 7 import ( 8 "bytes" 9 "fmt" 10 "os/exec" 11 "syscall" 12 "time" 13 ) 14 15 // Command contains the information of the command to run 16 type Command struct { 17 // cmd exec.Cmd 18 cmd *exec.Cmd 19 20 // Timeout is the time limit of seconds of the command 21 Timeout time.Duration 22 } 23 24 // NewCommand returns a new instance of Command 25 func NewCommand(path string, args ...string) *Command { 26 c := new(Command) 27 c.cmd = exec.Command(path, args...) 28 c.Timeout = time.Duration(Timeout) 29 30 return c 31 } 32 33 // Run runs a command returning its stdout, stderr and exit code 34 func (c *Command) Run() (string, string, int) { 35 return c.RunWithPipe(nil) 36 } 37 38 // RunWithPipe runs a command with stdin as an input and returning its stdout, stderr and exit code 39 func (c *Command) RunWithPipe(stdin *bytes.Buffer) (string, string, int) { 40 LogIfFail("Running command '%s %s'\n", c.cmd.Path, c.cmd.Args) 41 42 keepAliveTime := 1 * time.Minute 43 44 var stdout, stderr bytes.Buffer 45 c.cmd.Stdout = &stdout 46 c.cmd.Stderr = &stderr 47 48 if stdin != nil { 49 c.cmd.Stdin = stdin 50 } 51 52 if err := c.cmd.Start(); err != nil { 53 LogIfFail("could no start command: %v\n", err) 54 } 55 56 done := make(chan error) 57 go func() { done <- c.cmd.Wait() }() 58 59 var timeout <-chan time.Time 60 if c.Timeout > 0 { 61 timeout = time.After(c.Timeout * time.Second) 62 } 63 64 keepAliveCh := time.NewTimer(keepAliveTime) 65 66 for { 67 select { 68 case <-timeout: 69 keepAliveCh.Stop() 70 LogIfFail("Killing process timeout reached '%d' seconds\n", c.Timeout) 71 _ = c.cmd.Process.Kill() 72 return "", "", -1 73 74 case <-keepAliveCh.C: 75 // Avoid CI (i.e jenkins) kills the process for inactivity by printing a dot 76 fmt.Println(".") 77 keepAliveCh.Reset(keepAliveTime) 78 79 case err := <-done: 80 keepAliveCh.Stop() 81 if err != nil { 82 LogIfFail("command failed error '%s'\n", err) 83 } 84 85 exitCode := c.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() 86 87 LogIfFail("%+v\nTimeout: %d seconds\nExit Code: %d\nStdout: %s\nStderr: %s\n", 88 c.cmd.Args, c.Timeout, exitCode, stdout.String(), stderr.String()) 89 90 return stdout.String(), stderr.String(), exitCode 91 } 92 } 93 }