github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/model/destroy_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package model_test 5 6 import ( 7 "bytes" 8 "time" 9 10 "github.com/juju/cmd" 11 "github.com/juju/errors" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/apiserver/params" 16 "github.com/juju/juju/cmd/juju/model" 17 "github.com/juju/juju/cmd/modelcmd" 18 cmdtesting "github.com/juju/juju/cmd/testing" 19 "github.com/juju/juju/jujuclient" 20 "github.com/juju/juju/jujuclient/jujuclienttesting" 21 _ "github.com/juju/juju/provider/dummy" 22 "github.com/juju/juju/testing" 23 ) 24 25 type DestroySuite struct { 26 testing.FakeJujuXDGDataHomeSuite 27 api *fakeDestroyAPI 28 store *jujuclienttesting.MemStore 29 } 30 31 var _ = gc.Suite(&DestroySuite{}) 32 33 // fakeDestroyAPI mocks out the cient API 34 type fakeDestroyAPI struct { 35 err error 36 env map[string]interface{} 37 } 38 39 func (f *fakeDestroyAPI) Close() error { return nil } 40 41 func (f *fakeDestroyAPI) DestroyModel() error { 42 return f.err 43 } 44 45 func (s *DestroySuite) SetUpTest(c *gc.C) { 46 s.FakeJujuXDGDataHomeSuite.SetUpTest(c) 47 s.api = &fakeDestroyAPI{} 48 s.api.err = nil 49 50 err := modelcmd.WriteCurrentController("test1") 51 c.Assert(err, jc.ErrorIsNil) 52 s.store = jujuclienttesting.NewMemStore() 53 s.store.Controllers["test1"] = jujuclient.ControllerDetails{ControllerUUID: "test1-uuid"} 54 s.store.Models["test1"] = jujuclient.ControllerAccountModels{ 55 AccountModels: map[string]*jujuclient.AccountModels{ 56 "admin@local": { 57 Models: map[string]jujuclient.ModelDetails{ 58 "test1": {"test1-uuid"}, 59 "test2": {"test2-uuid"}, 60 }, 61 }, 62 }, 63 } 64 s.store.Accounts["test1"] = &jujuclient.ControllerAccounts{ 65 CurrentAccount: "admin@local", 66 } 67 } 68 69 func (s *DestroySuite) runDestroyCommand(c *gc.C, args ...string) (*cmd.Context, error) { 70 cmd := model.NewDestroyCommandForTest(s.api, s.store) 71 return testing.RunCommand(c, cmd, args...) 72 } 73 74 func (s *DestroySuite) NewDestroyCommand() cmd.Command { 75 return model.NewDestroyCommandForTest(s.api, s.store) 76 } 77 78 func checkModelExistsInStore(c *gc.C, name string, store jujuclient.ClientStore) { 79 controller, model := modelcmd.SplitModelName(name) 80 _, err := store.ModelByName(controller, "admin@local", model) 81 c.Assert(err, jc.ErrorIsNil) 82 } 83 84 func checkModelRemovedFromStore(c *gc.C, name string, store jujuclient.ClientStore) { 85 controller, model := modelcmd.SplitModelName(name) 86 _, err := store.ModelByName(controller, "admin@local", model) 87 c.Assert(err, jc.Satisfies, errors.IsNotFound) 88 } 89 90 func (s *DestroySuite) TestDestroyNoModelNameError(c *gc.C) { 91 _, err := s.runDestroyCommand(c) 92 c.Assert(err, gc.ErrorMatches, "no model specified") 93 } 94 95 func (s *DestroySuite) TestDestroyBadFlags(c *gc.C) { 96 _, err := s.runDestroyCommand(c, "-n") 97 c.Assert(err, gc.ErrorMatches, "flag provided but not defined: -n") 98 } 99 100 func (s *DestroySuite) TestDestroyUnknownArgument(c *gc.C) { 101 _, err := s.runDestroyCommand(c, "model", "whoops") 102 c.Assert(err, gc.ErrorMatches, `unrecognized args: \["whoops"\]`) 103 } 104 105 func (s *DestroySuite) TestDestroyUnknownModel(c *gc.C) { 106 _, err := s.runDestroyCommand(c, "foo") 107 c.Assert(err, gc.ErrorMatches, `cannot read model info: model test1:admin@local:foo not found`) 108 } 109 110 func (s *DestroySuite) TestDestroyCannotConnectToAPI(c *gc.C) { 111 s.api.err = errors.New("connection refused") 112 _, err := s.runDestroyCommand(c, "test2", "-y") 113 c.Assert(err, gc.ErrorMatches, "cannot destroy model: connection refused") 114 c.Check(c.GetTestLog(), jc.Contains, "failed to destroy model \"test2\"") 115 checkModelExistsInStore(c, "test1:test2", s.store) 116 } 117 118 func (s *DestroySuite) TestSystemDestroyFails(c *gc.C) { 119 _, err := s.runDestroyCommand(c, "test1", "-y") 120 c.Assert(err, gc.ErrorMatches, `"test1" is a controller; use 'juju destroy-controller' to destroy it`) 121 checkModelExistsInStore(c, "test1:test1", s.store) 122 } 123 124 func (s *DestroySuite) TestDestroy(c *gc.C) { 125 checkModelExistsInStore(c, "test1:test2", s.store) 126 _, err := s.runDestroyCommand(c, "test2", "-y") 127 c.Assert(err, jc.ErrorIsNil) 128 checkModelRemovedFromStore(c, "test1:test2", s.store) 129 } 130 131 func (s *DestroySuite) TestFailedDestroyModel(c *gc.C) { 132 s.api.err = errors.New("permission denied") 133 _, err := s.runDestroyCommand(c, "test1:test2", "-y") 134 c.Assert(err, gc.ErrorMatches, "cannot destroy model: permission denied") 135 checkModelExistsInStore(c, "test1:test2", s.store) 136 } 137 138 func (s *DestroySuite) resetModel(c *gc.C) { 139 s.store.Models["test1"] = jujuclient.ControllerAccountModels{ 140 AccountModels: map[string]*jujuclient.AccountModels{ 141 "admin@local": { 142 Models: map[string]jujuclient.ModelDetails{ 143 "test1": {"test1-uuid"}, 144 "test2": {"test2-uuid"}, 145 }, 146 }, 147 }, 148 } 149 } 150 151 func (s *DestroySuite) TestDestroyCommandConfirmation(c *gc.C) { 152 var stdin, stdout bytes.Buffer 153 ctx, err := cmd.DefaultContext() 154 c.Assert(err, jc.ErrorIsNil) 155 ctx.Stdout = &stdout 156 ctx.Stdin = &stdin 157 158 // Ensure confirmation is requested if "-y" is not specified. 159 stdin.WriteString("n") 160 _, errc := cmdtesting.RunCommand(ctx, s.NewDestroyCommand(), "test2") 161 select { 162 case err := <-errc: 163 c.Check(err, gc.ErrorMatches, "model destruction: aborted") 164 case <-time.After(testing.LongWait): 165 c.Fatalf("command took too long") 166 } 167 c.Check(testing.Stdout(ctx), gc.Matches, "WARNING!.*test2(.|\n)*") 168 checkModelExistsInStore(c, "test1:test1", s.store) 169 170 // EOF on stdin: equivalent to answering no. 171 stdin.Reset() 172 stdout.Reset() 173 _, errc = cmdtesting.RunCommand(ctx, s.NewDestroyCommand(), "test2") 174 select { 175 case err := <-errc: 176 c.Check(err, gc.ErrorMatches, "model destruction: aborted") 177 case <-time.After(testing.LongWait): 178 c.Fatalf("command took too long") 179 } 180 c.Check(testing.Stdout(ctx), gc.Matches, "WARNING!.*test2(.|\n)*") 181 checkModelExistsInStore(c, "test1:test2", s.store) 182 183 for _, answer := range []string{"y", "Y", "yes", "YES"} { 184 stdin.Reset() 185 stdout.Reset() 186 stdin.WriteString(answer) 187 _, errc = cmdtesting.RunCommand(ctx, s.NewDestroyCommand(), "test2") 188 select { 189 case err := <-errc: 190 c.Check(err, jc.ErrorIsNil) 191 case <-time.After(testing.LongWait): 192 c.Fatalf("command took too long") 193 } 194 checkModelRemovedFromStore(c, "test1:test2", s.store) 195 196 // Add the test2 model back into the store for the next test 197 s.resetModel(c) 198 } 199 } 200 201 func (s *DestroySuite) TestBlockedDestroy(c *gc.C) { 202 s.api.err = ¶ms.Error{Code: params.CodeOperationBlocked} 203 s.runDestroyCommand(c, "test2", "-y") 204 c.Check(c.GetTestLog(), jc.Contains, "To remove the block") 205 }