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