github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/cmd/juju/commands/switch_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package commands 5 6 import ( 7 "errors" 8 "os" 9 10 "github.com/juju/cmd/v3" 11 "github.com/juju/cmd/v3/cmdtesting" 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/cmd/juju/common" 17 "github.com/juju/juju/cmd/modelcmd" 18 _ "github.com/juju/juju/juju" 19 "github.com/juju/juju/jujuclient" 20 "github.com/juju/juju/jujuclient/jujuclienttesting" 21 coretesting "github.com/juju/juju/testing" 22 ) 23 24 type SwitchSimpleSuite struct { 25 coretesting.FakeJujuXDGDataHomeSuite 26 testing.Stub 27 store *jujuclient.MemStore 28 stubStore *jujuclienttesting.StubStore 29 onRefresh func() 30 } 31 32 var _ = gc.Suite(&SwitchSimpleSuite{}) 33 34 func (s *SwitchSimpleSuite) SetUpTest(c *gc.C) { 35 s.FakeJujuXDGDataHomeSuite.SetUpTest(c) 36 s.Stub.ResetCalls() 37 s.store = jujuclient.NewMemStore() 38 s.stubStore = jujuclienttesting.WrapClientStore(s.store) 39 s.onRefresh = nil 40 } 41 42 func (s *SwitchSimpleSuite) refreshModels(store jujuclient.ClientStore, controllerName string) error { 43 s.MethodCall(s, "RefreshModels", store, controllerName) 44 if s.onRefresh != nil { 45 s.onRefresh() 46 } 47 return s.NextErr() 48 } 49 50 func (s *SwitchSimpleSuite) run(c *gc.C, args ...string) (*cmd.Context, error) { 51 cmd := &switchCommand{ 52 Store: s.stubStore, 53 RefreshModels: s.refreshModels, 54 } 55 return cmdtesting.RunCommand(c, modelcmd.WrapBase(cmd), args...) 56 } 57 58 func (s *SwitchSimpleSuite) TestNoArgs(c *gc.C) { 59 _, err := s.run(c) 60 c.Assert(err, gc.ErrorMatches, common.MissingModelNameError("switch").Error()) 61 } 62 63 func (s *SwitchSimpleSuite) TestNoArgsCurrentController(c *gc.C) { 64 s.addController(c, "a-controller") 65 s.store.CurrentControllerName = "a-controller" 66 ctx, err := s.run(c) 67 c.Assert(err, jc.ErrorIsNil) 68 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "a-controller\n") 69 } 70 71 func (s *SwitchSimpleSuite) TestUnknownControllerNameReturnsError(c *gc.C) { 72 s.addController(c, "a-controller") 73 s.store.CurrentControllerName = "a-controller" 74 _, err := s.run(c, "another-controller:modela") 75 c.Assert(err, gc.ErrorMatches, "controller another-controller not found") 76 } 77 78 func (s *SwitchSimpleSuite) TestNoArgsCurrentModel(c *gc.C) { 79 s.addController(c, "a-controller") 80 s.store.CurrentControllerName = "a-controller" 81 s.store.Models["a-controller"] = &jujuclient.ControllerModels{ 82 Models: map[string]jujuclient.ModelDetails{"admin/mymodel": {}}, 83 CurrentModel: "admin/mymodel", 84 } 85 ctx, err := s.run(c) 86 c.Assert(err, jc.ErrorIsNil) 87 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "a-controller:admin/mymodel\n") 88 } 89 90 func (s *SwitchSimpleSuite) TestSwitchWritesCurrentController(c *gc.C) { 91 s.addController(c, "a-controller") 92 context, err := s.run(c, "a-controller") 93 c.Assert(err, jc.ErrorIsNil) 94 c.Assert(cmdtesting.Stderr(context), gc.Equals, " -> a-controller (controller)\n") 95 s.stubStore.CheckCalls(c, []testing.StubCall{ 96 {"CurrentController", nil}, 97 {"ControllerByName", []interface{}{"a-controller"}}, 98 {"CurrentModel", []interface{}{"a-controller"}}, 99 {"SetCurrentController", []interface{}{"a-controller"}}, 100 }) 101 } 102 103 func (s *SwitchSimpleSuite) TestSwitchWithCurrentController(c *gc.C) { 104 s.store.CurrentControllerName = "old" 105 s.addController(c, "old") 106 s.addController(c, "new") 107 context, err := s.run(c, "new") 108 c.Assert(err, jc.ErrorIsNil) 109 c.Assert(cmdtesting.Stderr(context), gc.Equals, "old (controller) -> new (controller)\n") 110 } 111 112 func (s *SwitchSimpleSuite) TestSwitchLocalControllerWithCurrent(c *gc.C) { 113 s.store.CurrentControllerName = "old" 114 s.addController(c, "old") 115 s.addController(c, "new") 116 context, err := s.run(c, "new") 117 c.Assert(err, jc.ErrorIsNil) 118 c.Assert(cmdtesting.Stderr(context), gc.Equals, "old (controller) -> new (controller)\n") 119 } 120 121 func (s *SwitchSimpleSuite) TestSwitchLocalControllerWithCurrentExplicit(c *gc.C) { 122 s.store.CurrentControllerName = "old" 123 s.addController(c, "old") 124 s.addController(c, "new") 125 context, err := s.run(c, "new:") 126 c.Assert(err, jc.ErrorIsNil) 127 c.Assert(cmdtesting.Stderr(context), gc.Equals, "old (controller) -> new (controller)\n") 128 } 129 130 func (s *SwitchSimpleSuite) TestSwitchSameController(c *gc.C) { 131 s.store.CurrentControllerName = "same" 132 s.addController(c, "same") 133 context, err := s.run(c, "same") 134 c.Assert(err, jc.ErrorIsNil) 135 c.Assert(cmdtesting.Stderr(context), gc.Equals, "same (controller) (no change)\n") 136 s.stubStore.CheckCalls(c, []testing.StubCall{ 137 {"CurrentController", nil}, 138 {"ControllerByName", []interface{}{"same"}}, 139 {"CurrentModel", []interface{}{"same"}}, 140 {"ControllerByName", []interface{}{"same"}}, 141 }) 142 } 143 144 func (s *SwitchSimpleSuite) TestSwitchControllerToModel(c *gc.C) { 145 s.store.CurrentControllerName = "ctrl" 146 s.addController(c, "ctrl") 147 s.store.Models["ctrl"] = &jujuclient.ControllerModels{ 148 Models: map[string]jujuclient.ModelDetails{"admin/mymodel": {}}, 149 } 150 context, err := s.run(c, "mymodel") 151 c.Assert(err, jc.ErrorIsNil) 152 c.Assert(cmdtesting.Stderr(context), gc.Equals, "ctrl (controller) -> ctrl:admin/mymodel\n") 153 s.stubStore.CheckCalls(c, []testing.StubCall{ 154 {"CurrentController", nil}, 155 {"ControllerByName", []interface{}{"ctrl"}}, 156 {"CurrentModel", []interface{}{"ctrl"}}, 157 {"ControllerByName", []interface{}{"mymodel"}}, 158 {"AccountDetails", []interface{}{"ctrl"}}, 159 {"SetCurrentModel", []interface{}{"ctrl", "admin/mymodel"}}, 160 }) 161 c.Assert(s.store.Models["ctrl"].CurrentModel, gc.Equals, "admin/mymodel") 162 } 163 164 func (s *SwitchSimpleSuite) TestSwitchControllerToModelDifferentController(c *gc.C) { 165 s.store.CurrentControllerName = "old" 166 s.addController(c, "old") 167 s.addController(c, "new") 168 s.store.Models["new"] = &jujuclient.ControllerModels{ 169 Models: map[string]jujuclient.ModelDetails{"admin/mymodel": {}}, 170 } 171 context, err := s.run(c, "new:mymodel") 172 c.Assert(err, jc.ErrorIsNil) 173 c.Assert(cmdtesting.Stderr(context), gc.Equals, "old (controller) -> new:admin/mymodel\n") 174 s.stubStore.CheckCalls(c, []testing.StubCall{ 175 {"CurrentController", nil}, 176 {"ControllerByName", []interface{}{"old"}}, 177 {"CurrentModel", []interface{}{"old"}}, 178 {"ControllerByName", []interface{}{"new:mymodel"}}, 179 {"ControllerByName", []interface{}{"new"}}, 180 {"AccountDetails", []interface{}{"new"}}, 181 {"SetCurrentModel", []interface{}{"new", "admin/mymodel"}}, 182 {"SetCurrentController", []interface{}{"new"}}, 183 }) 184 c.Assert(s.store.Models["new"].CurrentModel, gc.Equals, "admin/mymodel") 185 } 186 187 func (s *SwitchSimpleSuite) TestSwitchControllerSameNameAsModel(c *gc.C) { 188 s.store.CurrentControllerName = "old" 189 s.addController(c, "new") 190 s.addController(c, "old") 191 s.store.Models["new"] = &jujuclient.ControllerModels{ 192 Models: map[string]jujuclient.ModelDetails{"admin/mymodel": {}, "admin/old": {}}, 193 } 194 s.store.Models["old"] = &jujuclient.ControllerModels{ 195 Models: map[string]jujuclient.ModelDetails{"admin/somemodel": {}}, 196 } 197 _, err := s.run(c, "new:mymodel") 198 c.Assert(err, jc.ErrorIsNil) 199 context, err := s.run(c, "old") 200 c.Assert(err, jc.ErrorIsNil) 201 c.Assert(cmdtesting.Stderr(context), gc.Equals, "new:admin/mymodel -> old (controller)\n") 202 } 203 204 func (s *SwitchSimpleSuite) TestSwitchControllerSameNameAsModelExplicitModel(c *gc.C) { 205 s.store.CurrentControllerName = "old" 206 s.addController(c, "new") 207 s.addController(c, "old") 208 s.store.Models["new"] = &jujuclient.ControllerModels{ 209 Models: map[string]jujuclient.ModelDetails{"admin/mymodel": {}, "admin/old": {}}, 210 } 211 s.store.Models["old"] = &jujuclient.ControllerModels{ 212 Models: map[string]jujuclient.ModelDetails{"admin/somemodel": {}}, 213 } 214 _, err := s.run(c, "new:mymodel") 215 c.Assert(err, jc.ErrorIsNil) 216 context, err := s.run(c, ":old") 217 c.Assert(err, jc.ErrorIsNil) 218 c.Assert(cmdtesting.Stderr(context), gc.Equals, "new:admin/mymodel -> new:admin/old\n") 219 } 220 221 func (s *SwitchSimpleSuite) TestSwitchLocalControllerToModelDifferentController(c *gc.C) { 222 s.store.CurrentControllerName = "old" 223 s.addController(c, "old") 224 s.addController(c, "new") 225 s.store.Models["new"] = &jujuclient.ControllerModels{ 226 Models: map[string]jujuclient.ModelDetails{"admin/mymodel": {}}, 227 } 228 context, err := s.run(c, "new:mymodel") 229 c.Assert(err, jc.ErrorIsNil) 230 c.Assert(cmdtesting.Stderr(context), gc.Equals, "old (controller) -> new:admin/mymodel\n") 231 s.stubStore.CheckCalls(c, []testing.StubCall{ 232 {"CurrentController", nil}, 233 {"ControllerByName", []interface{}{"old"}}, 234 {"CurrentModel", []interface{}{"old"}}, 235 {"ControllerByName", []interface{}{"new:mymodel"}}, 236 {"ControllerByName", []interface{}{"new"}}, 237 {"AccountDetails", []interface{}{"new"}}, 238 {"SetCurrentModel", []interface{}{"new", "admin/mymodel"}}, 239 {"SetCurrentController", []interface{}{"new"}}, 240 }) 241 c.Assert(s.store.Models["new"].CurrentModel, gc.Equals, "admin/mymodel") 242 } 243 244 func (s *SwitchSimpleSuite) TestSwitchControllerToDifferentControllerCurrentModel(c *gc.C) { 245 s.store.CurrentControllerName = "old" 246 s.addController(c, "old") 247 s.addController(c, "new") 248 s.store.Models["new"] = &jujuclient.ControllerModels{ 249 Models: map[string]jujuclient.ModelDetails{"admin/mymodel": {}}, 250 CurrentModel: "admin/mymodel", 251 } 252 context, err := s.run(c, "new:mymodel") 253 c.Assert(err, jc.ErrorIsNil) 254 c.Assert(cmdtesting.Stderr(context), gc.Equals, "old (controller) -> new:admin/mymodel\n") 255 s.stubStore.CheckCalls(c, []testing.StubCall{ 256 {"CurrentController", nil}, 257 {"ControllerByName", []interface{}{"old"}}, 258 {"CurrentModel", []interface{}{"old"}}, 259 {"ControllerByName", []interface{}{"new:mymodel"}}, 260 {"ControllerByName", []interface{}{"new"}}, 261 {"AccountDetails", []interface{}{"new"}}, 262 {"SetCurrentModel", []interface{}{"new", "admin/mymodel"}}, 263 {"SetCurrentController", []interface{}{"new"}}, 264 }) 265 } 266 267 func (s *SwitchSimpleSuite) TestSwitchToModelDifferentOwner(c *gc.C) { 268 s.store.CurrentControllerName = "same" 269 s.addController(c, "same") 270 s.store.Models["same"] = &jujuclient.ControllerModels{ 271 Models: map[string]jujuclient.ModelDetails{ 272 "admin/mymodel": {}, 273 "bianca/mymodel": {}, 274 }, 275 CurrentModel: "admin/mymodel", 276 } 277 context, err := s.run(c, "bianca/mymodel") 278 c.Assert(err, jc.ErrorIsNil) 279 c.Assert(cmdtesting.Stderr(context), gc.Equals, "same:admin/mymodel -> same:bianca/mymodel\n") 280 c.Assert(s.store.Models["same"].CurrentModel, gc.Equals, "bianca/mymodel") 281 } 282 283 func (s *SwitchSimpleSuite) TestSwitchUnknownNoCurrentController(c *gc.C) { 284 _, err := s.run(c, "unknown") 285 c.Assert(err, gc.ErrorMatches, `"unknown" is not the name of a model or controller`) 286 s.stubStore.CheckCalls(c, []testing.StubCall{ 287 {"CurrentController", nil}, 288 {"ControllerByName", []interface{}{"unknown"}}, 289 }) 290 } 291 292 func (s *SwitchSimpleSuite) TestSwitchUnknownCurrentControllerRefreshModels(c *gc.C) { 293 s.store.CurrentControllerName = "ctrl" 294 s.addController(c, "ctrl") 295 s.onRefresh = func() { 296 s.store.Models["ctrl"] = &jujuclient.ControllerModels{ 297 Models: map[string]jujuclient.ModelDetails{"admin/unknown": {}}, 298 } 299 } 300 ctx, err := s.run(c, "unknown") 301 c.Assert(err, jc.ErrorIsNil) 302 c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "ctrl (controller) -> ctrl:admin/unknown\n") 303 s.CheckCallNames(c, "RefreshModels") 304 } 305 306 func (s *SwitchSimpleSuite) TestSwitchUnknownCurrentControllerRefreshModelsStillUnknown(c *gc.C) { 307 s.store.CurrentControllerName = "ctrl" 308 s.addController(c, "ctrl") 309 _, err := s.run(c, "unknown") 310 c.Assert(err, gc.ErrorMatches, `"unknown" is not the name of a model or controller`) 311 s.CheckCallNames(c, "RefreshModels") 312 } 313 314 func (s *SwitchSimpleSuite) TestSwitchUnknownCurrentControllerRefreshModelsFails(c *gc.C) { 315 s.store.CurrentControllerName = "ctrl" 316 s.addController(c, "ctrl") 317 s.SetErrors(errors.New("not very refreshing")) 318 _, err := s.run(c, "unknown") 319 c.Assert(err, gc.ErrorMatches, "refreshing models cache: not very refreshing") 320 s.CheckCallNames(c, "RefreshModels") 321 } 322 323 func (s *SwitchSimpleSuite) TestSettingWhenModelEnvVarSet(c *gc.C) { 324 os.Setenv("JUJU_MODEL", "using-model") 325 _, err := s.run(c, "erewhemos-2") 326 c.Assert(err, gc.ErrorMatches, `cannot switch when JUJU_MODEL is overriding the model \(set to "using-model"\)`) 327 } 328 329 func (s *SwitchSimpleSuite) TestSettingWhenControllerEnvVarSet(c *gc.C) { 330 os.Setenv("JUJU_CONTROLLER", "using-controller") 331 _, err := s.run(c, "erewhemos-2") 332 c.Assert(err, gc.ErrorMatches, `cannot switch when JUJU_CONTROLLER is overriding the controller \(set to "using-controller"\)`) 333 } 334 335 func (s *SwitchSimpleSuite) TestTooManyParams(c *gc.C) { 336 _, err := s.run(c, "foo", "bar") 337 c.Assert(err, gc.ErrorMatches, `unrecognized args: ."bar".`) 338 } 339 340 func (s *SwitchSimpleSuite) addController(c *gc.C, name string) { 341 s.store.Controllers[name] = jujuclient.ControllerDetails{} 342 s.store.Accounts[name] = jujuclient.AccountDetails{ 343 User: "admin", 344 } 345 } 346 347 func (s *SwitchSimpleSuite) TestSwitchCurrentModelInStore(c *gc.C) { 348 s.store.CurrentControllerName = "same" 349 s.addController(c, "same") 350 s.store.Models["same"] = &jujuclient.ControllerModels{ 351 Models: map[string]jujuclient.ModelDetails{ 352 "admin/mymodel": {}, 353 }, 354 CurrentModel: "admin/mymodel", 355 } 356 context, err := s.run(c, "mymodel") 357 c.Assert(err, jc.ErrorIsNil) 358 c.Assert(cmdtesting.Stderr(context), gc.Equals, "same:admin/mymodel (no change)\n") 359 s.stubStore.CheckCalls(c, []testing.StubCall{ 360 {"CurrentController", nil}, 361 {"ControllerByName", []interface{}{"same"}}, 362 {"CurrentModel", []interface{}{"same"}}, 363 {"ControllerByName", []interface{}{"mymodel"}}, 364 {"AccountDetails", []interface{}{"same"}}, 365 {"SetCurrentModel", []interface{}{"same", "admin/mymodel"}}, 366 }) 367 } 368 369 func (s *SwitchSimpleSuite) TestSwitchCurrentModelNoLongerInStore(c *gc.C) { 370 s.store.CurrentControllerName = "same" 371 s.addController(c, "same") 372 s.store.Models["same"] = &jujuclient.ControllerModels{CurrentModel: "admin/mymodel"} 373 _, err := s.run(c, "mymodel") 374 c.Assert(err, gc.ErrorMatches, `"mymodel" is not the name of a model or controller`) 375 }