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: ¶ms.Error{ 100 Message: "oy vey", 101 }, 102 }, { 103 Info: ¶ms.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 = ¶ms.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 }