github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/externalcontrollerupdater/externalcontrollerupdater_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package externalcontrollerupdater_test 5 6 import ( 7 "time" 8 9 "github.com/juju/clock/testclock" 10 "github.com/juju/errors" 11 "github.com/juju/testing" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 "gopkg.in/juju/names.v2" 15 "gopkg.in/juju/worker.v1/workertest" 16 17 "github.com/juju/juju/api" 18 "github.com/juju/juju/api/crosscontroller" 19 "github.com/juju/juju/core/crossmodel" 20 coretesting "github.com/juju/juju/testing" 21 "github.com/juju/juju/worker/externalcontrollerupdater" 22 ) 23 24 var _ = gc.Suite(&ExternalControllerUpdaterSuite{}) 25 26 type ExternalControllerUpdaterSuite struct { 27 coretesting.BaseSuite 28 29 updater mockExternalControllerUpdaterClient 30 watcher mockExternalControllerWatcherClient 31 32 clock *testclock.Clock 33 34 stub testing.Stub 35 newWatcher externalcontrollerupdater.NewExternalControllerWatcherClientFunc 36 } 37 38 func (s *ExternalControllerUpdaterSuite) SetUpTest(c *gc.C) { 39 s.BaseSuite.SetUpTest(c) 40 41 s.updater = mockExternalControllerUpdaterClient{ 42 watcher: newMockStringsWatcher(), 43 info: crossmodel.ControllerInfo{ 44 ControllerTag: coretesting.ControllerTag, 45 Alias: "foo", 46 Addrs: []string{"bar"}, 47 CACert: "baz", 48 }, 49 } 50 s.AddCleanup(func(*gc.C) { s.updater.watcher.Stop() }) 51 52 s.watcher = mockExternalControllerWatcherClient{ 53 watcher: newMockNotifyWatcher(), 54 info: crosscontroller.ControllerInfo{ 55 Addrs: []string{"foo"}, 56 CACert: "bar", 57 }, 58 } 59 s.AddCleanup(func(*gc.C) { s.watcher.watcher.Stop() }) 60 61 s.clock = testclock.NewClock(time.Time{}) 62 63 s.stub.ResetCalls() 64 s.newWatcher = func(apiInfo *api.Info) (externalcontrollerupdater.ExternalControllerWatcherClientCloser, error) { 65 s.stub.AddCall("NextExternalControllerWatcherClient", apiInfo) 66 if err := s.stub.NextErr(); err != nil { 67 return nil, err 68 } 69 return &s.watcher, nil 70 } 71 } 72 73 func (s *ExternalControllerUpdaterSuite) TestStartStop(c *gc.C) { 74 w, err := externalcontrollerupdater.New(&s.updater, s.newWatcher, s.clock) 75 c.Assert(err, jc.ErrorIsNil) 76 workertest.CleanKill(c, w) 77 } 78 79 func (s *ExternalControllerUpdaterSuite) TestWatchExternalControllersCalled(c *gc.C) { 80 s.updater.watcher.changes = make(chan []string) 81 82 w, err := externalcontrollerupdater.New(&s.updater, s.newWatcher, s.clock) 83 c.Assert(err, jc.ErrorIsNil) 84 defer workertest.CleanKill(c, w) 85 86 select { 87 case s.updater.watcher.changes <- []string{}: 88 case <-time.After(coretesting.LongWait): 89 c.Fatal("timed out waiting to send changes") 90 } 91 92 workertest.CleanKill(c, w) 93 s.updater.Stub.CheckCallNames(c, "WatchExternalControllers") 94 } 95 96 func (s *ExternalControllerUpdaterSuite) TestWatchExternalControllers(c *gc.C) { 97 s.updater.watcher.changes <- []string{coretesting.ControllerTag.Id()} 98 99 w, err := externalcontrollerupdater.New(&s.updater, s.newWatcher, s.clock) 100 c.Assert(err, jc.ErrorIsNil) 101 defer workertest.CleanKill(c, w) 102 103 // Cause three notifications. Only the first notification is 104 // accompanied by API address changes, so there should be only 105 // one API reconnection, and one local controller update. 106 for i := 0; i < 3; i++ { 107 select { 108 case s.watcher.watcher.changes <- struct{}{}: 109 case <-time.After(coretesting.LongWait): 110 c.Fatal("timed out waiting to send changes") 111 } 112 } 113 114 workertest.CleanKill(c, w) 115 s.stub.CheckCalls(c, []testing.StubCall{{ 116 "NextExternalControllerWatcherClient", 117 []interface{}{&api.Info{ 118 Addrs: s.updater.info.Addrs, 119 CACert: s.updater.info.CACert, 120 Tag: names.NewUserTag("jujuanonymous"), 121 }}, 122 }, { 123 "NextExternalControllerWatcherClient", 124 []interface{}{&api.Info{ 125 Addrs: s.watcher.info.Addrs, 126 CACert: s.updater.info.CACert, // only addresses are updated 127 Tag: names.NewUserTag("jujuanonymous"), 128 }}, 129 }}) 130 s.updater.Stub.CheckCalls(c, []testing.StubCall{{ 131 "WatchExternalControllers", 132 []interface{}{}, 133 }, { 134 "ExternalControllerInfo", 135 []interface{}{coretesting.ControllerTag.Id()}, 136 }, { 137 "SetExternalControllerInfo", 138 []interface{}{crossmodel.ControllerInfo{ 139 ControllerTag: s.updater.info.ControllerTag, 140 Alias: s.updater.info.Alias, 141 Addrs: s.watcher.info.Addrs, // new addrs 142 CACert: s.updater.info.CACert, 143 }}, 144 }}) 145 s.watcher.Stub.CheckCallNames(c, 146 "WatchControllerInfo", 147 "ControllerInfo", 148 "Close", 149 "WatchControllerInfo", 150 "ControllerInfo", // no change 151 "ControllerInfo", // no change 152 "Close", 153 ) 154 } 155 156 func (s *ExternalControllerUpdaterSuite) TestWatchExternalControllersErrorsContained(c *gc.C) { 157 // The first time we attempt to connect to the external controller, 158 // the dial should fail. The runner will reschedule the worker to 159 // try again. 160 s.stub.SetErrors(errors.New("no API connection for you")) 161 162 s.updater.watcher.changes <- []string{coretesting.ControllerTag.Id()} 163 s.watcher.watcher.changes = make(chan struct{}) 164 s.watcher.info.Addrs = s.updater.info.Addrs // no change 165 166 w, err := externalcontrollerupdater.New(&s.updater, s.newWatcher, s.clock) 167 c.Assert(err, jc.ErrorIsNil) 168 defer workertest.CleanKill(c, w) 169 170 // The first run of the controller worker should fail to 171 // connect to the API, and should abort. The runner should 172 // then be waiting for a minute to restart the controller 173 // worker. 174 s.clock.WaitAdvance(time.Second, coretesting.LongWait, 1) 175 s.clock.WaitAdvance(59*time.Second, coretesting.LongWait, 1) 176 177 // The controller worker should have been restarted now. 178 select { 179 case s.watcher.watcher.changes <- struct{}{}: 180 case <-time.After(coretesting.LongWait): 181 c.Fatal("timed out waiting to send changes") 182 } 183 184 workertest.CleanKill(c, w) 185 s.stub.CheckCalls(c, []testing.StubCall{{ 186 "NextExternalControllerWatcherClient", 187 []interface{}{&api.Info{ 188 Addrs: s.updater.info.Addrs, 189 CACert: s.updater.info.CACert, 190 Tag: names.NewUserTag("jujuanonymous"), 191 }}, 192 }, { 193 "NextExternalControllerWatcherClient", 194 []interface{}{&api.Info{ 195 Addrs: s.updater.info.Addrs, 196 CACert: s.updater.info.CACert, 197 Tag: names.NewUserTag("jujuanonymous"), 198 }}, 199 }}) 200 s.updater.Stub.CheckCallNames(c, 201 "WatchExternalControllers", 202 "ExternalControllerInfo", 203 "ExternalControllerInfo", 204 ) 205 s.watcher.Stub.CheckCallNames(c, 206 "WatchControllerInfo", 207 "ControllerInfo", 208 "Close", 209 ) 210 }