github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/controller/listmodels_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package controller_test 5 6 import ( 7 "regexp" 8 "time" 9 10 "github.com/juju/cmd" 11 "github.com/juju/cmd/cmdtesting" 12 "github.com/juju/collections/set" 13 gitjujutesting "github.com/juju/testing" 14 jc "github.com/juju/testing/checkers" 15 "github.com/juju/version" 16 gc "gopkg.in/check.v1" 17 "gopkg.in/juju/names.v2" 18 19 "github.com/juju/juju/api/base" 20 "github.com/juju/juju/apiserver/common" 21 "github.com/juju/juju/apiserver/params" 22 "github.com/juju/juju/cmd/juju/controller" 23 "github.com/juju/juju/core/model" 24 "github.com/juju/juju/core/status" 25 "github.com/juju/juju/jujuclient" 26 "github.com/juju/juju/testing" 27 ) 28 29 type BaseModelsSuite struct { 30 testing.FakeJujuXDGDataHomeSuite 31 api *fakeModelMgrAPIClient 32 store *jujuclient.MemStore 33 } 34 35 type ModelsSuiteV3 struct { 36 BaseModelsSuite 37 } 38 39 type ModelsSuiteV4 struct { 40 BaseModelsSuite 41 } 42 43 var _ = gc.Suite(&ModelsSuiteV3{}) 44 var _ = gc.Suite(&ModelsSuiteV4{}) 45 46 type fakeModelMgrAPIClient struct { 47 *gitjujutesting.Stub 48 49 err error 50 infos []params.ModelInfoResult 51 52 version int 53 } 54 55 func (f *fakeModelMgrAPIClient) BestAPIVersion() int { 56 f.MethodCall(f, "BestAPIVersion") 57 return f.version 58 } 59 60 func (f *fakeModelMgrAPIClient) Close() error { 61 f.MethodCall(f, "Close") 62 return nil 63 } 64 65 func (f *fakeModelMgrAPIClient) ListModels(user string) ([]base.UserModel, error) { 66 f.MethodCall(f, "ListModels", user) 67 if f.err != nil { 68 return nil, f.err 69 } 70 return f.convertInfosToUserModels(), nil 71 } 72 73 func (f *fakeModelMgrAPIClient) AllModels() ([]base.UserModel, error) { 74 f.MethodCall(f, "AllModels") 75 if f.err != nil { 76 return nil, f.err 77 } 78 return f.convertInfosToUserModels(), nil 79 } 80 81 func (f *fakeModelMgrAPIClient) ListModelSummaries(user string, all bool) ([]base.UserModelSummary, error) { 82 f.MethodCall(f, "ListModelSummaries", user, all) 83 if f.err != nil { 84 return nil, f.err 85 } 86 results := make([]base.UserModelSummary, len(f.infos)) 87 for i, info := range f.infos { 88 results[i] = base.UserModelSummary{} 89 if info.Error != nil { 90 results[i].Error = info.Error 91 continue 92 } 93 cloud, err := names.ParseCloudTag(info.Result.CloudTag) 94 if err != nil { 95 cloud = names.NewCloudTag("aws") 96 97 } 98 cred, err := names.ParseCloudCredentialTag(info.Result.CloudCredentialTag) 99 if err != nil { 100 cred = names.NewCloudCredentialTag("foo/bob/one") 101 102 } 103 owner, err := names.ParseUserTag(info.Result.OwnerTag) 104 if err != nil { 105 owner = names.NewUserTag("admin") 106 107 } 108 results[i] = base.UserModelSummary{ 109 Name: info.Result.Name, 110 Type: model.ModelType(info.Result.Type), 111 UUID: info.Result.UUID, 112 ControllerUUID: info.Result.ControllerUUID, 113 IsController: info.Result.IsController, 114 ProviderType: info.Result.ProviderType, 115 DefaultSeries: info.Result.DefaultSeries, 116 Cloud: cloud.Id(), 117 CloudRegion: info.Result.CloudRegion, 118 CloudCredential: cred.Id(), 119 Owner: owner.Id(), 120 Life: string(info.Result.Life), 121 Status: base.Status{ 122 Status: info.Result.Status.Status, 123 Info: info.Result.Status.Info, 124 Data: make(map[string]interface{}), 125 Since: info.Result.Status.Since, 126 }, 127 AgentVersion: info.Result.AgentVersion, 128 } 129 if info.Result.Migration != nil { 130 migration := info.Result.Migration 131 results[i].Migration = &base.MigrationSummary{ 132 Status: migration.Status, 133 StartTime: migration.Start, 134 EndTime: migration.End, 135 } 136 } 137 if info.Result.SLA != nil { 138 results[i].SLA = &base.SLASummary{ 139 Level: info.Result.SLA.Level, 140 Owner: info.Result.SLA.Owner, 141 } 142 } 143 if len(info.Result.Users) > 0 { 144 for _, u := range info.Result.Users { 145 if u.UserName == user { 146 results[i].ModelUserAccess = string(u.Access) 147 results[i].UserLastConnection = u.LastConnection 148 break 149 } 150 } 151 } 152 if len(info.Result.Machines) > 0 { 153 results[i].Counts = []base.EntityCount{ 154 {string(params.Machines), int64(len(info.Result.Machines))}, 155 } 156 cores := uint64(0) 157 for _, machine := range info.Result.Machines { 158 if machine.Hardware != nil && machine.Hardware.Cores != nil { 159 cores += *machine.Hardware.Cores 160 } 161 } 162 if cores > 0 { 163 results[i].Counts = append(results[i].Counts, base.EntityCount{string(params.Cores), int64(cores)}) 164 } 165 } 166 } 167 return results, nil 168 } 169 170 func (f *fakeModelMgrAPIClient) ModelInfo(tags []names.ModelTag) ([]params.ModelInfoResult, error) { 171 f.MethodCall(f, "ModelInfo", tags) 172 if f.infos != nil { 173 return f.infos, nil 174 } 175 results := make([]params.ModelInfoResult, len(tags)) 176 for i, tag := range tags { 177 for _, model := range f.infos { 178 if model.Error == nil { 179 if model.Result.UUID != tag.Id() { 180 continue 181 } 182 results[i] = model 183 } 184 } 185 } 186 return results, nil 187 } 188 189 func (f *fakeModelMgrAPIClient) convertInfosToUserModels() []base.UserModel { 190 models := make([]base.UserModel, len(f.infos)) 191 for i, info := range f.infos { 192 if info.Error == nil { 193 models[i] = base.UserModel{UUID: info.Result.UUID, Type: "local"} 194 } 195 } 196 return models 197 } 198 199 func (s *BaseModelsSuite) SetUpTest(c *gc.C) { 200 s.FakeJujuXDGDataHomeSuite.SetUpTest(c) 201 202 models := []base.UserModel{ 203 { 204 Name: "test-model1", 205 Owner: "admin", 206 UUID: "test-model1-UUID", 207 Type: model.IAAS, 208 }, { 209 Name: "test-model2", 210 Owner: "carlotta", 211 UUID: "test-model2-UUID", 212 Type: model.IAAS, 213 }, { 214 Name: "test-model3", 215 Owner: "daiwik@external", 216 UUID: "test-model3-UUID", 217 Type: model.IAAS, 218 }, 219 } 220 221 s.store = jujuclient.NewMemStore() 222 s.store.CurrentControllerName = "fake" 223 s.store.Controllers["fake"] = jujuclient.ControllerDetails{} 224 s.store.Models["fake"] = &jujuclient.ControllerModels{ 225 CurrentModel: "admin/test-model1", 226 } 227 s.store.Accounts["fake"] = jujuclient.AccountDetails{ 228 User: "admin", 229 Password: "password", 230 } 231 232 s.api = &fakeModelMgrAPIClient{ 233 Stub: &gitjujutesting.Stub{}, 234 version: 3, 235 } 236 s.api.infos = convert(models) 237 238 // Make api results interesting... 239 // 1st model 240 firstModel := s.api.infos[0].Result 241 last1 := time.Date(2015, 3, 20, 0, 0, 0, 0, time.UTC) 242 firstModel.Users = []params.ModelUserInfo{{ 243 UserName: "admin", 244 LastConnection: &last1, 245 Access: params.ModelReadAccess, 246 }} 247 //2nd model 248 secondModel := s.api.infos[1].Result 249 last2 := time.Date(2015, 3, 1, 0, 0, 0, 0, time.UTC) 250 secondModel.Users = []params.ModelUserInfo{{ 251 UserName: "admin", 252 LastConnection: &last2, 253 Access: params.ModelWriteAccess, 254 }} 255 // 3rd model 256 s.api.infos[2].Result.Status.Status = status.Destroying 257 } 258 259 func (s *BaseModelsSuite) TestModelsOwner(c *gc.C) { 260 context, err := cmdtesting.RunCommand(c, s.newCommand()) 261 c.Assert(err, jc.ErrorIsNil) 262 c.Assert(cmdtesting.Stdout(context), gc.Equals, ""+ 263 "Controller: fake\n"+ 264 "\n"+ 265 "Model Cloud/Region Type Status Access Last connection\n"+ 266 "test-model1* dummy local active read 2015-03-20\n"+ 267 "carlotta/test-model2 dummy local active write 2015-03-01\n"+ 268 "daiwik@external/test-model3 dummy local destroying - never connected\n"+ 269 "\n") 270 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 271 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 272 } 273 274 // TestModelsForAdmin tests that a model admin user will get model credential. 275 // Credential will only appear in non-tabular format - either yaml or json. 276 func (s *BaseModelsSuite) TestModelsWithCredentials(c *gc.C) { 277 for i, infoResult := range s.api.infos { 278 // let's say only some models will have credentials returned from api... 279 if i%2 == 0 { 280 infoResult.Result.CloudCredentialTag = "cloudcred-some-cloud_some-owner_some-credential" 281 } 282 } 283 284 context, err := cmdtesting.RunCommand(c, s.newCommand(), "--format=yaml") 285 c.Assert(err, jc.ErrorIsNil) 286 c.Assert(cmdtesting.Stdout(context), jc.Contains, "credential") 287 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 288 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 289 } 290 291 func (s *BaseModelsSuite) TestModelsNonOwner(c *gc.C) { 292 // Ensure fake api caters to user 'bob' 293 for _, apiInfo := range s.api.infos { 294 if apiInfo.Error == nil { 295 bobs := make([]params.ModelUserInfo, len(apiInfo.Result.Users)) 296 for i, u := range apiInfo.Result.Users { 297 u.UserName = "bob" 298 bobs[i] = u 299 } 300 apiInfo.Result.Users = bobs 301 } 302 } 303 context, err := cmdtesting.RunCommand(c, s.newCommand(), "--user", "bob") 304 c.Assert(err, jc.ErrorIsNil) 305 c.Assert(cmdtesting.Stdout(context), gc.Equals, ""+ 306 "Controller: fake\n"+ 307 "\n"+ 308 "Model Cloud/Region Type Status Access Last connection\n"+ 309 "admin/test-model1* dummy local active read 2015-03-20\n"+ 310 "carlotta/test-model2 dummy local active write 2015-03-01\n"+ 311 "daiwik@external/test-model3 dummy local destroying - never connected\n"+ 312 "\n") 313 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 314 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 315 } 316 317 func (s *BaseModelsSuite) TestModelsNoneCurrent(c *gc.C) { 318 delete(s.store.Models, "fake") 319 context, err := cmdtesting.RunCommand(c, s.newCommand()) 320 c.Assert(err, jc.ErrorIsNil) 321 c.Assert(cmdtesting.Stdout(context), gc.Equals, ""+ 322 "Controller: fake\n"+ 323 "\n"+ 324 "Model Cloud/Region Type Status Access Last connection\n"+ 325 "test-model1 dummy local active read 2015-03-20\n"+ 326 "carlotta/test-model2 dummy local active write 2015-03-01\n"+ 327 "daiwik@external/test-model3 dummy local destroying - never connected\n"+ 328 "\n") 329 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 330 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 331 } 332 333 func (s *BaseModelsSuite) TestModelsUUID(c *gc.C) { 334 one := uint64(1) 335 s.api.infos[0].Result.Machines = []params.ModelMachineInfo{ 336 {Id: "0", Hardware: ¶ms.MachineHardware{Cores: &one}}, {Id: "1"}, 337 } 338 339 context, err := cmdtesting.RunCommand(c, s.newCommand(), "--uuid") 340 c.Assert(err, jc.ErrorIsNil) 341 c.Assert(cmdtesting.Stdout(context), gc.Equals, ""+ 342 "Controller: fake\n"+ 343 "\n"+ 344 "Model UUID Cloud/Region Type Status Machines Cores Access Last connection\n"+ 345 "test-model1* test-model1-UUID dummy local active 2 1 read 2015-03-20\n"+ 346 "carlotta/test-model2 test-model2-UUID dummy local active 0 - write 2015-03-01\n"+ 347 "daiwik@external/test-model3 test-model3-UUID dummy local destroying 0 - - never connected\n"+ 348 "\n") 349 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 350 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 351 } 352 353 func (s *BaseModelsSuite) TestModelsMachineInfo(c *gc.C) { 354 one := uint64(1) 355 s.api.infos[0].Result.Machines = []params.ModelMachineInfo{ 356 {Id: "0", Hardware: ¶ms.MachineHardware{Cores: &one}}, {Id: "1"}, 357 } 358 359 context, err := cmdtesting.RunCommand(c, s.newCommand()) 360 c.Assert(err, jc.ErrorIsNil) 361 c.Assert(cmdtesting.Stdout(context), gc.Equals, ""+ 362 "Controller: fake\n"+ 363 "\n"+ 364 "Model Cloud/Region Type Status Machines Cores Access Last connection\n"+ 365 "test-model1* dummy local active 2 1 read 2015-03-20\n"+ 366 "carlotta/test-model2 dummy local active 0 - write 2015-03-01\n"+ 367 "daiwik@external/test-model3 dummy local destroying 0 - - never connected\n"+ 368 "\n") 369 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 370 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 371 } 372 373 func (s *BaseModelsSuite) TestUnrecognizedArg(c *gc.C) { 374 context, err := cmdtesting.RunCommand(c, s.newCommand(), "whoops") 375 c.Assert(err, gc.ErrorMatches, `unrecognized args: \["whoops"\]`) 376 c.Assert(cmdtesting.Stdout(context), gc.Equals, "") 377 c.Assert(cmdtesting.Stderr(context), gc.Equals, "ERROR unrecognized args: [\"whoops\"]\n") 378 s.api.CheckNoCalls(c) 379 } 380 381 func (s *BaseModelsSuite) TestInvalidUser(c *gc.C) { 382 context, err := cmdtesting.RunCommand(c, s.newCommand(), "--user", "+bob") 383 c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`user "+bob" not valid`)) 384 c.Assert(cmdtesting.Stdout(context), gc.Equals, "") 385 c.Assert(cmdtesting.Stderr(context), gc.Equals, "user \"+bob\" not valid\n") 386 s.api.CheckNoCalls(c) 387 } 388 389 func (s *BaseModelsSuite) TestModelsError(c *gc.C) { 390 s.api.err = common.ErrPerm 391 context, err := cmdtesting.RunCommand(c, s.newCommand()) 392 c.Assert(err, gc.ErrorMatches, ".*: permission denied") 393 c.Assert(cmdtesting.Stdout(context), gc.Equals, "") 394 c.Assert(cmdtesting.Stderr(context), gc.Equals, "cannot list models: permission denied\n") 395 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "Close") 396 } 397 398 func (s *BaseModelsSuite) TestWithIncompleteModels(c *gc.C) { 399 basicAndStatusInfo := createBasicModelInfo() 400 basicAndStatusInfo.Status = params.EntityStatus{ 401 Status: status.Busy, 402 } 403 404 basicAndUsersInfo := createBasicModelInfo() 405 basicAndUsersInfo.Users = []params.ModelUserInfo{ 406 {"admin", "display name", nil, params.UserAccessPermission("admin")}, 407 } 408 409 basicAndMachinesInfo := createBasicModelInfo() 410 basicAndMachinesInfo.Machines = []params.ModelMachineInfo{ 411 {Id: "2"}, 412 {Id: "12"}, 413 } 414 415 s.api.infos = []params.ModelInfoResult{ 416 {Result: createBasicModelInfo()}, 417 {Result: basicAndStatusInfo}, 418 {Result: basicAndUsersInfo}, 419 {Result: basicAndMachinesInfo}, 420 } 421 context, err := cmdtesting.RunCommand(c, s.newCommand()) 422 c.Assert(err, jc.ErrorIsNil) 423 c.Assert(cmdtesting.Stdout(context), gc.Equals, ` 424 Controller: fake 425 426 Model Cloud/Region Type Status Machines Access Last connection 427 owner/basic-model altostratus/mid-level local - 0 - never connected 428 owner/basic-model altostratus/mid-level local busy 0 - never connected 429 owner/basic-model altostratus/mid-level local - 0 admin never connected 430 owner/basic-model altostratus/mid-level local - 2 - never connected 431 432 `[1:]) 433 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 434 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 435 } 436 437 func (s *BaseModelsSuite) TestListModelsWithAgent(c *gc.C) { 438 basicInfo := createBasicModelInfo() 439 s.assertAgentVersionPresent(c, basicInfo, jc.Contains) 440 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 441 } 442 443 func (s *BaseModelsSuite) TestListModelsWithNoAgent(c *gc.C) { 444 basicInfo := createBasicModelInfo() 445 basicInfo.AgentVersion = nil 446 s.assertAgentVersionPresent(c, basicInfo, gc.Not(jc.Contains)) 447 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 448 } 449 450 func (s *BaseModelsSuite) TestNoModelsMessage(c *gc.C) { 451 assertExpectedOutput := func(context *cmd.Context) { 452 c.Assert(cmdtesting.Stdout(context), gc.Equals, ` 453 Controller: fake 454 455 Model Cloud/Region Type Status Access Last connection 456 457 `[1:]) 458 c.Assert(cmdtesting.Stderr(context), gc.Equals, controller.NoModelsMessage+"\n") 459 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 460 } 461 462 s.api.infos = nil 463 context, err := cmdtesting.RunCommand(c, s.newCommand()) 464 c.Assert(err, jc.ErrorIsNil) 465 assertExpectedOutput(context) 466 467 s.api.ResetCalls() 468 469 s.api.infos = []params.ModelInfoResult{} 470 context, err = cmdtesting.RunCommand(c, s.newCommand()) 471 c.Assert(err, jc.ErrorIsNil) 472 assertExpectedOutput(context) 473 } 474 475 func (s *BaseModelsSuite) newCommand() cmd.Command { 476 return controller.NewListModelsCommandForTest(s.api, s.api, s.store) 477 } 478 479 func (s *BaseModelsSuite) assertAgentVersionPresent(c *gc.C, testInfo *params.ModelInfo, checker gc.Checker) { 480 s.api.infos = []params.ModelInfoResult{ 481 {Result: testInfo}, 482 } 483 context, err := cmdtesting.RunCommand(c, s.newCommand(), "--format=yaml") 484 c.Assert(err, jc.ErrorIsNil) 485 c.Assert(cmdtesting.Stdout(context), checker, "agent-version") 486 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 487 } 488 489 func (s *BaseModelsSuite) checkAPICalls(c *gc.C, expectedCalls ...string) { 490 actualCalls := []string{} 491 492 switch s.api.version { 493 case 4: 494 oldCalls := set.NewStrings("ModelInfo", "AllModels", "ListModels") 495 // need to add Close here too because in previous implementations it could 496 // have been called more than once. 497 oldCalls.Add("Close") 498 for _, call := range expectedCalls { 499 if !oldCalls.Contains(call) { 500 actualCalls = append(actualCalls, call) 501 } 502 } 503 actualCalls = append(actualCalls, "ListModelSummaries", "Close") 504 default: 505 actualCalls = expectedCalls 506 } 507 508 s.api.CheckCallNames(c, actualCalls...) 509 } 510 511 func createBasicModelInfo() *params.ModelInfo { 512 agentVersion, _ := version.Parse("2.55.5") 513 return ¶ms.ModelInfo{ 514 Name: "basic-model", 515 UUID: testing.ModelTag.Id(), 516 Type: "iaas", 517 ProviderType: "local", 518 ControllerUUID: testing.ControllerTag.Id(), 519 IsController: false, 520 OwnerTag: names.NewUserTag("owner").String(), 521 Life: params.Dead, 522 CloudTag: names.NewCloudTag("altostratus").String(), 523 CloudRegion: "mid-level", 524 AgentVersion: &agentVersion, 525 } 526 } 527 528 func convert(models []base.UserModel) []params.ModelInfoResult { 529 agentVersion, _ := version.Parse("2.55.5") 530 infoResults := make([]params.ModelInfoResult, len(models)) 531 for i, model := range models { 532 infoResult := params.ModelInfoResult{} 533 infoResult.Result = ¶ms.ModelInfo{ 534 Name: model.Name, 535 UUID: model.UUID, 536 Type: model.Type.String(), 537 OwnerTag: names.NewUserTag(model.Owner).String(), 538 CloudTag: "cloud-dummy", 539 ProviderType: "local", 540 AgentVersion: &agentVersion, 541 Status: params.EntityStatus{Status: status.Active}, 542 } 543 infoResults[i] = infoResult 544 } 545 return infoResults 546 } 547 548 func (s *ModelsSuiteV3) SetUpTest(c *gc.C) { 549 s.BaseModelsSuite.SetUpTest(c) 550 // re-run all the test for ModelManager v3 551 s.BaseModelsSuite.api.version = 3 552 } 553 554 func (s *ModelsSuiteV3) TestModelsWithOneUnauthorised(c *gc.C) { 555 c.Assert(s.store.Models["fake"].Models, gc.HasLen, 0) 556 s.api.infos[2].Error = ¶ms.Error{ 557 Message: "permission denied", 558 Code: params.CodeUnauthorized, 559 } 560 561 context, err := cmdtesting.RunCommand(c, s.newCommand()) 562 c.Assert(err, jc.ErrorIsNil) 563 c.Assert(cmdtesting.Stdout(context), gc.Equals, ""+ 564 "Controller: fake\n"+ 565 "\n"+ 566 "Model Cloud/Region Type Status Access Last connection\n"+ 567 "test-model1* dummy local active read 2015-03-20\n"+ 568 "carlotta/test-model2 dummy local active write 2015-03-01\n"+ 569 "\n") 570 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 571 c.Assert(s.store.Models["fake"].Models, gc.DeepEquals, map[string]jujuclient.ModelDetails{ 572 "admin/test-model1": {ModelUUID: "test-model1-UUID", ModelType: model.IAAS}, 573 "carlotta/test-model2": {ModelUUID: "test-model2-UUID", ModelType: model.IAAS}, 574 }) 575 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 576 } 577 578 func (s *ModelsSuiteV3) TestModelsJson(c *gc.C) { 579 context, err := cmdtesting.RunCommand(c, s.newCommand(), "--format", "json") 580 c.Assert(err, jc.ErrorIsNil) 581 c.Assert(cmdtesting.Stdout(context), gc.Equals, `{"models":[{"name":"admin/test-model1","short-name":"test-model1","model-uuid":"test-model1-UUID","model-type":"iaas","controller-uuid":"","controller-name":"fake","is-controller":false,"owner":"admin","cloud":"dummy","type":"local","life":"","status":{"current":"active"},"users":{"admin":{"access":"read","last-connection":"2015-03-20"}},"agent-version":"2.55.5"},{"name":"carlotta/test-model2","short-name":"test-model2","model-uuid":"test-model2-UUID","model-type":"iaas","controller-uuid":"","controller-name":"fake","is-controller":false,"owner":"carlotta","cloud":"dummy","type":"local","life":"","status":{"current":"active"},"users":{"admin":{"access":"write","last-connection":"2015-03-01"}},"agent-version":"2.55.5"},{"name":"daiwik@external/test-model3","short-name":"test-model3","model-uuid":"test-model3-UUID","model-type":"iaas","controller-uuid":"","controller-name":"fake","is-controller":false,"owner":"daiwik@external","cloud":"dummy","type":"local","life":"","status":{"current":"destroying"},"agent-version":"2.55.5"}],"current-model":"test-model1"} 582 `) 583 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 584 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 585 } 586 587 func (s *ModelsSuiteV3) TestModelsYaml(c *gc.C) { 588 context, err := cmdtesting.RunCommand(c, s.newCommand(), "--format", "yaml") 589 c.Assert(err, jc.ErrorIsNil) 590 c.Assert(cmdtesting.Stdout(context), gc.Equals, ` 591 models: 592 - name: admin/test-model1 593 short-name: test-model1 594 model-uuid: test-model1-UUID 595 model-type: iaas 596 controller-uuid: "" 597 controller-name: fake 598 is-controller: false 599 owner: admin 600 cloud: dummy 601 type: local 602 life: "" 603 status: 604 current: active 605 users: 606 admin: 607 access: read 608 last-connection: "2015-03-20" 609 agent-version: 2.55.5 610 - name: carlotta/test-model2 611 short-name: test-model2 612 model-uuid: test-model2-UUID 613 model-type: iaas 614 controller-uuid: "" 615 controller-name: fake 616 is-controller: false 617 owner: carlotta 618 cloud: dummy 619 type: local 620 life: "" 621 status: 622 current: active 623 users: 624 admin: 625 access: write 626 last-connection: "2015-03-01" 627 agent-version: 2.55.5 628 - name: daiwik@external/test-model3 629 short-name: test-model3 630 model-uuid: test-model3-UUID 631 model-type: iaas 632 controller-uuid: "" 633 controller-name: fake 634 is-controller: false 635 owner: daiwik@external 636 cloud: dummy 637 type: local 638 life: "" 639 status: 640 current: destroying 641 agent-version: 2.55.5 642 current-model: test-model1 643 `[1:]) 644 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 645 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 646 } 647 648 func (s *ModelsSuiteV3) TestAllModels(c *gc.C) { 649 c.Assert(s.store.Models["fake"].Models, gc.HasLen, 0) 650 context, err := cmdtesting.RunCommand(c, s.newCommand(), "--all") 651 c.Assert(err, jc.ErrorIsNil) 652 c.Assert(cmdtesting.Stdout(context), gc.Equals, ""+ 653 "Controller: fake\n"+ 654 "\n"+ 655 "Model Cloud/Region Type Status Access Last connection\n"+ 656 "test-model1* dummy local active read 2015-03-20\n"+ 657 "carlotta/test-model2 dummy local active write 2015-03-01\n"+ 658 "daiwik@external/test-model3 dummy local destroying - never connected\n"+ 659 "\n") 660 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 661 c.Assert(s.store.Models["fake"].Models, gc.DeepEquals, map[string]jujuclient.ModelDetails{ 662 "admin/test-model1": {ModelUUID: "test-model1-UUID", ModelType: model.IAAS}, 663 "carlotta/test-model2": {ModelUUID: "test-model2-UUID", ModelType: model.IAAS}, 664 "daiwik@external/test-model3": {ModelUUID: "test-model3-UUID", ModelType: model.IAAS}, 665 }) 666 s.api.CheckCallNames(c, "BestAPIVersion", "AllModels", "Close", "ModelInfo", "Close") 667 } 668 669 func (s *ModelsSuiteV4) SetUpTest(c *gc.C) { 670 s.BaseModelsSuite.SetUpTest(c) 671 // re-run all the test for ModelManager v4 672 s.BaseModelsSuite.api.version = 4 673 } 674 675 func (s *ModelsSuiteV4) TestModelsJson(c *gc.C) { 676 context, err := cmdtesting.RunCommand(c, s.newCommand(), "--format", "json") 677 c.Assert(err, jc.ErrorIsNil) 678 c.Assert(cmdtesting.Stdout(context), gc.Equals, `{"models":[{"name":"admin/test-model1","short-name":"test-model1","model-uuid":"test-model1-UUID","model-type":"iaas","controller-uuid":"","controller-name":"fake","is-controller":false,"owner":"admin","cloud":"dummy","credential":{"name":"one","owner":"bob","cloud":"foo"},"type":"local","life":"","status":{"current":"active"},"access":"read","last-connection":"2015-03-20","agent-version":"2.55.5"},{"name":"carlotta/test-model2","short-name":"test-model2","model-uuid":"test-model2-UUID","model-type":"iaas","controller-uuid":"","controller-name":"fake","is-controller":false,"owner":"carlotta","cloud":"dummy","credential":{"name":"one","owner":"bob","cloud":"foo"},"type":"local","life":"","status":{"current":"active"},"access":"write","last-connection":"2015-03-01","agent-version":"2.55.5"},{"name":"daiwik@external/test-model3","short-name":"test-model3","model-uuid":"test-model3-UUID","model-type":"iaas","controller-uuid":"","controller-name":"fake","is-controller":false,"owner":"daiwik@external","cloud":"dummy","credential":{"name":"one","owner":"bob","cloud":"foo"},"type":"local","life":"","status":{"current":"destroying"},"access":"","last-connection":"never connected","agent-version":"2.55.5"}],"current-model":"test-model1"} 679 `) 680 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 681 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 682 } 683 684 func (s *ModelsSuiteV4) TestModelsYaml(c *gc.C) { 685 context, err := cmdtesting.RunCommand(c, s.newCommand(), "--format", "yaml") 686 c.Assert(err, jc.ErrorIsNil) 687 c.Assert(cmdtesting.Stdout(context), gc.Equals, ` 688 models: 689 - name: admin/test-model1 690 short-name: test-model1 691 model-uuid: test-model1-UUID 692 model-type: iaas 693 controller-uuid: "" 694 controller-name: fake 695 is-controller: false 696 owner: admin 697 cloud: dummy 698 credential: 699 name: one 700 owner: bob 701 cloud: foo 702 type: local 703 life: "" 704 status: 705 current: active 706 access: read 707 last-connection: "2015-03-20" 708 agent-version: 2.55.5 709 - name: carlotta/test-model2 710 short-name: test-model2 711 model-uuid: test-model2-UUID 712 model-type: iaas 713 controller-uuid: "" 714 controller-name: fake 715 is-controller: false 716 owner: carlotta 717 cloud: dummy 718 credential: 719 name: one 720 owner: bob 721 cloud: foo 722 type: local 723 life: "" 724 status: 725 current: active 726 access: write 727 last-connection: "2015-03-01" 728 agent-version: 2.55.5 729 - name: daiwik@external/test-model3 730 short-name: test-model3 731 model-uuid: test-model3-UUID 732 model-type: iaas 733 controller-uuid: "" 734 controller-name: fake 735 is-controller: false 736 owner: daiwik@external 737 cloud: dummy 738 credential: 739 name: one 740 owner: bob 741 cloud: foo 742 type: local 743 life: "" 744 status: 745 current: destroying 746 access: "" 747 last-connection: never connected 748 agent-version: 2.55.5 749 current-model: test-model1 750 `[1:]) 751 c.Assert(cmdtesting.Stderr(context), gc.Equals, "") 752 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 753 } 754 755 func (s *ModelsSuiteV4) TestModelsWithOneModelInError(c *gc.C) { 756 c.Assert(s.store.Models["fake"].Models, gc.HasLen, 0) 757 s.api.infos[2].Error = ¶ms.Error{ 758 Message: "some model error", 759 } 760 761 context, err := cmdtesting.RunCommand(c, s.newCommand()) 762 c.Assert(err, jc.ErrorIsNil) 763 c.Assert(cmdtesting.Stdout(context), gc.Equals, ""+ 764 "Controller: fake\n"+ 765 "\n"+ 766 "Model Cloud/Region Type Status Access Last connection\n"+ 767 "test-model1* dummy local active read 2015-03-20\n"+ 768 "carlotta/test-model2 dummy local active write 2015-03-01\n"+ 769 "\n") 770 c.Assert(cmdtesting.Stderr(context), gc.Equals, "some model error\n") 771 c.Assert(s.store.Models["fake"].Models, gc.DeepEquals, map[string]jujuclient.ModelDetails{ 772 "admin/test-model1": {ModelUUID: "test-model1-UUID", ModelType: model.IAAS}, 773 "carlotta/test-model2": {ModelUUID: "test-model2-UUID", ModelType: model.IAAS}, 774 }) 775 s.checkAPICalls(c, "BestAPIVersion", "ListModels", "ModelInfo", "Close") 776 } 777 778 func (s *ModelsSuiteV4) TestAllModels(c *gc.C) { 779 assertAPICallsArgs := func(all bool) { 780 s.api.CheckCalls(c, []gitjujutesting.StubCall{{ 781 "BestAPIVersion", []interface{}{}, 782 }, { 783 "ListModelSummaries", []interface{}{"admin", all}, 784 }, { 785 "Close", []interface{}{}, 786 }, 787 }) 788 } 789 790 _, err := cmdtesting.RunCommand(c, s.newCommand(), "--all") 791 c.Assert(err, jc.ErrorIsNil) 792 assertAPICallsArgs(true) 793 794 s.api.ResetCalls() 795 796 _, err = cmdtesting.RunCommand(c, s.newCommand()) 797 c.Assert(err, jc.ErrorIsNil) 798 assertAPICallsArgs(false) 799 }