func (s *InstancePollerSuite) TestWatchModelMachinesSuccess(c *gc.C) { // Add a couple of machines. s.st.SetMachineInfo(c, machineInfo{id: "2"}) s.st.SetMachineInfo(c, machineInfo{id: "1"}) expectedResult := params.StringsWatchResult{ Error: nil, StringsWatcherId: "1", Changes: []string{"1", "2"}, // initial event (sorted ids) } result, err := s.api.WatchModelMachines() c.Assert(err, jc.ErrorIsNil) c.Assert(result, jc.DeepEquals, expectedResult) // Verify the watcher resource was registered. c.Assert(s.resources.Count(), gc.Equals, 1) resource1 := s.resources.Get("1") defer func() { if resource1 != nil { statetesting.AssertStop(c, resource1) } }() // Check that the watcher has consumed the initial event wc1 := statetesting.NewStringsWatcherC(c, s.st, resource1.(state.StringsWatcher)) wc1.AssertNoChange() s.st.CheckCallNames(c, "WatchModelMachines") // Add another watcher to verify events coalescence. result, err = s.api.WatchModelMachines() c.Assert(err, jc.ErrorIsNil) expectedResult.StringsWatcherId = "2" c.Assert(result, jc.DeepEquals, expectedResult) s.st.CheckCallNames(c, "WatchModelMachines", "WatchModelMachines") c.Assert(s.resources.Count(), gc.Equals, 2) resource2 := s.resources.Get("2") defer statetesting.AssertStop(c, resource2) wc2 := statetesting.NewStringsWatcherC(c, s.st, resource2.(state.StringsWatcher)) wc2.AssertNoChange() // Remove machine 1, check it's reported. s.st.RemoveMachine(c, "1") wc1.AssertChangeInSingleEvent("1") // Make separate changes, check they're combined. s.st.SetMachineInfo(c, machineInfo{id: "2", life: state.Dying}) s.st.SetMachineInfo(c, machineInfo{id: "3"}) s.st.RemoveMachine(c, "42") // ignored wc1.AssertChangeInSingleEvent("2", "3") wc2.AssertChangeInSingleEvent("1", "2", "3") // Stop the first watcher and assert its changes chan is closed. c.Assert(resource1.Stop(), jc.ErrorIsNil) wc1.AssertClosed() resource1 = nil }
// WatchEnvironMachines returns a StringsWatcher that notifies of // changes to the life cycles of the top level machines in the current // environment. func (e *EnvironMachinesWatcher) WatchEnvironMachines() (params.StringsWatchResult, error) { result := params.StringsWatchResult{} if !e.authorizer.AuthEnvironManager() { return result, ErrPerm } watch := e.st.WatchEnvironMachines() // Consume the initial event and forward it to the result. if changes, ok := <-watch.Changes(); ok { result.StringsWatcherId = e.resources.Register(watch) result.Changes = changes } else { err := watcher.EnsureErr(watch) return result, fmt.Errorf("cannot obtain initial environment machines: %v", err) } return result, nil }
func (s *StorageProvisionerAPI) watchStorageEntities( args params.Entities, watchEnvironStorage func() state.StringsWatcher, watchMachineStorage func(names.MachineTag) state.StringsWatcher, ) (params.StringsWatchResults, error) { canAccess, err := s.getScopeAuthFunc() if err != nil { return params.StringsWatchResults{}, common.ServerError(common.ErrPerm) } results := params.StringsWatchResults{ Results: make([]params.StringsWatchResult, len(args.Entities)), } one := func(arg params.Entity) (string, []string, error) { tag, err := names.ParseTag(arg.Tag) if err != nil || !canAccess(tag) { return "", nil, common.ErrPerm } var w state.StringsWatcher if tag, ok := tag.(names.MachineTag); ok { w = watchMachineStorage(tag) } else { w = watchEnvironStorage() } if changes, ok := <-w.Changes(); ok { return s.resources.Register(w), changes, nil } return "", nil, watcher.EnsureErr(w) } for i, arg := range args.Entities { var result params.StringsWatchResult id, changes, err := one(arg) if err != nil { result.Error = common.ServerError(err) } else { result.StringsWatcherId = id result.Changes = changes } results.Results[i] = result } return results, nil }