github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/action/action_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package action_test 5 6 import ( 7 "fmt" 8 "testing" 9 10 "github.com/juju/names" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 "gopkg.in/juju/charm.v5" 14 15 "github.com/juju/juju/apiserver/action" 16 "github.com/juju/juju/apiserver/common" 17 "github.com/juju/juju/apiserver/params" 18 apiservertesting "github.com/juju/juju/apiserver/testing" 19 jujutesting "github.com/juju/juju/juju/testing" 20 "github.com/juju/juju/state" 21 coretesting "github.com/juju/juju/testing" 22 jujuFactory "github.com/juju/juju/testing/factory" 23 ) 24 25 func TestAll(t *testing.T) { 26 coretesting.MgoTestPackage(t) 27 } 28 29 type actionSuite struct { 30 jujutesting.JujuConnSuite 31 32 action *action.ActionAPI 33 authorizer apiservertesting.FakeAuthorizer 34 resources *common.Resources 35 36 charm *state.Charm 37 machine0 *state.Machine 38 machine1 *state.Machine 39 dummy *state.Service 40 wordpress *state.Service 41 mysql *state.Service 42 wordpressUnit *state.Unit 43 mysqlUnit *state.Unit 44 } 45 46 var _ = gc.Suite(&actionSuite{}) 47 48 func (s *actionSuite) SetUpTest(c *gc.C) { 49 s.JujuConnSuite.SetUpTest(c) 50 51 s.authorizer = apiservertesting.FakeAuthorizer{ 52 Tag: s.AdminUserTag(c), 53 } 54 var err error 55 s.action, err = action.NewActionAPI(s.State, nil, s.authorizer) 56 c.Assert(err, jc.ErrorIsNil) 57 58 factory := jujuFactory.NewFactory(s.State) 59 60 s.charm = factory.MakeCharm(c, &jujuFactory.CharmParams{ 61 Name: "wordpress", 62 }) 63 64 s.dummy = factory.MakeService(c, &jujuFactory.ServiceParams{ 65 Name: "dummy", 66 Charm: factory.MakeCharm(c, &jujuFactory.CharmParams{ 67 Name: "dummy", 68 }), 69 Creator: s.AdminUserTag(c), 70 }) 71 s.wordpress = factory.MakeService(c, &jujuFactory.ServiceParams{ 72 Name: "wordpress", 73 Charm: s.charm, 74 Creator: s.AdminUserTag(c), 75 }) 76 s.machine0 = factory.MakeMachine(c, &jujuFactory.MachineParams{ 77 Series: "quantal", 78 Jobs: []state.MachineJob{state.JobHostUnits, state.JobManageEnviron}, 79 }) 80 s.wordpressUnit = factory.MakeUnit(c, &jujuFactory.UnitParams{ 81 Service: s.wordpress, 82 Machine: s.machine0, 83 }) 84 85 mysqlCharm := factory.MakeCharm(c, &jujuFactory.CharmParams{ 86 Name: "mysql", 87 }) 88 s.mysql = factory.MakeService(c, &jujuFactory.ServiceParams{ 89 Name: "mysql", 90 Charm: mysqlCharm, 91 Creator: s.AdminUserTag(c), 92 }) 93 s.machine1 = factory.MakeMachine(c, &jujuFactory.MachineParams{ 94 Series: "quantal", 95 Jobs: []state.MachineJob{state.JobHostUnits}, 96 }) 97 s.mysqlUnit = factory.MakeUnit(c, &jujuFactory.UnitParams{ 98 Service: s.mysql, 99 Machine: s.machine1, 100 }) 101 s.resources = common.NewResources() 102 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 103 } 104 105 func (s *actionSuite) TestActions(c *gc.C) { 106 arg := params.Actions{ 107 Actions: []params.Action{ 108 {Receiver: s.wordpressUnit.Tag().String(), Name: "fakeaction", Parameters: map[string]interface{}{}}, 109 {Receiver: s.mysqlUnit.Tag().String(), Name: "fakeaction", Parameters: map[string]interface{}{}}, 110 {Receiver: s.wordpressUnit.Tag().String(), Name: "fakeaction", Parameters: map[string]interface{}{"foo": 1, "bar": "please"}}, 111 {Receiver: s.mysqlUnit.Tag().String(), Name: "fakeaction", Parameters: map[string]interface{}{"baz": true}}, 112 }} 113 114 r, err := s.action.Enqueue(arg) 115 c.Assert(err, gc.Equals, nil) 116 c.Assert(r.Results, gc.HasLen, len(arg.Actions)) 117 118 entities := make([]params.Entity, len(r.Results)) 119 for i, result := range r.Results { 120 entities[i] = params.Entity{Tag: result.Action.Tag} 121 } 122 123 actions, err := s.action.Actions(params.Entities{Entities: entities}) 124 c.Assert(err, gc.Equals, nil) 125 126 c.Assert(len(actions.Results), gc.Equals, len(entities)) 127 for i, got := range actions.Results { 128 c.Logf("check index %d (%s: %s)", i, entities[i].Tag, arg.Actions[i].Name) 129 c.Assert(got.Error, gc.Equals, (*params.Error)(nil)) 130 c.Assert(got.Action, gc.Not(gc.Equals), (*params.Action)(nil)) 131 c.Assert(got.Action.Tag, gc.Equals, entities[i].Tag) 132 c.Assert(got.Action.Name, gc.Equals, arg.Actions[i].Name) 133 c.Assert(got.Action.Receiver, gc.Equals, arg.Actions[i].Receiver) 134 c.Assert(got.Action.Parameters, gc.DeepEquals, arg.Actions[i].Parameters) 135 c.Assert(got.Status, gc.Equals, params.ActionPending) 136 c.Assert(got.Message, gc.Equals, "") 137 c.Assert(got.Output, gc.DeepEquals, map[string]interface{}{}) 138 } 139 } 140 141 func (s *actionSuite) TestFindActionTagsByPrefix(c *gc.C) { 142 // NOTE: full testing with multiple matches has been moved to state package. 143 arg := params.Actions{Actions: []params.Action{{Receiver: s.wordpressUnit.Tag().String(), Name: "fakeaction", Parameters: map[string]interface{}{}}}} 144 r, err := s.action.Enqueue(arg) 145 c.Assert(err, gc.Equals, nil) 146 c.Assert(r.Results, gc.HasLen, len(arg.Actions)) 147 148 actionTag, err := names.ParseActionTag(r.Results[0].Action.Tag) 149 c.Assert(err, gc.Equals, nil) 150 prefix := actionTag.Id()[:7] 151 tags, err := s.action.FindActionTagsByPrefix(params.FindTags{Prefixes: []string{prefix}}) 152 c.Assert(err, gc.Equals, nil) 153 154 entities, ok := tags.Matches[prefix] 155 c.Assert(ok, gc.Equals, true) 156 c.Assert(len(entities), gc.Equals, 1) 157 c.Assert(entities[0].Tag, gc.Equals, actionTag.String()) 158 } 159 160 func (s *actionSuite) TestEnqueue(c *gc.C) { 161 // Make sure no Actions already exist on wordpress Unit. 162 actions, err := s.wordpressUnit.Actions() 163 c.Assert(err, jc.ErrorIsNil) 164 c.Assert(actions, gc.HasLen, 0) 165 166 // Make sure no Actions already exist on mysql Unit. 167 actions, err = s.mysqlUnit.Actions() 168 c.Assert(err, jc.ErrorIsNil) 169 c.Assert(actions, gc.HasLen, 0) 170 171 // Add Actions. 172 expectedName := "fakeaction" 173 expectedParameters := map[string]interface{}{"kan jy nie": "verstaand"} 174 arg := params.Actions{ 175 Actions: []params.Action{ 176 // No receiver. 177 {Name: "fakeaction"}, 178 // Good. 179 {Receiver: s.wordpressUnit.Tag().String(), Name: expectedName, Parameters: expectedParameters}, 180 // Service tag instead of Unit tag. 181 {Receiver: s.wordpress.Tag().String(), Name: "fakeaction"}, 182 // Missing name. 183 {Receiver: s.mysqlUnit.Tag().String(), Parameters: expectedParameters}, 184 }, 185 } 186 res, err := s.action.Enqueue(arg) 187 c.Assert(err, jc.ErrorIsNil) 188 c.Assert(res.Results, gc.HasLen, 4) 189 190 expectedError := ¶ms.Error{Message: "id not found", Code: "not found"} 191 emptyActionTag := names.ActionTag{} 192 c.Assert(res.Results[0].Error, gc.DeepEquals, expectedError) 193 c.Assert(res.Results[0].Action, gc.IsNil) 194 195 c.Assert(res.Results[1].Error, gc.IsNil) 196 c.Assert(res.Results[1].Action, gc.NotNil) 197 c.Assert(res.Results[1].Action.Receiver, gc.Equals, s.wordpressUnit.Tag().String()) 198 c.Assert(res.Results[1].Action.Tag, gc.Not(gc.Equals), emptyActionTag) 199 200 c.Assert(res.Results[2].Error, gc.DeepEquals, expectedError) 201 c.Assert(res.Results[2].Action, gc.IsNil) 202 203 c.Assert(res.Results[3].Error, gc.ErrorMatches, "no action name given") 204 c.Assert(res.Results[3].Action, gc.IsNil) 205 206 // Make sure an Action was enqueued for the wordpress Unit. 207 actions, err = s.wordpressUnit.Actions() 208 c.Assert(err, jc.ErrorIsNil) 209 c.Assert(actions, gc.HasLen, 1) 210 c.Assert(actions[0].Name(), gc.Equals, expectedName) 211 c.Assert(actions[0].Parameters(), gc.DeepEquals, expectedParameters) 212 c.Assert(actions[0].Receiver(), gc.Equals, s.wordpressUnit.Name()) 213 214 // Make sure an Action was not enqueued for the mysql Unit. 215 actions, err = s.mysqlUnit.Actions() 216 c.Assert(err, jc.ErrorIsNil) 217 c.Assert(actions, gc.HasLen, 0) 218 } 219 220 type testCaseAction struct { 221 Name string 222 Parameters map[string]interface{} 223 Execute bool 224 } 225 226 type receiverGroup struct { 227 ExpectedError *params.Error 228 Receiver names.Tag 229 Actions []testCaseAction 230 } 231 232 type testCase struct { 233 Groups []receiverGroup 234 } 235 236 var testCases = []testCase{{ 237 Groups: []receiverGroup{ 238 { 239 ExpectedError: ¶ms.Error{Message: "id not found", Code: "not found"}, 240 Receiver: names.NewServiceTag("wordpress"), 241 Actions: []testCaseAction{}, 242 }, { 243 Receiver: names.NewUnitTag("wordpress/0"), 244 Actions: []testCaseAction{ 245 {"fakeaction", map[string]interface{}{}, false}, 246 {"fakeaction", map[string]interface{}{"asdf": 3}, true}, 247 {"fakeaction", map[string]interface{}{"qwer": "ty"}, false}, 248 }, 249 }, { 250 Receiver: names.NewUnitTag("mysql/0"), 251 Actions: []testCaseAction{ 252 {"fakeaction", map[string]interface{}{"zxcv": false}, false}, 253 {"fakeaction", map[string]interface{}{}, true}, 254 }, 255 }, 256 }, 257 }} 258 259 func (s *actionSuite) TestListAll(c *gc.C) { 260 for _, testCase := range testCases { 261 // set up query args 262 arg := params.Entities{Entities: make([]params.Entity, len(testCase.Groups))} 263 264 // prepare state, and set up expectations. 265 expected := params.ActionsByReceivers{Actions: make([]params.ActionsByReceiver, len(testCase.Groups))} 266 for i, group := range testCase.Groups { 267 arg.Entities[i] = params.Entity{Tag: group.Receiver.String()} 268 269 cur := &expected.Actions[i] 270 cur.Error = group.ExpectedError 271 272 // short circuit and bail if the ActionReceiver isn't a Unit. 273 if _, ok := group.Receiver.(names.UnitTag); !ok { 274 continue 275 } 276 277 cur.Receiver = group.Receiver.String() 278 cur.Actions = make([]params.ActionResult, len(group.Actions)) 279 280 // get Unit (ActionReceiver) for this Pair in the test case. 281 unit, err := s.State.Unit(group.Receiver.Id()) 282 c.Assert(err, jc.ErrorIsNil) 283 assertReadyToTest(c, unit) 284 285 // add each action from the test case. 286 for j, action := range group.Actions { 287 // add action. 288 added, err := unit.AddAction(action.Name, action.Parameters) 289 c.Assert(err, jc.ErrorIsNil) 290 291 // make expectation 292 exp := &cur.Actions[j] 293 exp.Action = ¶ms.Action{ 294 Tag: added.ActionTag().String(), 295 Name: action.Name, 296 Parameters: action.Parameters, 297 } 298 exp.Status = params.ActionPending 299 exp.Output = map[string]interface{}{} 300 301 if action.Execute { 302 status := state.ActionCompleted 303 output := map[string]interface{}{"output": "blah, blah, blah"} 304 message := "success" 305 306 fa, err := added.Finish(state.ActionResults{Status: status, Results: output, Message: message}) 307 c.Assert(err, jc.ErrorIsNil) 308 c.Assert(fa.Status(), gc.Equals, state.ActionCompleted) 309 310 exp.Status = string(status) 311 exp.Message = message 312 exp.Output = output 313 } 314 } 315 } 316 317 // validate assumptions. 318 actionList, err := s.action.ListAll(arg) 319 c.Assert(err, jc.ErrorIsNil) 320 assertSame(c, actionList, expected) 321 } 322 } 323 324 func (s *actionSuite) TestListPending(c *gc.C) { 325 for _, testCase := range testCases { 326 // set up query args 327 arg := params.Entities{Entities: make([]params.Entity, len(testCase.Groups))} 328 329 // prepare state, and set up expectations. 330 expected := params.ActionsByReceivers{Actions: make([]params.ActionsByReceiver, len(testCase.Groups))} 331 for i, group := range testCase.Groups { 332 arg.Entities[i] = params.Entity{Tag: group.Receiver.String()} 333 334 cur := &expected.Actions[i] 335 cur.Error = group.ExpectedError 336 337 // short circuit and bail if the ActionReceiver isn't a Unit. 338 if _, ok := group.Receiver.(names.UnitTag); !ok { 339 continue 340 } 341 342 cur.Receiver = group.Receiver.String() 343 cur.Actions = []params.ActionResult{} 344 345 // get Unit (ActionReceiver) for this Pair in the test case. 346 unit, err := s.State.Unit(group.Receiver.Id()) 347 c.Assert(err, jc.ErrorIsNil) 348 assertReadyToTest(c, unit) 349 350 // add each action from the test case. 351 for _, action := range group.Actions { 352 // add action. 353 added, err := unit.AddAction(action.Name, action.Parameters) 354 c.Assert(err, jc.ErrorIsNil) 355 356 if action.Execute { 357 status := state.ActionCompleted 358 output := map[string]interface{}{"output": "blah, blah, blah"} 359 message := "success" 360 361 fa, err := added.Finish(state.ActionResults{Status: status, Results: output, Message: message}) 362 c.Assert(err, jc.ErrorIsNil) 363 c.Assert(fa.Status(), gc.Equals, state.ActionCompleted) 364 } else { 365 // add expectation 366 exp := params.ActionResult{ 367 Action: ¶ms.Action{ 368 Tag: added.ActionTag().String(), 369 Name: action.Name, 370 Parameters: action.Parameters, 371 }, 372 Status: params.ActionPending, 373 Output: map[string]interface{}{}, 374 } 375 cur.Actions = append(cur.Actions, exp) 376 } 377 } 378 } 379 380 // validate assumptions. 381 actionList, err := s.action.ListPending(arg) 382 c.Assert(err, jc.ErrorIsNil) 383 assertSame(c, actionList, expected) 384 } 385 } 386 387 func (s *actionSuite) TestListRunning(c *gc.C) { 388 for _, testCase := range testCases { 389 // set up query args 390 arg := params.Entities{Entities: make([]params.Entity, len(testCase.Groups))} 391 392 // prepare state, and set up expectations. 393 expected := params.ActionsByReceivers{Actions: make([]params.ActionsByReceiver, len(testCase.Groups))} 394 for i, group := range testCase.Groups { 395 arg.Entities[i] = params.Entity{Tag: group.Receiver.String()} 396 397 cur := &expected.Actions[i] 398 cur.Error = group.ExpectedError 399 400 // short circuit and bail if the ActionReceiver isn't a Unit. 401 if _, ok := group.Receiver.(names.UnitTag); !ok { 402 continue 403 } 404 405 cur.Receiver = group.Receiver.String() 406 cur.Actions = []params.ActionResult{} 407 408 // get Unit (ActionReceiver) for this Pair in the test case. 409 unit, err := s.State.Unit(group.Receiver.Id()) 410 c.Assert(err, jc.ErrorIsNil) 411 assertReadyToTest(c, unit) 412 413 // add each action from the test case. 414 for _, action := range group.Actions { 415 // add action. 416 added, err := unit.AddAction(action.Name, action.Parameters) 417 c.Assert(err, jc.ErrorIsNil) 418 419 if action.Execute { 420 started, err := added.Begin() 421 c.Assert(err, jc.ErrorIsNil) 422 c.Assert(started.Status(), gc.Equals, state.ActionRunning) 423 424 // add expectation 425 exp := params.ActionResult{ 426 Action: ¶ms.Action{ 427 Tag: added.ActionTag().String(), 428 Name: action.Name, 429 Parameters: action.Parameters, 430 }, 431 Status: params.ActionRunning, 432 Output: map[string]interface{}{}, 433 } 434 cur.Actions = append(cur.Actions, exp) 435 } 436 } 437 } 438 439 // validate assumptions. 440 actionList, err := s.action.ListRunning(arg) 441 c.Assert(err, jc.ErrorIsNil) 442 assertSame(c, actionList, expected) 443 } 444 } 445 446 func (s *actionSuite) TestListCompleted(c *gc.C) { 447 for _, testCase := range testCases { 448 // set up query args 449 arg := params.Entities{Entities: make([]params.Entity, len(testCase.Groups))} 450 451 // prepare state, and set up expectations. 452 expected := params.ActionsByReceivers{Actions: make([]params.ActionsByReceiver, len(testCase.Groups))} 453 for i, group := range testCase.Groups { 454 arg.Entities[i] = params.Entity{Tag: group.Receiver.String()} 455 456 cur := &expected.Actions[i] 457 cur.Error = group.ExpectedError 458 459 // short circuit and bail if the ActionReceiver isn't a Unit. 460 if _, ok := group.Receiver.(names.UnitTag); !ok { 461 continue 462 } 463 464 cur.Receiver = group.Receiver.String() 465 cur.Actions = []params.ActionResult{} 466 467 // get Unit (ActionReceiver) for this Pair in the test case. 468 unit, err := s.State.Unit(group.Receiver.Id()) 469 c.Assert(err, jc.ErrorIsNil) 470 assertReadyToTest(c, unit) 471 472 // add each action from the test case. 473 for _, action := range group.Actions { 474 // add action. 475 added, err := unit.AddAction(action.Name, action.Parameters) 476 c.Assert(err, jc.ErrorIsNil) 477 478 if action.Execute { 479 status := state.ActionCompleted 480 output := map[string]interface{}{"output": "blah, blah, blah"} 481 message := "success" 482 483 _, err = added.Finish(state.ActionResults{Status: status, Results: output, Message: message}) 484 c.Assert(err, jc.ErrorIsNil) 485 486 // add expectation 487 exp := params.ActionResult{ 488 Action: ¶ms.Action{ 489 Tag: added.ActionTag().String(), 490 Name: action.Name, 491 Parameters: action.Parameters, 492 }, 493 Status: string(status), 494 Message: message, 495 Output: output, 496 } 497 cur.Actions = append(cur.Actions, exp) 498 } 499 } 500 } 501 502 // validate assumptions. 503 actionList, err := s.action.ListCompleted(arg) 504 c.Assert(err, jc.ErrorIsNil) 505 assertSame(c, actionList, expected) 506 } 507 } 508 509 func (s *actionSuite) TestCancel(c *gc.C) { 510 // Make sure no Actions already exist on wordpress Unit. 511 actions, err := s.wordpressUnit.Actions() 512 c.Assert(err, jc.ErrorIsNil) 513 c.Assert(actions, gc.HasLen, 0) 514 515 // Make sure no Actions already exist on mysql Unit. 516 actions, err = s.mysqlUnit.Actions() 517 c.Assert(err, jc.ErrorIsNil) 518 c.Assert(actions, gc.HasLen, 0) 519 520 // Add Actions. 521 tests := params.Actions{ 522 Actions: []params.Action{{ 523 Receiver: s.wordpressUnit.Tag().String(), 524 Name: "fakeaction", 525 }, { 526 Receiver: s.wordpressUnit.Tag().String(), 527 Name: "fakeaction", 528 }, { 529 Receiver: s.mysqlUnit.Tag().String(), 530 Name: "fakeaction", 531 }, { 532 Receiver: s.mysqlUnit.Tag().String(), 533 Name: "fakeaction", 534 }}, 535 } 536 537 results, err := s.action.Enqueue(tests) 538 c.Assert(err, jc.ErrorIsNil) 539 c.Assert(results.Results, gc.HasLen, 4) 540 for _, res := range results.Results { 541 c.Assert(res.Error, gc.IsNil) 542 } 543 544 // Cancel Some. 545 arg := params.Entities{ 546 Entities: []params.Entity{ 547 // "wp-two" 548 {Tag: results.Results[1].Action.Tag}, 549 // "my-one" 550 {Tag: results.Results[2].Action.Tag}, 551 }} 552 results, err = s.action.Cancel(arg) 553 c.Assert(err, jc.ErrorIsNil) 554 c.Assert(results.Results, gc.HasLen, 2) 555 556 // Assert the Actions are all in the expected state. 557 tags := params.Entities{Entities: []params.Entity{{Tag: s.wordpressUnit.Tag().String()}, {Tag: s.mysqlUnit.Tag().String()}}} 558 obtained, err := s.action.ListAll(tags) 559 c.Assert(err, jc.ErrorIsNil) 560 c.Assert(obtained.Actions, gc.HasLen, 2) 561 562 wpActions := obtained.Actions[0].Actions 563 c.Assert(wpActions, gc.HasLen, 2) 564 c.Assert(wpActions[0].Action.Name, gc.Equals, "fakeaction") 565 c.Assert(wpActions[0].Status, gc.Equals, params.ActionPending) 566 c.Assert(wpActions[1].Action.Name, gc.Equals, "fakeaction") 567 c.Assert(wpActions[1].Status, gc.Equals, params.ActionCancelled) 568 569 myActions := obtained.Actions[1].Actions 570 c.Assert(myActions, gc.HasLen, 2) 571 c.Assert(myActions[0].Action.Name, gc.Equals, "fakeaction") 572 c.Assert(myActions[0].Status, gc.Equals, params.ActionPending) 573 c.Assert(myActions[1].Action.Name, gc.Equals, "fakeaction") 574 c.Assert(myActions[1].Status, gc.Equals, params.ActionCancelled) 575 } 576 577 func (s *actionSuite) TestServicesCharmActions(c *gc.C) { 578 actionSchemas := map[string]map[string]interface{}{ 579 "snapshot": { 580 "type": "object", 581 "title": "snapshot", 582 "description": "Take a snapshot of the database.", 583 "properties": map[string]interface{}{ 584 "outfile": map[string]interface{}{ 585 "description": "The file to write out to.", 586 "type": "string", 587 "default": "foo.bz2", 588 }, 589 }, 590 }, 591 "fakeaction": { 592 "type": "object", 593 "title": "fakeaction", 594 "description": "No description", 595 "properties": map[string]interface{}{}, 596 }, 597 } 598 tests := []struct { 599 serviceNames []string 600 expectedResults params.ServicesCharmActionsResults 601 }{{ 602 serviceNames: []string{"dummy"}, 603 expectedResults: params.ServicesCharmActionsResults{ 604 Results: []params.ServiceCharmActionsResult{ 605 { 606 ServiceTag: names.NewServiceTag("dummy").String(), 607 Actions: &charm.Actions{ 608 ActionSpecs: map[string]charm.ActionSpec{ 609 "snapshot": { 610 Description: "Take a snapshot of the database.", 611 Params: actionSchemas["snapshot"], 612 }, 613 }, 614 }, 615 }, 616 }, 617 }, 618 }, { 619 serviceNames: []string{"wordpress"}, 620 expectedResults: params.ServicesCharmActionsResults{ 621 Results: []params.ServiceCharmActionsResult{ 622 { 623 ServiceTag: names.NewServiceTag("wordpress").String(), 624 Actions: &charm.Actions{ 625 ActionSpecs: map[string]charm.ActionSpec{ 626 "fakeaction": { 627 Description: "No description", 628 Params: actionSchemas["fakeaction"], 629 }, 630 }, 631 }, 632 }, 633 }, 634 }, 635 }, { 636 serviceNames: []string{"nonsense"}, 637 expectedResults: params.ServicesCharmActionsResults{ 638 Results: []params.ServiceCharmActionsResult{ 639 { 640 ServiceTag: names.NewServiceTag("nonsense").String(), 641 Error: ¶ms.Error{ 642 Message: `service "nonsense" not found`, 643 Code: "not found", 644 }, 645 }, 646 }, 647 }, 648 }} 649 650 for i, t := range tests { 651 c.Logf("test %d: services: %#v", i, t.serviceNames) 652 653 svcTags := params.Entities{ 654 Entities: make([]params.Entity, len(t.serviceNames)), 655 } 656 657 for j, svc := range t.serviceNames { 658 svcTag := names.NewServiceTag(svc) 659 svcTags.Entities[j] = params.Entity{Tag: svcTag.String()} 660 } 661 662 results, err := s.action.ServicesCharmActions(svcTags) 663 c.Assert(err, jc.ErrorIsNil) 664 c.Check(results.Results, jc.DeepEquals, t.expectedResults.Results) 665 } 666 } 667 668 func assertReadyToTest(c *gc.C, receiver state.ActionReceiver) { 669 // make sure there are no actions on the receiver already. 670 actions, err := receiver.Actions() 671 c.Assert(err, jc.ErrorIsNil) 672 c.Assert(actions, gc.HasLen, 0) 673 674 // make sure there are no actions pending already. 675 actions, err = receiver.PendingActions() 676 c.Assert(err, jc.ErrorIsNil) 677 c.Assert(actions, gc.HasLen, 0) 678 679 // make sure there are no actions running already. 680 actions, err = receiver.RunningActions() 681 c.Assert(err, jc.ErrorIsNil) 682 c.Assert(actions, gc.HasLen, 0) 683 684 // make sure there are no actions completed already. 685 actions, err = receiver.CompletedActions() 686 c.Assert(err, jc.ErrorIsNil) 687 c.Assert(actions, gc.HasLen, 0) 688 } 689 690 func assertSame(c *gc.C, got, expected params.ActionsByReceivers) { 691 c.Assert(got.Actions, gc.HasLen, len(expected.Actions)) 692 for i, g1 := range got.Actions { 693 e1 := expected.Actions[i] 694 c.Assert(g1.Error, gc.DeepEquals, e1.Error) 695 c.Assert(g1.Receiver, gc.DeepEquals, e1.Receiver) 696 c.Assert(toStrings(g1.Actions), jc.SameContents, toStrings(e1.Actions)) 697 } 698 } 699 700 func toStrings(items []params.ActionResult) []string { 701 ret := make([]string, len(items)) 702 for i, a := range items { 703 ret[i] = stringify(a) 704 } 705 return ret 706 } 707 708 func stringify(r params.ActionResult) string { 709 a := r.Action 710 if a == nil { 711 a = ¶ms.Action{} 712 } 713 return fmt.Sprintf("%s-%s-%#v-%s-%s-%#v", a.Tag, a.Name, a.Parameters, r.Status, r.Message, r.Output) 714 }