github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/runcommands/runcommands_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package runcommands_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	jc "github.com/juju/testing/checkers"
     9  	"github.com/juju/utils/exec"
    10  	gc "gopkg.in/check.v1"
    11  	"gopkg.in/juju/charm.v6-unstable"
    12  
    13  	"github.com/juju/juju/worker/uniter/operation"
    14  	"github.com/juju/juju/worker/uniter/remotestate"
    15  	"github.com/juju/juju/worker/uniter/resolver"
    16  	"github.com/juju/juju/worker/uniter/runcommands"
    17  	"github.com/juju/juju/worker/uniter/runner"
    18  	runnercontext "github.com/juju/juju/worker/uniter/runner/context"
    19  )
    20  
    21  type runcommandsSuite struct {
    22  	charmURL         *charm.URL
    23  	remoteState      remotestate.Snapshot
    24  	mockRunner       mockRunner
    25  	callbacks        *mockCallbacks
    26  	opFactory        operation.Factory
    27  	resolver         resolver.Resolver
    28  	commands         runcommands.Commands
    29  	runCommands      func(string) (*exec.ExecResponse, error)
    30  	commandCompleted func(string)
    31  }
    32  
    33  var _ = gc.Suite(&runcommandsSuite{})
    34  
    35  func (s *runcommandsSuite) SetUpTest(c *gc.C) {
    36  	s.charmURL = charm.MustParseURL("cs:precise/mysql-2")
    37  	s.remoteState = remotestate.Snapshot{
    38  		CharmURL: s.charmURL,
    39  	}
    40  	s.mockRunner = mockRunner{runCommands: func(commands string) (*exec.ExecResponse, error) {
    41  		return s.runCommands(commands)
    42  	}}
    43  	s.callbacks = &mockCallbacks{}
    44  	s.opFactory = operation.NewFactory(operation.FactoryParams{
    45  		Callbacks: s.callbacks,
    46  		RunnerFactory: &mockRunnerFactory{
    47  			newCommandRunner: func(info runnercontext.CommandInfo) (runner.Runner, error) {
    48  				return &s.mockRunner, nil
    49  			},
    50  		},
    51  	})
    52  
    53  	s.commands = runcommands.NewCommands()
    54  	s.commandCompleted = nil
    55  	s.resolver = runcommands.NewCommandsResolver(
    56  		s.commands, func(id string) {
    57  			if s.commandCompleted != nil {
    58  				s.commandCompleted(id)
    59  			}
    60  		},
    61  	)
    62  }
    63  
    64  func (s *runcommandsSuite) TestRunCommands(c *gc.C) {
    65  	localState := resolver.LocalState{
    66  		CharmURL: s.charmURL,
    67  		State: operation.State{
    68  			Kind: operation.Continue,
    69  		},
    70  	}
    71  	id := s.commands.AddCommand(operation.CommandArgs{
    72  		Commands: "echo foxtrot",
    73  	}, func(*exec.ExecResponse, error) {})
    74  	s.remoteState.Commands = []string{id}
    75  	op, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
    76  	c.Assert(err, jc.ErrorIsNil)
    77  	c.Assert(op.String(), gc.Equals, "run commands (0)")
    78  }
    79  
    80  func (s *runcommandsSuite) TestRunCommandsCallbacks(c *gc.C) {
    81  	var completed []string
    82  	s.commandCompleted = func(id string) {
    83  		completed = append(completed, id)
    84  	}
    85  
    86  	var run []string
    87  	s.runCommands = func(commands string) (*exec.ExecResponse, error) {
    88  		run = append(run, commands)
    89  		return &exec.ExecResponse{}, nil
    90  	}
    91  	localState := resolver.LocalState{
    92  		CharmURL: s.charmURL,
    93  		State: operation.State{
    94  			Kind: operation.Continue,
    95  		},
    96  	}
    97  
    98  	id := s.commands.AddCommand(operation.CommandArgs{
    99  		Commands: "echo foxtrot",
   100  	}, func(*exec.ExecResponse, error) {})
   101  	s.remoteState.Commands = []string{id}
   102  
   103  	op, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	c.Assert(op.String(), gc.Equals, "run commands (0)")
   106  
   107  	_, err = op.Prepare(operation.State{})
   108  	c.Assert(err, jc.ErrorIsNil)
   109  	c.Assert(run, gc.HasLen, 0)
   110  	c.Assert(completed, gc.HasLen, 0)
   111  
   112  	_, err = op.Execute(operation.State{})
   113  	c.Assert(err, jc.ErrorIsNil)
   114  	c.Assert(run, jc.DeepEquals, []string{"echo foxtrot"})
   115  	c.Assert(completed, gc.HasLen, 0)
   116  
   117  	_, err = op.Commit(operation.State{})
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	c.Assert(completed, jc.DeepEquals, []string{id})
   120  }
   121  
   122  func (s *runcommandsSuite) TestRunCommandsCommitErrorNoCompletedCallback(c *gc.C) {
   123  	// Override opFactory with one that creates run command
   124  	// operations with failing Commit methods.
   125  	s.opFactory = commitErrorOpFactory{s.opFactory}
   126  
   127  	var completed []string
   128  	s.commandCompleted = func(id string) {
   129  		completed = append(completed, id)
   130  	}
   131  
   132  	var run []string
   133  	s.runCommands = func(commands string) (*exec.ExecResponse, error) {
   134  		run = append(run, commands)
   135  		return &exec.ExecResponse{}, nil
   136  	}
   137  	localState := resolver.LocalState{
   138  		CharmURL: s.charmURL,
   139  		State: operation.State{
   140  			Kind: operation.Continue,
   141  		},
   142  	}
   143  
   144  	id := s.commands.AddCommand(operation.CommandArgs{
   145  		Commands: "echo foxtrot",
   146  	}, func(*exec.ExecResponse, error) {})
   147  	s.remoteState.Commands = []string{id}
   148  
   149  	op, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   150  	c.Assert(err, jc.ErrorIsNil)
   151  	c.Assert(op.String(), gc.Equals, "run commands (0)")
   152  
   153  	_, err = op.Prepare(operation.State{})
   154  	c.Assert(err, jc.ErrorIsNil)
   155  
   156  	_, err = op.Execute(operation.State{})
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	c.Assert(run, jc.DeepEquals, []string{"echo foxtrot"})
   159  	c.Assert(completed, gc.HasLen, 0)
   160  
   161  	_, err = op.Commit(operation.State{})
   162  	c.Assert(err, gc.ErrorMatches, "Commit failed")
   163  	// commandCompleted is not called if Commit fails
   164  	c.Assert(completed, gc.HasLen, 0)
   165  }
   166  
   167  func (s *runcommandsSuite) TestRunCommandsError(c *gc.C) {
   168  	localState := resolver.LocalState{
   169  		CharmURL: s.charmURL,
   170  		State: operation.State{
   171  			Kind: operation.Continue,
   172  		},
   173  	}
   174  	s.runCommands = func(commands string) (*exec.ExecResponse, error) {
   175  		return nil, errors.Errorf("executing commands: %s", commands)
   176  	}
   177  
   178  	var execErr error
   179  	id := s.commands.AddCommand(operation.CommandArgs{
   180  		Commands: "echo foxtrot",
   181  	}, func(_ *exec.ExecResponse, err error) {
   182  		execErr = err
   183  	})
   184  	s.remoteState.Commands = []string{id}
   185  
   186  	op, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	c.Assert(op.String(), gc.Equals, "run commands (0)")
   189  
   190  	_, err = op.Prepare(operation.State{})
   191  	c.Assert(err, jc.ErrorIsNil)
   192  
   193  	_, err = op.Execute(operation.State{})
   194  	c.Assert(execErr, gc.ErrorMatches, "executing commands: echo foxtrot")
   195  	c.Assert(execErr, gc.ErrorMatches, "executing commands: echo foxtrot")
   196  }
   197  
   198  func (s *runcommandsSuite) TestRunCommandsStatus(c *gc.C) {
   199  	localState := resolver.LocalState{
   200  		CharmURL: s.charmURL,
   201  		State: operation.State{
   202  			Kind: operation.Continue,
   203  		},
   204  	}
   205  
   206  	id := s.commands.AddCommand(operation.CommandArgs{
   207  		Commands: "echo foxtrot",
   208  	}, func(*exec.ExecResponse, error) {})
   209  	s.remoteState.Commands = []string{id}
   210  
   211  	op, err := s.resolver.NextOp(localState, s.remoteState, s.opFactory)
   212  	c.Assert(err, jc.ErrorIsNil)
   213  	c.Assert(op.String(), gc.Equals, "run commands (0)")
   214  	s.callbacks.CheckCalls(c, nil /* no calls */)
   215  
   216  	_, err = op.Prepare(operation.State{})
   217  	c.Assert(err, jc.ErrorIsNil)
   218  	s.callbacks.CheckCalls(c, nil /* no calls */)
   219  
   220  	s.callbacks.SetErrors(errors.New("cannot set status"))
   221  	_, err = op.Execute(operation.State{})
   222  	c.Assert(err, gc.ErrorMatches, "cannot set status")
   223  	s.callbacks.CheckCallNames(c, "SetExecutingStatus")
   224  	s.callbacks.CheckCall(c, 0, "SetExecutingStatus", "running commands")
   225  }
   226  
   227  type commitErrorOpFactory struct {
   228  	operation.Factory
   229  }
   230  
   231  func (f commitErrorOpFactory) NewCommands(args operation.CommandArgs, sendResponse operation.CommandResponseFunc) (operation.Operation, error) {
   232  	op, err := f.Factory.NewCommands(args, sendResponse)
   233  	if err == nil {
   234  		op = commitErrorOperation{op}
   235  	}
   236  	return op, err
   237  }
   238  
   239  type commitErrorOperation struct {
   240  	operation.Operation
   241  }
   242  
   243  func (commitErrorOperation) Commit(operation.State) (*operation.State, error) {
   244  	return nil, errors.New("Commit failed")
   245  }