func (s *execSuite) TestKillAbortedIfUnsuccessfull(c *gc.C) { killCalled := false mockChan := make(chan time.Time, 1) defer close(mockChan) params := exec.RunParams{ Commands: "sleep 100", WorkingDir: "", Environment: []string{}, Clock: &mockClock{C: mockChan}, KillProcess: func(*os.Process) error { killCalled = true return nil }, } err := params.Run() c.Assert(err, gc.IsNil) c.Assert(params.Process(), gc.Not(gc.IsNil)) cancelChan := make(chan struct{}, 1) defer close(cancelChan) cancelChan <- struct{}{} mockChan <- time.Now() res, err := params.WaitWithCancel(cancelChan) c.Assert(err, gc.ErrorMatches, fmt.Sprintf("tried to kill process %d, but timed out", params.Process().Pid)) c.Assert(res, gc.IsNil) c.Assert(killCalled, jc.IsTrue) }
func (*execSuite) TestWaitWithCancel(c *gc.C) { params := exec.RunParams{ Commands: "sleep 100", Clock: &mockClock{C: make(chan time.Time)}, } err := params.Run() c.Assert(err, gc.IsNil) c.Assert(params.Process(), gc.Not(gc.IsNil)) cancelChan := make(chan struct{}, 1) defer close(cancelChan) cancelChan <- struct{}{} result, err := params.WaitWithCancel(cancelChan) c.Assert(err, gc.Equals, exec.ErrCancelled) c.Assert(string(result.Stdout), gc.Equals, "") c.Assert(string(result.Stderr), gc.Equals, "") c.Assert(result.Code, gc.Equals, cancelErrCode) }
// runCommandsWithTimeout is a helper to abstract common code between run commands and // juju-run as an action func (runner *runner) runCommandsWithTimeout(commands string, timeout time.Duration, clock clock.Clock) (*utilexec.ExecResponse, error) { srv, err := runner.startJujucServer() if err != nil { return nil, err } defer srv.Close() env, err := runner.context.HookVars(runner.paths) if err != nil { return nil, errors.Trace(err) } command := utilexec.RunParams{ Commands: commands, WorkingDir: runner.paths.GetCharmDir(), Environment: env, Clock: clock, } err = command.Run() if err != nil { return nil, err } runner.context.SetProcess(hookProcess{command.Process()}) var cancel chan struct{} if timeout != 0 { cancel = make(chan struct{}) go func() { <-clock.After(timeout) close(cancel) }() } // Block and wait for process to finish return command.WaitWithCancel(cancel) }
func (*execSuite) TestRunCommands(c *gc.C) { newDir, err := longPathAsString(c.MkDir()) c.Assert(err, gc.IsNil) for i, test := range []struct { message string commands string workingDir string environment []string stdout string stderr string code int }{ { message: "test stdout capture", commands: "echo 'testing stdout'", stdout: "testing stdout\r\n", }, { message: "test stderr capture", commands: "Write-Error 'testing stderr'", stderr: "testing stderr\r\n", }, { message: "test return code", commands: "exit 42", code: 42, }, { message: "test working dir", commands: "(pwd).Path", workingDir: newDir, stdout: filepath.FromSlash(newDir) + "\r\n", }, { message: "test environment", commands: "echo $env:OMG_IT_WORKS", environment: []string{"OMG_IT_WORKS=like magic"}, stdout: "like magic\r\n", }, } { c.Logf("%v: %s", i, test.message) params := exec.RunParams{ Commands: test.commands, WorkingDir: test.workingDir, Environment: test.environment, } result, err := exec.RunCommands(params) c.Assert(err, gc.IsNil) c.Assert(string(result.Stdout), gc.Equals, test.stdout) c.Assert(string(result.Stderr), jc.Contains, test.stderr) c.Assert(result.Code, gc.Equals, test.code) err = params.Run() c.Assert(err, gc.IsNil) c.Assert(params.Process(), gc.Not(gc.IsNil)) result, err = params.Wait() c.Assert(err, gc.IsNil) c.Assert(string(result.Stdout), gc.Equals, test.stdout) c.Assert(string(result.Stderr), jc.Contains, test.stderr) c.Assert(result.Code, gc.Equals, test.code) err = params.Run() c.Assert(err, gc.IsNil) c.Assert(params.Process(), gc.Not(gc.IsNil)) result, err = params.WaitWithCancel(nil) c.Assert(err, gc.IsNil) c.Assert(string(result.Stdout), gc.Equals, test.stdout) c.Assert(string(result.Stderr), jc.Contains, test.stderr) c.Assert(result.Code, gc.Equals, test.code) } }