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