github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/api/watcher/watcher_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package watcher_test 5 6 import ( 7 stdtesting "testing" 8 "time" 9 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/api" 14 "github.com/juju/juju/api/watcher" 15 "github.com/juju/juju/apiserver/params" 16 "github.com/juju/juju/juju/testing" 17 "github.com/juju/juju/state" 18 statetesting "github.com/juju/juju/state/testing" 19 coretesting "github.com/juju/juju/testing" 20 ) 21 22 func TestAll(t *stdtesting.T) { 23 coretesting.MgoTestPackage(t) 24 } 25 26 type watcherSuite struct { 27 testing.JujuConnSuite 28 29 stateAPI *api.State 30 31 // These are raw State objects. Use them for setup and assertions, but 32 // should never be touched by the API calls themselves 33 rawMachine *state.Machine 34 } 35 36 var _ = gc.Suite(&watcherSuite{}) 37 38 func (s *watcherSuite) SetUpTest(c *gc.C) { 39 s.JujuConnSuite.SetUpTest(c) 40 s.stateAPI, s.rawMachine = s.OpenAPIAsNewMachine(c) 41 } 42 43 func (s *watcherSuite) TestWatchInitialEventConsumed(c *gc.C) { 44 // Machiner.Watch should send the initial event as part of the Watch 45 // call (for NotifyWatchers there is no state to be transmitted). So a 46 // call to Next() should not have anything to return. 47 var results params.NotifyWatchResults 48 args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag().String()}}} 49 err := s.stateAPI.APICall("Machiner", s.stateAPI.BestFacadeVersion("Machiner"), "", "Watch", args, &results) 50 c.Assert(err, jc.ErrorIsNil) 51 c.Assert(results.Results, gc.HasLen, 1) 52 result := results.Results[0] 53 c.Assert(result.Error, gc.IsNil) 54 55 // We expect the Call() to "Next" to block, so run it in a goroutine. 56 done := make(chan error) 57 go func() { 58 ignored := struct{}{} 59 done <- s.stateAPI.APICall("NotifyWatcher", s.stateAPI.BestFacadeVersion("NotifyWatcher"), result.NotifyWatcherId, "Next", nil, &ignored) 60 }() 61 62 select { 63 case err := <-done: 64 c.Errorf("Call(Next) did not block immediately after Watch(): err %v", err) 65 case <-time.After(coretesting.ShortWait): 66 } 67 } 68 69 func (s *watcherSuite) TestWatchMachine(c *gc.C) { 70 var results params.NotifyWatchResults 71 args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag().String()}}} 72 err := s.stateAPI.APICall("Machiner", s.stateAPI.BestFacadeVersion("Machiner"), "", "Watch", args, &results) 73 c.Assert(err, jc.ErrorIsNil) 74 c.Assert(results.Results, gc.HasLen, 1) 75 result := results.Results[0] 76 c.Assert(result.Error, gc.IsNil) 77 78 // params.NotifyWatcher conforms to the state.NotifyWatcher interface 79 w := watcher.NewNotifyWatcher(s.stateAPI, result) 80 wc := statetesting.NewNotifyWatcherC(c, s.State, w) 81 wc.AssertOneChange() 82 statetesting.AssertStop(c, w) 83 wc.AssertClosed() 84 } 85 86 func (s *watcherSuite) TestNotifyWatcherStopsWithPendingSend(c *gc.C) { 87 var results params.NotifyWatchResults 88 args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag().String()}}} 89 err := s.stateAPI.APICall("Machiner", s.stateAPI.BestFacadeVersion("Machiner"), "", "Watch", args, &results) 90 c.Assert(err, jc.ErrorIsNil) 91 c.Assert(results.Results, gc.HasLen, 1) 92 result := results.Results[0] 93 c.Assert(result.Error, gc.IsNil) 94 95 // params.NotifyWatcher conforms to the state.NotifyWatcher interface 96 w := watcher.NewNotifyWatcher(s.stateAPI, result) 97 wc := statetesting.NewNotifyWatcherC(c, s.State, w) 98 99 // Now, without reading any changes try stopping the watcher. 100 statetesting.AssertCanStopWhenSending(c, w) 101 wc.AssertClosed() 102 } 103 104 func (s *watcherSuite) TestWatchUnitsKeepsEvents(c *gc.C) { 105 // Create two services, relate them, and add one unit to each - a 106 // principal and a subordinate. 107 mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 108 s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging")) 109 eps, err := s.State.InferEndpoints("mysql", "logging") 110 c.Assert(err, jc.ErrorIsNil) 111 rel, err := s.State.AddRelation(eps...) 112 c.Assert(err, jc.ErrorIsNil) 113 principal, err := mysql.AddUnit() 114 c.Assert(err, jc.ErrorIsNil) 115 err = principal.AssignToMachine(s.rawMachine) 116 c.Assert(err, jc.ErrorIsNil) 117 relUnit, err := rel.Unit(principal) 118 c.Assert(err, jc.ErrorIsNil) 119 err = relUnit.EnterScope(nil) 120 c.Assert(err, jc.ErrorIsNil) 121 subordinate, err := s.State.Unit("logging/0") 122 c.Assert(err, jc.ErrorIsNil) 123 124 // Call the Deployer facade's WatchUnits for machine-0. 125 var results params.StringsWatchResults 126 args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag().String()}}} 127 err = s.stateAPI.APICall("Deployer", s.stateAPI.BestFacadeVersion("Deployer"), "", "WatchUnits", args, &results) 128 c.Assert(err, jc.ErrorIsNil) 129 c.Assert(results.Results, gc.HasLen, 1) 130 result := results.Results[0] 131 c.Assert(result.Error, gc.IsNil) 132 133 // Start a StringsWatcher and check the initial event. 134 w := watcher.NewStringsWatcher(s.stateAPI, result) 135 wc := statetesting.NewStringsWatcherC(c, s.State, w) 136 wc.AssertChange("mysql/0", "logging/0") 137 wc.AssertNoChange() 138 139 // Now, without reading any changes advance the lifecycle of both 140 // units, inducing an update server-side after each two changes to 141 // ensure they're reported as separate events over the API. 142 err = subordinate.EnsureDead() 143 c.Assert(err, jc.ErrorIsNil) 144 s.BackingState.StartSync() 145 err = subordinate.Remove() 146 c.Assert(err, jc.ErrorIsNil) 147 err = principal.EnsureDead() 148 c.Assert(err, jc.ErrorIsNil) 149 s.BackingState.StartSync() 150 151 // Expect these changes as 2 separate events, so that 152 // nothing gets lost. 153 wc.AssertChange("logging/0") 154 wc.AssertChange("mysql/0") 155 wc.AssertNoChange() 156 157 statetesting.AssertStop(c, w) 158 wc.AssertClosed() 159 } 160 161 func (s *watcherSuite) TestStringsWatcherStopsWithPendingSend(c *gc.C) { 162 // Call the Deployer facade's WatchUnits for machine-0. 163 var results params.StringsWatchResults 164 args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag().String()}}} 165 err := s.stateAPI.APICall("Deployer", s.stateAPI.BestFacadeVersion("Deployer"), "", "WatchUnits", args, &results) 166 c.Assert(err, jc.ErrorIsNil) 167 c.Assert(results.Results, gc.HasLen, 1) 168 result := results.Results[0] 169 c.Assert(result.Error, gc.IsNil) 170 171 // Start a StringsWatcher and check the initial event. 172 w := watcher.NewStringsWatcher(s.stateAPI, result) 173 wc := statetesting.NewStringsWatcherC(c, s.State, w) 174 175 // Create a service, deploy a unit of it on the machine. 176 mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 177 principal, err := mysql.AddUnit() 178 c.Assert(err, jc.ErrorIsNil) 179 err = principal.AssignToMachine(s.rawMachine) 180 c.Assert(err, jc.ErrorIsNil) 181 182 // Ensure the initial event is delivered. Then test the watcher 183 // can be stopped cleanly without reading the pending change. 184 s.BackingState.StartSync() 185 statetesting.AssertCanStopWhenSending(c, w) 186 wc.AssertClosed() 187 }