github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/state/payloads_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "fmt" 8 "sort" 9 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 "gopkg.in/juju/charm.v6-unstable" 14 15 "github.com/juju/juju/payload" 16 "github.com/juju/juju/state" 17 "github.com/juju/juju/testing/factory" 18 ) 19 20 type PayloadsSuite struct { 21 ConnSuite 22 } 23 24 var _ = gc.Suite(&PayloadsSuite{}) 25 26 func (s *PayloadsSuite) TestLookUp(c *gc.C) { 27 fix := s.newFixture(c) 28 29 result, err := fix.UnitPayloads.LookUp("returned", "ignored") 30 c.Check(result, gc.Equals, "returned") 31 c.Check(err, jc.ErrorIsNil) 32 } 33 34 func (s *PayloadsSuite) TestListPartial(c *gc.C) { 35 // Note: List and ListAll are extensively tested via the Check 36 // methods on payloadFixture, used throughout the suite. But 37 // they don't cover this feature... 38 fix, initial := s.newPayloadFixture(c) 39 results, err := fix.UnitPayloads.List("whatever", initial.Name) 40 c.Assert(err, jc.ErrorIsNil) 41 c.Assert(results, gc.HasLen, 2) 42 43 missing := results[0] 44 c.Check(missing.ID, gc.Equals, "whatever") 45 c.Check(missing.Payload, gc.IsNil) 46 c.Check(missing.NotFound, jc.IsTrue) 47 c.Check(missing.Error, jc.Satisfies, errors.IsNotFound) 48 c.Check(missing.Error, gc.ErrorMatches, "whatever not found") 49 50 found := results[1] 51 c.Check(found.ID, gc.Equals, initial.Name) 52 c.Assert(found.Payload, gc.NotNil) 53 c.Assert(*found.Payload, jc.DeepEquals, fix.FullPayload(initial)) 54 c.Check(found.NotFound, jc.IsFalse) 55 c.Check(found.Error, jc.ErrorIsNil) 56 } 57 58 func (s *PayloadsSuite) TestNoPayloads(c *gc.C) { 59 fix := s.newFixture(c) 60 61 fix.CheckNoPayload(c) 62 } 63 64 func (s *PayloadsSuite) TestTrackInvalidPayload(c *gc.C) { 65 // not an exhaustive test, just an indication we do Validate() 66 fix := s.newFixture(c) 67 pl := fix.SamplePayload("") 68 69 err := fix.UnitPayloads.Track(pl) 70 c.Check(err, jc.Satisfies, errors.IsNotValid) 71 c.Check(err, gc.ErrorMatches, `missing ID not valid`) 72 fix.CheckNoPayload(c) 73 } 74 75 func (s *PayloadsSuite) TestTrackInvalidUnit(c *gc.C) { 76 77 // Note: this is STUPID, but none of the unit-specific contexts 78 // between `api/context/register.go` and here ever check that 79 // the track request is correctly targeted. So we overwrite it 80 // unconditionally... because register is unconditionally 81 // sending a garbage unit name for some reason. 82 83 fix := s.newFixture(c) 84 expect := fix.SamplePayload("some-docker-id") 85 track := expect 86 track.Unit = "different/0" 87 88 err := fix.UnitPayloads.Track(track) 89 // In a sensible implementation, this would be: 90 // 91 // c.Check(err, jc.Satisfies, errors.IsNotValid) 92 // c.Check(err, gc.ErrorMatches, `unexpected Unit "different/0" not valid`) 93 // 94 // fix.CheckUnitPayloads(c) 95 // fix.CheckModelPayloads(c) 96 // 97 // ...but instead we have: 98 c.Assert(err, jc.ErrorIsNil) 99 fix.CheckOnePayload(c, expect) 100 } 101 102 func (s *PayloadsSuite) TestTrackInsertPayload(c *gc.C) { 103 fix := s.newFixture(c) 104 desired := fix.SamplePayload("some-docker-id") 105 106 err := fix.UnitPayloads.Track(desired) 107 c.Assert(err, jc.ErrorIsNil) 108 fix.CheckOnePayload(c, desired) 109 } 110 111 func (s *PayloadsSuite) TestTrackUpdatePayload(c *gc.C) { 112 fix, initial := s.newPayloadFixture(c) 113 replacement := initial 114 replacement.ID = "new-exciting-different" 115 116 err := fix.UnitPayloads.Track(replacement) 117 c.Assert(err, jc.ErrorIsNil) 118 fix.CheckOnePayload(c, replacement) 119 } 120 121 func (s *PayloadsSuite) TestTrackMultiplePayloads(c *gc.C) { 122 fix, initial := s.newPayloadFixture(c) 123 additional := fix.SamplePayload("another-docker-id") 124 additional.Name = "app" 125 126 err := fix.UnitPayloads.Track(additional) 127 c.Assert(err, jc.ErrorIsNil) 128 129 full1 := fix.FullPayload(initial) 130 full2 := fix.FullPayload(additional) 131 fix.CheckUnitPayloads(c, full1, full2) 132 fix.CheckModelPayloads(c, full1, full2) 133 } 134 135 func (s *PayloadsSuite) TestTrackMultipleUnits(c *gc.C) { 136 fix, initial := s.newPayloadFixture(c) 137 138 // Create a new unit to add another payload to. 139 applicationName := fix.Unit.ApplicationName() 140 application, err := s.State.Application(applicationName) 141 c.Assert(err, jc.ErrorIsNil) 142 machine2 := s.Factory.MakeMachine(c, nil) 143 unit2 := s.Factory.MakeUnit(c, &factory.UnitParams{ 144 Application: application, 145 Machine: machine2, 146 }) 147 148 // Add a payload which should be independent of the 149 // UnitPayloads in the fixture. 150 unit2Payloads, err := s.State.UnitPayloads(unit2) 151 c.Assert(err, jc.ErrorIsNil) 152 additional := initial 153 additional.Unit = unit2.Name() 154 err = unit2Payloads.Track(additional) 155 c.Assert(err, jc.ErrorIsNil) 156 157 // Check the independent payload only shows up in 158 // the fixture's ModelPayloads, not its UnitPayloads. 159 full1 := fix.FullPayload(initial) 160 full2 := payload.FullPayloadInfo{ 161 Payload: additional, 162 Machine: machine2.Id(), 163 } 164 fix.CheckUnitPayloads(c, full1) 165 fix.CheckModelPayloads(c, full1, full2) 166 } 167 168 func (s *PayloadsSuite) TestSetStatusInvalid(c *gc.C) { 169 fix, initial := s.newPayloadFixture(c) 170 171 err := fix.UnitPayloads.SetStatus(initial.Name, "twirling") 172 c.Check(err, jc.Satisfies, errors.IsNotValid) 173 c.Check(err.Error(), gc.Equals, `status "twirling" not supported; expected one of ["running", "starting", "stopped", "stopping"]`) 174 175 fix.CheckOnePayload(c, initial) 176 } 177 178 func (s *PayloadsSuite) TestSetStatus(c *gc.C) { 179 fix, initial := s.newPayloadFixture(c) 180 expect := initial 181 expect.Status = "stopping" 182 183 err := fix.UnitPayloads.SetStatus(initial.Name, "stopping") 184 c.Assert(err, jc.ErrorIsNil) 185 186 fix.CheckOnePayload(c, expect) 187 } 188 189 func (s *PayloadsSuite) TestUntrackMissing(c *gc.C) { 190 fix := s.newFixture(c) 191 192 err := fix.UnitPayloads.Untrack("whatever") 193 c.Assert(err, jc.ErrorIsNil) 194 fix.CheckNoPayload(c) 195 } 196 197 func (s *PayloadsSuite) TestUntrack(c *gc.C) { 198 fix, initial := s.newPayloadFixture(c) 199 200 err := fix.UnitPayloads.Untrack(initial.Name) 201 c.Assert(err, jc.ErrorIsNil) 202 fix.CheckNoPayload(c) 203 } 204 205 func (s *PayloadsSuite) TestRemoveUnitUntracksPayloads(c *gc.C) { 206 fix, _ := s.newPayloadFixture(c) 207 additional := fix.SamplePayload("another-docker-id") 208 additional.Name = "app" 209 err := fix.UnitPayloads.Track(additional) 210 c.Assert(err, jc.ErrorIsNil) 211 212 err = fix.Unit.Destroy() 213 c.Assert(err, jc.ErrorIsNil) 214 err = s.State.Cleanup() 215 c.Assert(err, jc.ErrorIsNil) 216 fix.CheckNoPayload(c) 217 } 218 219 func (s *PayloadsSuite) TestTrackRaceDyingUnit(c *gc.C) { 220 fix := s.newFixture(c) 221 preventUnitDestroyRemove(c, fix.Unit) 222 223 defer state.SetBeforeHooks(c, s.State, func() { 224 err := fix.Unit.Destroy() 225 c.Assert(err, jc.ErrorIsNil) 226 }).Check() 227 228 desired := fix.SamplePayload("this-is-fine") 229 err := fix.UnitPayloads.Track(desired) 230 c.Assert(err, jc.ErrorIsNil) 231 fix.CheckOnePayload(c, desired) 232 } 233 234 func (s *PayloadsSuite) TestTrackRaceDeadUnit(c *gc.C) { 235 fix := s.newFixture(c) 236 preventUnitDestroyRemove(c, fix.Unit) 237 238 defer state.SetBeforeHooks(c, s.State, func() { 239 err := fix.Unit.Destroy() 240 c.Assert(err, jc.ErrorIsNil) 241 err = fix.Unit.EnsureDead() 242 c.Assert(err, jc.ErrorIsNil) 243 }).Check() 244 245 desired := fix.SamplePayload("sorry-too-late") 246 err := fix.UnitPayloads.Track(desired) 247 c.Check(err, gc.ErrorMatches, fix.DeadUnitMessage()) 248 fix.CheckNoPayload(c) 249 } 250 251 func (s *PayloadsSuite) TestTrackRaceRemovedUnit(c *gc.C) { 252 fix := s.newFixture(c) 253 254 defer state.SetBeforeHooks(c, s.State, func() { 255 err := fix.Unit.Destroy() 256 c.Assert(err, jc.ErrorIsNil) 257 }).Check() 258 259 desired := fix.SamplePayload("sorry-too-late") 260 err := fix.UnitPayloads.Track(desired) 261 c.Check(err, gc.ErrorMatches, fix.DeadUnitMessage()) 262 fix.CheckNoPayload(c) 263 } 264 265 func (s *PayloadsSuite) TestTrackRaceTrack(c *gc.C) { 266 fix := s.newFixture(c) 267 desired := fix.SamplePayload("wanted") 268 interloper := fix.SamplePayload("not-wanted") 269 270 defer state.SetBeforeHooks(c, s.State, func() { 271 err := fix.UnitPayloads.Track(interloper) 272 c.Assert(err, jc.ErrorIsNil) 273 }).Check() 274 275 err := fix.UnitPayloads.Track(desired) 276 c.Assert(err, jc.ErrorIsNil) 277 fix.CheckOnePayload(c, desired) 278 } 279 280 func (s *PayloadsSuite) TestTrackRaceSetStatus(c *gc.C) { 281 fix, initial := s.newPayloadFixture(c) 282 desired := initial 283 desired.Status = "starting" 284 285 defer state.SetBeforeHooks(c, s.State, func() { 286 err := fix.UnitPayloads.SetStatus(initial.Name, "stopping") 287 c.Assert(err, jc.ErrorIsNil) 288 }).Check() 289 290 err := fix.UnitPayloads.Track(desired) 291 c.Assert(err, jc.ErrorIsNil) 292 fix.CheckOnePayload(c, desired) 293 } 294 295 func (s *PayloadsSuite) TestTrackRaceUntrack(c *gc.C) { 296 fix, initial := s.newPayloadFixture(c) 297 298 defer state.SetBeforeHooks(c, s.State, func() { 299 err := fix.UnitPayloads.Untrack(initial.Name) 300 c.Assert(err, jc.ErrorIsNil) 301 }).Check() 302 303 err := fix.UnitPayloads.Track(initial) 304 c.Assert(err, jc.ErrorIsNil) 305 fix.CheckOnePayload(c, initial) 306 } 307 308 func (s *PayloadsSuite) TestSetStatusRaceTrack(c *gc.C) { 309 fix, initial := s.newPayloadFixture(c) 310 expect := initial 311 expect.Status = "stopped" 312 313 defer state.SetBeforeHooks(c, s.State, func() { 314 err := fix.UnitPayloads.Track(initial) 315 c.Assert(err, jc.ErrorIsNil) 316 }).Check() 317 318 err := fix.UnitPayloads.SetStatus(initial.Name, "stopped") 319 c.Assert(err, jc.ErrorIsNil) 320 fix.CheckOnePayload(c, expect) 321 } 322 323 func (s *PayloadsSuite) TestSetStatusRaceUntrack(c *gc.C) { 324 fix, initial := s.newPayloadFixture(c) 325 326 defer state.SetBeforeHooks(c, s.State, func() { 327 err := fix.UnitPayloads.Untrack(initial.Name) 328 c.Assert(err, jc.ErrorIsNil) 329 }).Check() 330 331 err := fix.UnitPayloads.SetStatus(initial.Name, "stopped") 332 c.Check(errors.Cause(err), gc.Equals, payload.ErrNotFound) 333 c.Check(err, gc.ErrorMatches, "payload not found") 334 fix.CheckNoPayload(c) 335 } 336 337 func (s *PayloadsSuite) TestUntrackRaceTrack(c *gc.C) { 338 fix, initial := s.newPayloadFixture(c) 339 340 defer state.SetBeforeHooks(c, s.State, func() { 341 err := fix.UnitPayloads.Track(initial) 342 c.Assert(err, jc.ErrorIsNil) 343 }).Check() 344 345 err := fix.UnitPayloads.Untrack(initial.Name) 346 c.Assert(err, jc.ErrorIsNil) 347 fix.CheckNoPayload(c) 348 } 349 350 func (s *PayloadsSuite) TestUntrackRaceSetStatus(c *gc.C) { 351 fix, initial := s.newPayloadFixture(c) 352 353 defer state.SetBeforeHooks(c, s.State, func() { 354 err := fix.UnitPayloads.SetStatus(initial.Name, "stopping") 355 c.Assert(err, jc.ErrorIsNil) 356 }).Check() 357 358 err := fix.UnitPayloads.Untrack(initial.Name) 359 c.Assert(err, jc.ErrorIsNil) 360 fix.CheckNoPayload(c) 361 } 362 363 func (s *PayloadsSuite) TestUntrackRaceUntrack(c *gc.C) { 364 fix, initial := s.newPayloadFixture(c) 365 366 defer state.SetBeforeHooks(c, s.State, func() { 367 err := fix.UnitPayloads.Untrack(initial.Name) 368 c.Assert(err, jc.ErrorIsNil) 369 }).Check() 370 371 err := fix.UnitPayloads.Untrack(initial.Name) 372 c.Assert(err, jc.ErrorIsNil) 373 fix.CheckNoPayload(c) 374 } 375 376 // ------------------------- 377 // test helpers 378 379 type payloadsFixture struct { 380 ModelPayloads state.ModelPayloads 381 UnitPayloads state.UnitPayloads 382 Machine *state.Machine 383 Unit *state.Unit 384 } 385 386 func (s *PayloadsSuite) newFixture(c *gc.C) payloadsFixture { 387 machine := s.Factory.MakeMachine(c, nil) 388 unit := s.Factory.MakeUnit(c, &factory.UnitParams{Machine: machine}) 389 modelPayloads, err := s.State.ModelPayloads() 390 c.Assert(err, jc.ErrorIsNil) 391 unitPayloads, err := s.State.UnitPayloads(unit) 392 c.Assert(err, jc.ErrorIsNil) 393 return payloadsFixture{ 394 ModelPayloads: modelPayloads, 395 UnitPayloads: unitPayloads, 396 Machine: machine, 397 Unit: unit, 398 } 399 } 400 401 func (s *PayloadsSuite) newPayloadFixture(c *gc.C) (payloadsFixture, payload.Payload) { 402 fix := s.newFixture(c) 403 initial := fix.SamplePayload("some-docker-id") 404 err := fix.UnitPayloads.Track(initial) 405 c.Assert(err, jc.ErrorIsNil) 406 return fix, initial 407 } 408 409 func (fix payloadsFixture) SamplePayload(id string) payload.Payload { 410 return payload.Payload{ 411 PayloadClass: charm.PayloadClass{ 412 Name: "database", 413 Type: "docker", 414 }, 415 Status: payload.StateRunning, 416 ID: id, 417 Unit: fix.Unit.Name(), 418 } 419 } 420 421 func (fix payloadsFixture) DeadUnitMessage() string { 422 return fmt.Sprintf("unit %q no longer available", fix.Unit.Name()) 423 } 424 425 func (fix payloadsFixture) FullPayload(pl payload.Payload) payload.FullPayloadInfo { 426 return payload.FullPayloadInfo{ 427 Payload: pl, 428 Machine: fix.Machine.Id(), 429 } 430 } 431 432 func (fix payloadsFixture) CheckNoPayload(c *gc.C) { 433 fix.CheckModelPayloads(c) 434 fix.CheckUnitPayloads(c) 435 } 436 437 func (fix payloadsFixture) CheckOnePayload(c *gc.C, expect payload.Payload) { 438 full := fix.FullPayload(expect) 439 fix.CheckModelPayloads(c, full) 440 fix.CheckUnitPayloads(c, full) 441 } 442 443 func (fix payloadsFixture) CheckModelPayloads(c *gc.C, expect ...payload.FullPayloadInfo) { 444 actual, err := fix.ModelPayloads.ListAll() 445 c.Check(err, jc.ErrorIsNil) 446 sort.Sort(byPayloadInfo(actual)) 447 sort.Sort(byPayloadInfo(expect)) 448 c.Check(actual, jc.DeepEquals, expect) 449 } 450 451 func (fix payloadsFixture) CheckUnitPayloads(c *gc.C, expect ...payload.FullPayloadInfo) { 452 actual, err := fix.UnitPayloads.List() 453 c.Check(err, jc.ErrorIsNil) 454 extracted := fix.extractInfos(c, actual) 455 sort.Sort(byPayloadInfo(extracted)) 456 sort.Sort(byPayloadInfo(expect)) 457 c.Check(extracted, jc.DeepEquals, expect) 458 } 459 460 func (payloadsFixture) extractInfos(c *gc.C, results []payload.Result) []payload.FullPayloadInfo { 461 fulls := make([]payload.FullPayloadInfo, 0, len(results)) 462 for _, result := range results { 463 c.Assert(result.ID, gc.Equals, result.Payload.Name) 464 c.Assert(result.Payload, gc.NotNil) 465 c.Assert(result.NotFound, jc.IsFalse) 466 c.Assert(result.Error, jc.ErrorIsNil) 467 fulls = append(fulls, *result.Payload) 468 } 469 return fulls 470 } 471 472 type byPayloadInfo []payload.FullPayloadInfo 473 474 func (s byPayloadInfo) Len() int { return len(s) } 475 func (s byPayloadInfo) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 476 func (s byPayloadInfo) Less(i, j int) bool { 477 if s[i].Machine != s[j].Machine { 478 return s[i].Machine < s[j].Machine 479 } 480 if s[i].Payload.Unit != s[j].Payload.Unit { 481 return s[i].Payload.Unit < s[j].Payload.Unit 482 } 483 return s[i].Payload.Name < s[j].Payload.Name 484 } 485 486 // ---------------------------------------------------------- 487 // original functional tests 488 489 type PayloadsFunctionalSuite struct { 490 ConnSuite 491 } 492 493 var _ = gc.Suite(&PayloadsFunctionalSuite{}) 494 495 func (s *PayloadsFunctionalSuite) TestModelPayloads(c *gc.C) { 496 machine := "0" 497 unit := addUnit(c, s.ConnSuite, unitArgs{ 498 charm: "dummy", 499 service: "a-application", 500 metadata: payloadsMetaYAML, 501 machine: machine, 502 }) 503 504 ust, err := s.State.UnitPayloads(unit) 505 c.Assert(err, jc.ErrorIsNil) 506 507 st, err := s.State.ModelPayloads() 508 c.Assert(err, jc.ErrorIsNil) 509 510 payloads, err := st.ListAll() 511 c.Assert(err, jc.ErrorIsNil) 512 c.Check(payloads, gc.HasLen, 0) 513 514 err = ust.Track(payload.Payload{ 515 PayloadClass: charm.PayloadClass{ 516 Name: "payloadA", 517 Type: "docker", 518 }, 519 Status: payload.StateRunning, 520 ID: "xyz", 521 Unit: "a-application/0", 522 }) 523 c.Assert(err, jc.ErrorIsNil) 524 525 unitPayloads, err := ust.List() 526 c.Assert(err, jc.ErrorIsNil) 527 c.Assert(unitPayloads, gc.HasLen, 1) 528 529 payloads, err = st.ListAll() 530 c.Assert(err, jc.ErrorIsNil) 531 c.Check(payloads, jc.DeepEquals, []payload.FullPayloadInfo{{ 532 Payload: payload.Payload{ 533 PayloadClass: charm.PayloadClass{ 534 Name: "payloadA", 535 Type: "docker", 536 }, 537 ID: "xyz", 538 Status: payload.StateRunning, 539 Labels: []string{}, 540 Unit: "a-application/0", 541 }, 542 Machine: machine, 543 }}) 544 545 id, err := ust.LookUp("payloadA", "xyz") 546 c.Assert(err, jc.ErrorIsNil) 547 548 err = ust.Untrack(id) 549 c.Assert(err, jc.ErrorIsNil) 550 551 payloads, err = st.ListAll() 552 c.Assert(err, jc.ErrorIsNil) 553 c.Check(payloads, gc.HasLen, 0) 554 } 555 556 func (s *PayloadsFunctionalSuite) TestUnitPayloads(c *gc.C) { 557 machine := "0" 558 unit := addUnit(c, s.ConnSuite, unitArgs{ 559 charm: "dummy", 560 service: "a-application", 561 metadata: payloadsMetaYAML, 562 machine: machine, 563 }) 564 565 st, err := s.State.UnitPayloads(unit) 566 c.Assert(err, jc.ErrorIsNil) 567 568 results, err := st.List() 569 c.Assert(err, jc.ErrorIsNil) 570 c.Check(results, gc.HasLen, 0) 571 572 pl := payload.Payload{ 573 PayloadClass: charm.PayloadClass{ 574 Name: "payloadA", 575 Type: "docker", 576 }, 577 ID: "xyz", 578 Status: payload.StateRunning, 579 Unit: "a-application/0", 580 } 581 err = st.Track(pl) 582 c.Assert(err, jc.ErrorIsNil) 583 584 results, err = st.List() 585 c.Assert(err, jc.ErrorIsNil) 586 // TODO(ericsnow) Once Track returns the new ID we can drop 587 // the following two lines. 588 c.Assert(results, gc.HasLen, 1) 589 id := results[0].ID 590 c.Check(results, jc.DeepEquals, []payload.Result{{ 591 ID: id, 592 Payload: &payload.FullPayloadInfo{ 593 Payload: pl, 594 Machine: machine, 595 }, 596 }}) 597 598 lookedUpID, err := st.LookUp("payloadA", "xyz") 599 c.Assert(err, jc.ErrorIsNil) 600 c.Check(lookedUpID, gc.Equals, id) 601 602 c.Logf("using ID %q", id) 603 results, err = st.List(id) 604 c.Assert(err, jc.ErrorIsNil) 605 c.Check(results, jc.DeepEquals, []payload.Result{{ 606 ID: id, 607 Payload: &payload.FullPayloadInfo{ 608 Payload: pl, 609 Machine: machine, 610 }, 611 }}) 612 613 err = st.SetStatus(id, "running") 614 c.Assert(err, jc.ErrorIsNil) 615 616 results, err = st.List(id) 617 c.Assert(err, jc.ErrorIsNil) 618 c.Check(results, jc.DeepEquals, []payload.Result{{ 619 ID: id, 620 Payload: &payload.FullPayloadInfo{ 621 Payload: pl, 622 Machine: machine, 623 }, 624 }}) 625 626 // Ensure existing ones are replaced. 627 update := pl 628 update.ID = "abc" 629 err = st.Track(update) 630 c.Check(err, jc.ErrorIsNil) 631 results, err = st.List() 632 c.Assert(err, jc.ErrorIsNil) 633 c.Check(results, jc.DeepEquals, []payload.Result{{ 634 ID: id, 635 Payload: &payload.FullPayloadInfo{ 636 Payload: update, 637 Machine: machine, 638 }, 639 }}) 640 641 err = st.Untrack(id) 642 c.Assert(err, jc.ErrorIsNil) 643 644 results, err = st.List() 645 c.Assert(err, jc.ErrorIsNil) 646 c.Check(results, gc.HasLen, 0) 647 } 648 649 const payloadsMetaYAML = ` 650 name: a-charm 651 summary: a charm... 652 description: a charm... 653 payloads: 654 payloadA: 655 type: docker 656 ` 657 658 type unitArgs struct { 659 charm string 660 service string 661 metadata string 662 machine string 663 } 664 665 func addUnit(c *gc.C, s ConnSuite, args unitArgs) *state.Unit { 666 ch := s.AddTestingCharm(c, args.charm) 667 ch = s.AddMetaCharm(c, args.charm, args.metadata, 2) 668 669 svc := s.AddTestingService(c, args.service, ch) 670 unit, err := svc.AddUnit() 671 c.Assert(err, jc.ErrorIsNil) 672 673 // TODO(ericsnow) Explicitly: call unit.AssignToMachine(m)? 674 c.Assert(args.machine, gc.Equals, "0") 675 err = unit.AssignToNewMachine() // machine "0" 676 c.Assert(err, jc.ErrorIsNil) 677 678 return unit 679 }