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