github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/worker/instancepoller/updater_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // TODO(wallyworld) - move to instancepoller_test 5 package instancepoller 6 7 import ( 8 "errors" 9 stdtesting "testing" 10 "time" 11 12 jc "github.com/juju/testing/checkers" 13 gc "launchpad.net/gocheck" 14 15 "github.com/juju/juju/state" 16 "github.com/juju/juju/state/api/params" 17 coretesting "github.com/juju/juju/testing" 18 ) 19 20 func TestPackage(t *stdtesting.T) { 21 coretesting.MgoTestPackage(t) 22 } 23 24 var _ = gc.Suite(&updaterSuite{}) 25 26 type updaterSuite struct { 27 coretesting.BaseSuite 28 } 29 30 func (*updaterSuite) TestStopsWatcher(c *gc.C) { 31 context := &testUpdaterContext{ 32 dyingc: make(chan struct{}), 33 } 34 expectErr := errors.New("some error") 35 watcher := &testMachinesWatcher{ 36 changes: make(chan []string), 37 err: expectErr, 38 } 39 done := make(chan error) 40 go func() { 41 done <- watchMachinesLoop(context, watcher) 42 }() 43 close(context.dyingc) 44 select { 45 case err := <-done: 46 c.Assert(err, gc.ErrorMatches, ".*"+expectErr.Error()) 47 case <-time.After(coretesting.LongWait): 48 c.Fatalf("timed out waiting for watchMachinesLoop to terminate") 49 } 50 c.Assert(watcher.stopped, jc.IsTrue) 51 } 52 53 func (*updaterSuite) TestWatchMachinesWaitsForMachinePollers(c *gc.C) { 54 // We can't see that the machine pollers are still alive directly, 55 // but we can make the machine's Refresh method block, 56 // and test that watchMachinesLoop only terminates 57 // when it unblocks. 58 waitRefresh := make(chan struct{}) 59 m := &testMachine{ 60 id: "99", 61 instanceId: "i1234", 62 life: state.Alive, 63 refresh: func() error { 64 // Signal that we're in Refresh. 65 waitRefresh <- struct{}{} 66 // Wait to be unblocked. 67 <-waitRefresh 68 return nil 69 }, 70 } 71 dyingc := make(chan struct{}) 72 context := &testUpdaterContext{ 73 dyingc: dyingc, 74 newMachineContextFunc: func() machineContext { 75 return &testMachineContext{ 76 getInstanceInfo: instanceInfoGetter(c, "i1234", testAddrs, "running", nil), 77 dyingc: dyingc, 78 } 79 }, 80 getMachineFunc: func(id string) (machine, error) { 81 c.Check(id, gc.Equals, m.id) 82 return m, nil 83 }, 84 } 85 watcher := &testMachinesWatcher{ 86 changes: make(chan []string), 87 } 88 done := make(chan error) 89 go func() { 90 done <- watchMachinesLoop(context, watcher) 91 }() 92 // Send two changes; the first one should start the machineLoop; 93 // the second should call Refresh. 94 watcher.changes <- []string{"99"} 95 watcher.changes <- []string{"99"} 96 // Wait for the machineLoop to call Refresh 97 select { 98 case <-waitRefresh: 99 c.Logf("poller called Refresh") 100 case <-time.After(coretesting.LongWait): 101 c.Fatalf("timed out waiting for machine to be refreshed") 102 } 103 close(context.dyingc) 104 // Wait a little while to be sure that watchMachinesLoop is 105 // actually waiting for its machine poller to finish. 106 select { 107 case err := <-done: 108 c.Fatalf("watchMachinesLoop terminated prematurely: %v", err) 109 case <-time.After(coretesting.ShortWait): 110 } 111 112 waitRefresh <- struct{}{} 113 select { 114 case err := <-done: 115 c.Assert(err, gc.IsNil) 116 case <-time.After(coretesting.LongWait): 117 c.Fatalf("timed out waiting for watchMachinesLoop to terminate") 118 } 119 c.Assert(watcher.stopped, jc.IsTrue) 120 } 121 122 func (s *updaterSuite) TestManualMachinesIgnored(c *gc.C) { 123 waitStatus := make(chan struct{}) 124 s.PatchValue(&MachineStatus, func(m *testMachine) (status params.Status, info string, data params.StatusData, err error) { 125 // Signal that we're in Status. 126 waitStatus <- struct{}{} 127 return params.StatusPending, "", params.StatusData{}, nil 128 }) 129 m := &testMachine{ 130 id: "99", 131 instanceId: "manual:1234", 132 life: state.Alive, 133 } 134 dyingc := make(chan struct{}) 135 context := &testUpdaterContext{ 136 dyingc: dyingc, 137 newMachineContextFunc: func() machineContext { 138 return &testMachineContext{ 139 getInstanceInfo: instanceInfoGetter(c, "manual:1234", testAddrs, "running", nil), 140 dyingc: dyingc, 141 } 142 }, 143 getMachineFunc: func(id string) (machine, error) { 144 c.Check(id, gc.Equals, m.id) 145 return m, nil 146 }, 147 } 148 watcher := &testMachinesWatcher{ 149 changes: make(chan []string), 150 } 151 done := make(chan error) 152 go func() { 153 done <- watchMachinesLoop(context, watcher) 154 }() 155 // Send a change to start the machineLoop; 156 watcher.changes <- []string{"99"} 157 select { 158 case <-waitStatus: 159 c.Fatalf("poller called Status") 160 case <-time.After(coretesting.ShortWait): 161 c.Logf("status not called") 162 } 163 close(context.dyingc) 164 select { 165 case err := <-done: 166 c.Assert(err, gc.IsNil) 167 case <-time.After(coretesting.LongWait): 168 c.Fatalf("timed out waiting for watchMachinesLoop to terminate") 169 } 170 c.Assert(watcher.stopped, jc.IsTrue) 171 } 172 173 type testUpdaterContext struct { 174 newMachineContextFunc func() machineContext 175 getMachineFunc func(id string) (machine, error) 176 dyingc chan struct{} 177 } 178 179 func (context *testUpdaterContext) newMachineContext() machineContext { 180 return context.newMachineContextFunc() 181 } 182 183 func (context *testUpdaterContext) getMachine(id string) (machine, error) { 184 return context.getMachineFunc(id) 185 } 186 187 func (context *testUpdaterContext) dying() <-chan struct{} { 188 return context.dyingc 189 } 190 191 type testMachinesWatcher struct { 192 stopped bool 193 changes chan []string 194 err error 195 } 196 197 func (w *testMachinesWatcher) Changes() <-chan []string { 198 return w.changes 199 } 200 201 func (w *testMachinesWatcher) Stop() error { 202 w.stopped = true 203 return w.err 204 } 205 206 func (w *testMachinesWatcher) Err() error { 207 return w.err 208 }