func (s *watcherSuite) TestStringsWatcherStopsWithPendingSend(c *gc.C) { // Call the Deployer facade's WatchUnits for machine-0. var results params.StringsWatchResults args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag()}}} err := s.stateAPI.Call("Deployer", "", "WatchUnits", args, &results) c.Assert(err, gc.IsNil) c.Assert(results.Results, gc.HasLen, 1) result := results.Results[0] c.Assert(result.Error, gc.IsNil) // Start a StringsWatcher and check the initial event. w := watcher.NewStringsWatcher(s.stateAPI, result) wc := statetesting.NewStringsWatcherC(c, s.State, w) // Create a service, deploy a unit of it on the machine. mysql, err := s.State.AddService("mysql", s.AddTestingCharm(c, "mysql")) c.Assert(err, gc.IsNil) principal, err := mysql.AddUnit() c.Assert(err, gc.IsNil) err = principal.AssignToMachine(s.rawMachine) c.Assert(err, gc.IsNil) // Ensure the initial event is delivered. Then test the watcher // can be stopped cleanly without reading the pending change. s.BackingState.Sync() statetesting.AssertCanStopWhenSending(c, w) wc.AssertClosed() }
func (s *watcherSuite) TestWatchUnitsKeepsEvents(c *gc.C) { // Create two services, relate them, and add one unit to each - a // principal and a subordinate. mysql, err := s.State.AddService("mysql", s.AddTestingCharm(c, "mysql")) c.Assert(err, gc.IsNil) logging, err := s.State.AddService("logging", s.AddTestingCharm(c, "logging")) c.Assert(err, gc.IsNil) eps, err := s.State.InferEndpoints([]string{"mysql", "logging"}) c.Assert(err, gc.IsNil) rel, err := s.State.AddRelation(eps...) c.Assert(err, gc.IsNil) principal, err := mysql.AddUnit() c.Assert(err, gc.IsNil) err = principal.AssignToMachine(s.rawMachine) c.Assert(err, gc.IsNil) relUnit, err := rel.Unit(principal) c.Assert(err, gc.IsNil) err = relUnit.EnterScope(nil) c.Assert(err, gc.IsNil) subordinate, err := logging.Unit("logging/0") c.Assert(err, gc.IsNil) // Call the Deployer facade's WatchUnits for machine-0. var results params.StringsWatchResults args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag()}}} err = s.stateAPI.Call("Deployer", "", "WatchUnits", args, &results) c.Assert(err, gc.IsNil) c.Assert(results.Results, gc.HasLen, 1) result := results.Results[0] c.Assert(result.Error, gc.IsNil) // Start a StringsWatcher and check the initial event. w := watcher.NewStringsWatcher(s.stateAPI, result) wc := statetesting.NewStringsWatcherC(c, s.State, w) wc.AssertChange("mysql/0", "logging/0") wc.AssertNoChange() // Now, without reading any changes advance the lifecycle of both // units, inducing an update server-side after each two changes to // ensure they're reported as separate events over the API. err = subordinate.EnsureDead() c.Assert(err, gc.IsNil) s.BackingState.Sync() err = subordinate.Remove() c.Assert(err, gc.IsNil) err = principal.EnsureDead() c.Assert(err, gc.IsNil) s.BackingState.Sync() // Expect these changes as 2 separate events, so that // nothing gets lost. wc.AssertChange("logging/0") wc.AssertChange("mysql/0") wc.AssertNoChange() statetesting.AssertStop(c, w) wc.AssertClosed() }
// WatchUnits starts a StringsWatcher to watch all units deployed to // the machine, in order to track which ones should be deployed or // recalled. func (m *Machine) WatchUnits() (*watcher.StringsWatcher, error) { var results params.StringsWatchResults args := params.Entities{ Entities: []params.Entity{{Tag: m.tag}}, } err := m.dstate.caller.Call("Deployer", "", "WatchUnits", args, &results) if err != nil { return nil, err } if len(results.Results) != 1 { return nil, fmt.Errorf("expected one result, got %d", len(results.Results)) } result := results.Results[0] if result.Error != nil { return nil, result.Error } w := watcher.NewStringsWatcher(m.dstate.caller, result) return w, nil }