github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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 "github.com/juju/names" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/apiserver/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 tag: names.NewMachineTag("99"), 61 instanceId: "i1234", 62 life: params.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(tag names.MachineTag) (machine, error) { 81 c.Check(tag, jc.DeepEquals, m.tag) 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, jc.ErrorIsNil) 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) (params.StatusResult, error) { 125 // Signal that we're in Status. 126 waitStatus <- struct{}{} 127 return params.StatusResult{ 128 Status: params.StatusPending, 129 Info: "", 130 Data: map[string]interface{}{}, 131 Since: nil, 132 }, nil 133 }) 134 m := &testMachine{ 135 tag: names.NewMachineTag("99"), 136 instanceId: "manual:1234", 137 life: params.Alive, 138 } 139 dyingc := make(chan struct{}) 140 context := &testUpdaterContext{ 141 dyingc: dyingc, 142 newMachineContextFunc: func() machineContext { 143 return &testMachineContext{ 144 getInstanceInfo: instanceInfoGetter(c, "manual:1234", testAddrs, "running", nil), 145 dyingc: dyingc, 146 } 147 }, 148 getMachineFunc: func(tag names.MachineTag) (machine, error) { 149 c.Check(tag, jc.DeepEquals, m.tag) 150 return m, nil 151 }, 152 } 153 watcher := &testMachinesWatcher{ 154 changes: make(chan []string), 155 } 156 done := make(chan error) 157 go func() { 158 done <- watchMachinesLoop(context, watcher) 159 }() 160 // Send a change to start the machineLoop; 161 watcher.changes <- []string{"99"} 162 select { 163 case <-waitStatus: 164 c.Fatalf("poller called Status") 165 case <-time.After(coretesting.ShortWait): 166 c.Logf("status not called") 167 } 168 close(context.dyingc) 169 select { 170 case err := <-done: 171 c.Assert(err, jc.ErrorIsNil) 172 case <-time.After(coretesting.LongWait): 173 c.Fatalf("timed out waiting for watchMachinesLoop to terminate") 174 } 175 c.Assert(watcher.stopped, jc.IsTrue) 176 } 177 178 type testUpdaterContext struct { 179 newMachineContextFunc func() machineContext 180 getMachineFunc func(tag names.MachineTag) (machine, error) 181 dyingc chan struct{} 182 } 183 184 func (context *testUpdaterContext) newMachineContext() machineContext { 185 return context.newMachineContextFunc() 186 } 187 188 func (context *testUpdaterContext) getMachine(tag names.MachineTag) (machine, error) { 189 return context.getMachineFunc(tag) 190 } 191 192 func (context *testUpdaterContext) dying() <-chan struct{} { 193 return context.dyingc 194 } 195 196 type testMachinesWatcher struct { 197 stopped bool 198 changes chan []string 199 err error 200 } 201 202 func (w *testMachinesWatcher) Changes() <-chan []string { 203 return w.changes 204 } 205 206 func (w *testMachinesWatcher) Stop() error { 207 w.stopped = true 208 return w.err 209 } 210 211 func (w *testMachinesWatcher) Err() error { 212 return w.err 213 }