github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/machine/remove_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package machine_test
     5  
     6  import (
     7  	"github.com/juju/cmd"
     8  	"github.com/juju/cmd/cmdtesting"
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/api"
    13  	"github.com/juju/juju/apiserver/common"
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/cmd/juju/machine"
    16  	"github.com/juju/juju/testing"
    17  )
    18  
    19  type RemoveMachineSuite struct {
    20  	testing.FakeJujuXDGDataHomeSuite
    21  	fake          *fakeRemoveMachineAPI
    22  	apiConnection *mockAPIConnection
    23  }
    24  
    25  var _ = gc.Suite(&RemoveMachineSuite{})
    26  
    27  func (s *RemoveMachineSuite) SetUpTest(c *gc.C) {
    28  	s.FakeJujuXDGDataHomeSuite.SetUpTest(c)
    29  	s.fake = &fakeRemoveMachineAPI{}
    30  	s.apiConnection = &mockAPIConnection{
    31  		bestFacadeVersion: 4,
    32  	}
    33  }
    34  
    35  func (s *RemoveMachineSuite) run(c *gc.C, args ...string) (*cmd.Context, error) {
    36  	remove, _ := machine.NewRemoveCommandForTest(s.apiConnection, s.fake)
    37  	return cmdtesting.RunCommand(c, remove, args...)
    38  }
    39  
    40  func (s *RemoveMachineSuite) TestInit(c *gc.C) {
    41  	for i, test := range []struct {
    42  		args        []string
    43  		machines    []string
    44  		force       bool
    45  		keep        bool
    46  		errorString string
    47  	}{
    48  		{
    49  			errorString: "no machines specified",
    50  		}, {
    51  			args:     []string{"1"},
    52  			machines: []string{"1"},
    53  		}, {
    54  			args:     []string{"1", "2"},
    55  			machines: []string{"1", "2"},
    56  		}, {
    57  			args:     []string{"1", "--force"},
    58  			machines: []string{"1"},
    59  			force:    true,
    60  		}, {
    61  			args:     []string{"--force", "1", "2"},
    62  			machines: []string{"1", "2"},
    63  			force:    true,
    64  		}, {
    65  			args:     []string{"--keep-instance", "1", "2"},
    66  			machines: []string{"1", "2"},
    67  			keep:     true,
    68  		}, {
    69  			args:        []string{"lxd"},
    70  			errorString: `invalid machine id "lxd"`,
    71  		}, {
    72  			args:     []string{"1/lxd/2"},
    73  			machines: []string{"1/lxd/2"},
    74  		},
    75  	} {
    76  		c.Logf("test %d", i)
    77  		wrappedCommand, removeCmd := machine.NewRemoveCommandForTest(s.apiConnection, s.fake)
    78  		err := cmdtesting.InitCommand(wrappedCommand, test.args)
    79  		if test.errorString == "" {
    80  			c.Check(err, jc.ErrorIsNil)
    81  			c.Check(removeCmd.Force, gc.Equals, test.force)
    82  			c.Check(removeCmd.KeepInstance, gc.Equals, test.keep)
    83  			c.Check(removeCmd.MachineIds, jc.DeepEquals, test.machines)
    84  		} else {
    85  			c.Check(err, gc.ErrorMatches, test.errorString)
    86  		}
    87  	}
    88  }
    89  
    90  func (s *RemoveMachineSuite) TestRemove(c *gc.C) {
    91  	_, err := s.run(c, "1", "2/lxd/1")
    92  	c.Assert(err, jc.ErrorIsNil)
    93  	c.Assert(s.fake.forced, jc.IsFalse)
    94  	c.Assert(s.fake.machines, jc.DeepEquals, []string{"1", "2/lxd/1"})
    95  }
    96  
    97  func (s *RemoveMachineSuite) TestRemoveOutput(c *gc.C) {
    98  	s.fake.results = []params.DestroyMachineResult{{
    99  		Error: &params.Error{
   100  			Message: "oy vey",
   101  		},
   102  	}, {
   103  		Info: &params.DestroyMachineInfo{
   104  			DestroyedUnits:   []params.Entity{{"unit-foo-0"}},
   105  			DestroyedStorage: []params.Entity{{"storage-bar-1"}},
   106  			DetachedStorage:  []params.Entity{{"storage-baz-2"}},
   107  		},
   108  	}}
   109  	ctx, err := s.run(c, "1", "2/lxd/1")
   110  	c.Assert(err, gc.Equals, cmd.ErrSilent)
   111  	stderr := cmdtesting.Stderr(ctx)
   112  	c.Assert(stderr, gc.Equals, `
   113  removing machine 1 failed: oy vey
   114  removing machine 2/lxd/1
   115  - will remove unit foo/0
   116  - will remove storage bar/1
   117  - will detach storage baz/2
   118  `[1:])
   119  }
   120  
   121  func (s *RemoveMachineSuite) TestRemoveOutputKeep(c *gc.C) {
   122  	ctx, err := s.run(c, "--keep-instance", "1", "2")
   123  	c.Assert(err, jc.ErrorIsNil)
   124  	stderr := cmdtesting.Stderr(ctx)
   125  	c.Assert(stderr, gc.Equals, `
   126  removing machine 1 (but retaining cloud instance)
   127  removing machine 2 (but retaining cloud instance)
   128  `[1:])
   129  }
   130  
   131  func (s *RemoveMachineSuite) TestRemoveForce(c *gc.C) {
   132  	_, err := s.run(c, "--force", "1", "2/lxd/1")
   133  	c.Assert(err, jc.ErrorIsNil)
   134  	c.Assert(s.fake.forced, jc.IsTrue)
   135  	c.Assert(s.fake.keep, jc.IsFalse)
   136  	c.Assert(s.fake.machines, jc.DeepEquals, []string{"1", "2/lxd/1"})
   137  }
   138  
   139  func (s *RemoveMachineSuite) TestRemoveKeep(c *gc.C) {
   140  	_, err := s.run(c, "--keep-instance", "1", "2")
   141  	c.Assert(err, jc.ErrorIsNil)
   142  	c.Assert(s.fake.forced, jc.IsFalse)
   143  	c.Assert(s.fake.keep, jc.IsTrue)
   144  	c.Assert(s.fake.machines, jc.DeepEquals, []string{"1", "2"})
   145  }
   146  
   147  func (s *RemoveMachineSuite) TestBlockedError(c *gc.C) {
   148  	s.fake.removeError = common.OperationBlockedError("TestBlockedError")
   149  	_, err := s.run(c, "1")
   150  	c.Assert(s.fake.forced, jc.IsFalse)
   151  	testing.AssertOperationWasBlocked(c, err, ".*TestBlockedError.*")
   152  }
   153  
   154  func (s *RemoveMachineSuite) TestForceBlockedError(c *gc.C) {
   155  	s.fake.removeError = common.OperationBlockedError("TestForceBlockedError")
   156  	_, err := s.run(c, "--force", "1")
   157  	c.Assert(s.fake.forced, jc.IsTrue)
   158  	testing.AssertOperationWasBlocked(c, err, ".*TestForceBlockedError.*")
   159  }
   160  
   161  func (s *RemoveMachineSuite) TestOldFacadeRemoveKeep(c *gc.C) {
   162  	s.apiConnection.bestFacadeVersion = 3
   163  	_, err := s.run(c, "--keep-instance", "1")
   164  	c.Assert(err, gc.ErrorMatches, "this version of Juju doesn't support --keep-instance")
   165  }
   166  
   167  type fakeRemoveMachineAPI struct {
   168  	forced      bool
   169  	keep        bool
   170  	machines    []string
   171  	removeError error
   172  	results     []params.DestroyMachineResult
   173  }
   174  
   175  func (f *fakeRemoveMachineAPI) Close() error {
   176  	return nil
   177  }
   178  
   179  func (f *fakeRemoveMachineAPI) DestroyMachines(machines ...string) ([]params.DestroyMachineResult, error) {
   180  	f.forced = false
   181  	return f.destroyMachines(machines)
   182  }
   183  
   184  func (f *fakeRemoveMachineAPI) ForceDestroyMachines(machines ...string) ([]params.DestroyMachineResult, error) {
   185  	f.forced = true
   186  	return f.destroyMachines(machines)
   187  }
   188  
   189  func (f *fakeRemoveMachineAPI) DestroyMachinesWithParams(force, keep bool, machines ...string) ([]params.DestroyMachineResult, error) {
   190  	f.forced = force
   191  	f.keep = keep
   192  	return f.destroyMachines(machines)
   193  }
   194  
   195  func (f *fakeRemoveMachineAPI) destroyMachines(machines []string) ([]params.DestroyMachineResult, error) {
   196  	f.machines = machines
   197  	if f.removeError != nil || f.results != nil {
   198  		return f.results, f.removeError
   199  	}
   200  	results := make([]params.DestroyMachineResult, len(machines))
   201  	for i := range results {
   202  		results[i].Info = &params.DestroyMachineInfo{}
   203  	}
   204  	return results, nil
   205  }
   206  
   207  type mockAPIConnection struct {
   208  	api.Connection
   209  	bestFacadeVersion int
   210  }
   211  
   212  func (m *mockAPIConnection) BestFacadeVersion(name string) int {
   213  	return m.bestFacadeVersion
   214  }