github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/api/agent/uniter/leadership_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package uniter_test 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/testing" 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 12 "github.com/juju/juju/api/agent/uniter" 13 "github.com/juju/juju/core/watcher" 14 "github.com/juju/juju/rpc/params" 15 ) 16 17 type leadershipSuite struct { 18 testing.IsolationSuite 19 stub *testing.Stub 20 responders []responder 21 lsa *uniter.LeadershipSettingsAccessor 22 } 23 24 var _ = gc.Suite(&leadershipSuite{}) 25 26 type responder func(interface{}) 27 28 var mockWatcher = struct{ watcher.NotifyWatcher }{} 29 30 func (s *leadershipSuite) SetUpTest(c *gc.C) { 31 s.IsolationSuite.SetUpTest(c) 32 s.lsa = uniter.NewLeadershipSettingsAccessor( 33 func(request string, params, response interface{}) error { 34 s.stub.AddCall("FacadeCall", request, params) 35 s.nextResponse(response) 36 return s.stub.NextErr() 37 }, 38 func(result params.NotifyWatchResult) watcher.NotifyWatcher { 39 s.stub.AddCall("NewNotifyWatcher", result) 40 return mockWatcher 41 }, 42 ) 43 } 44 45 func (s *leadershipSuite) nextResponse(response interface{}) { 46 var responder responder 47 responder, s.responders = s.responders[0], s.responders[1:] 48 if responder != nil { 49 responder(response) 50 } 51 } 52 53 func (s *leadershipSuite) addResponder(responder responder) { 54 s.responders = append(s.responders, responder) 55 } 56 57 func (s *leadershipSuite) CheckCalls(c *gc.C, calls []testing.StubCall, f func()) { 58 s.stub = &testing.Stub{} 59 s.responders = nil 60 f() 61 s.stub.CheckCalls(c, calls) 62 } 63 64 func (s *leadershipSuite) expectReadCalls() []testing.StubCall { 65 return []testing.StubCall{{ 66 FuncName: "FacadeCall", 67 Args: []interface{}{ 68 "Read", 69 params.Entities{Entities: []params.Entity{{ 70 Tag: "application-foobar", 71 }}}, 72 }, 73 }} 74 } 75 76 func (s *leadershipSuite) TestReadSuccess(c *gc.C) { 77 s.CheckCalls(c, s.expectReadCalls(), func() { 78 s.addResponder(func(response interface{}) { 79 typed, ok := response.(*params.GetLeadershipSettingsBulkResults) 80 c.Assert(ok, jc.IsTrue) 81 typed.Results = []params.GetLeadershipSettingsResult{{ 82 Settings: params.Settings{ 83 "foo": "bar", 84 "baz": "qux", 85 }, 86 }} 87 }) 88 settings, err := s.lsa.Read("foobar") 89 c.Check(err, jc.ErrorIsNil) 90 c.Check(settings, jc.DeepEquals, map[string]string{ 91 "foo": "bar", 92 "baz": "qux", 93 }) 94 }) 95 } 96 97 func (s *leadershipSuite) TestReadFailure(c *gc.C) { 98 s.CheckCalls(c, s.expectReadCalls(), func() { 99 s.addResponder(func(response interface{}) { 100 typed, ok := response.(*params.GetLeadershipSettingsBulkResults) 101 c.Assert(ok, jc.IsTrue) 102 typed.Results = []params.GetLeadershipSettingsResult{{ 103 Error: ¶ms.Error{Message: "pow"}, 104 }} 105 }) 106 settings, err := s.lsa.Read("foobar") 107 c.Check(err, gc.ErrorMatches, "failed to read leadership settings: pow") 108 c.Check(settings, gc.IsNil) 109 }) 110 } 111 112 func (s *leadershipSuite) TestReadError(c *gc.C) { 113 s.CheckCalls(c, s.expectReadCalls(), func() { 114 s.addResponder(nil) 115 s.stub.SetErrors(errors.New("blart")) 116 settings, err := s.lsa.Read("foobar") 117 c.Check(err, gc.ErrorMatches, "failed to call leadership api: blart") 118 c.Check(settings, gc.IsNil) 119 }) 120 } 121 122 func (s *leadershipSuite) TestReadNoResults(c *gc.C) { 123 s.CheckCalls(c, s.expectReadCalls(), func() { 124 s.addResponder(nil) 125 settings, err := s.lsa.Read("foobar") 126 c.Check(err, gc.ErrorMatches, "expected 1 result from leadership api, got 0") 127 c.Check(settings, gc.IsNil) 128 }) 129 } 130 131 func (s *leadershipSuite) expectMergeCalls() []testing.StubCall { 132 return []testing.StubCall{{ 133 FuncName: "FacadeCall", 134 Args: []interface{}{ 135 "Merge", 136 params.MergeLeadershipSettingsBulkParams{ 137 Params: []params.MergeLeadershipSettingsParam{{ 138 ApplicationTag: "application-foobar", 139 UnitTag: "unit-foobar-0", 140 Settings: map[string]string{ 141 "foo": "bar", 142 "baz": "qux", 143 }, 144 }}, 145 }, 146 }, 147 }} 148 } 149 150 func (s *leadershipSuite) TestMergeSuccess(c *gc.C) { 151 s.CheckCalls(c, s.expectMergeCalls(), func() { 152 s.addResponder(func(response interface{}) { 153 typed, ok := response.(*params.ErrorResults) 154 c.Assert(ok, jc.IsTrue) 155 typed.Results = []params.ErrorResult{{ 156 Error: nil, 157 }} 158 }) 159 err := s.lsa.Merge("foobar", "foobar/0", map[string]string{ 160 "foo": "bar", 161 "baz": "qux", 162 }) 163 c.Check(err, jc.ErrorIsNil) 164 }) 165 } 166 167 func (s *leadershipSuite) TestMergeFailure(c *gc.C) { 168 s.CheckCalls(c, s.expectMergeCalls(), func() { 169 s.addResponder(func(response interface{}) { 170 typed, ok := response.(*params.ErrorResults) 171 c.Assert(ok, jc.IsTrue) 172 typed.Results = []params.ErrorResult{{ 173 Error: ¶ms.Error{Message: "zap"}, 174 }} 175 }) 176 err := s.lsa.Merge("foobar", "foobar/0", map[string]string{ 177 "foo": "bar", 178 "baz": "qux", 179 }) 180 c.Check(err, gc.ErrorMatches, "failed to merge leadership settings: zap") 181 }) 182 } 183 184 func (s *leadershipSuite) TestMergeError(c *gc.C) { 185 s.CheckCalls(c, s.expectMergeCalls(), func() { 186 s.addResponder(nil) 187 s.stub.SetErrors(errors.New("dink")) 188 err := s.lsa.Merge("foobar", "foobar/0", map[string]string{ 189 "foo": "bar", 190 "baz": "qux", 191 }) 192 c.Check(err, gc.ErrorMatches, "failed to call leadership api: dink") 193 }) 194 } 195 196 func (s *leadershipSuite) TestMergeNoResults(c *gc.C) { 197 s.CheckCalls(c, s.expectMergeCalls(), func() { 198 s.addResponder(nil) 199 err := s.lsa.Merge("foobar", "foobar/0", map[string]string{ 200 "foo": "bar", 201 "baz": "qux", 202 }) 203 c.Check(err, gc.ErrorMatches, "expected 1 result from leadership api, got 0") 204 }) 205 } 206 207 func (s *leadershipSuite) expectWatchCalls() []testing.StubCall { 208 return []testing.StubCall{{ 209 FuncName: "FacadeCall", 210 Args: []interface{}{ 211 "WatchLeadershipSettings", 212 params.Entities{Entities: []params.Entity{{ 213 Tag: "application-foobar", 214 }}}, 215 }, 216 }} 217 } 218 219 func (s *leadershipSuite) TestWatchSuccess(c *gc.C) { 220 expectCalls := append(s.expectWatchCalls(), testing.StubCall{ 221 FuncName: "NewNotifyWatcher", 222 Args: []interface{}{ 223 params.NotifyWatchResult{ 224 NotifyWatcherId: "123", 225 }, 226 }, 227 }) 228 s.CheckCalls(c, expectCalls, func() { 229 s.addResponder(func(response interface{}) { 230 typed, ok := response.(*params.NotifyWatchResults) 231 c.Assert(ok, jc.IsTrue) 232 typed.Results = []params.NotifyWatchResult{{ 233 NotifyWatcherId: "123", 234 }} 235 }) 236 watcher, err := s.lsa.WatchLeadershipSettings("foobar") 237 c.Check(err, jc.ErrorIsNil) 238 c.Check(watcher, gc.Equals, mockWatcher) 239 }) 240 } 241 242 func (s *leadershipSuite) TestWatchFailure(c *gc.C) { 243 s.CheckCalls(c, s.expectWatchCalls(), func() { 244 s.addResponder(func(response interface{}) { 245 typed, ok := response.(*params.NotifyWatchResults) 246 c.Assert(ok, jc.IsTrue) 247 typed.Results = []params.NotifyWatchResult{{ 248 Error: ¶ms.Error{Message: "blah"}, 249 }} 250 }) 251 watcher, err := s.lsa.WatchLeadershipSettings("foobar") 252 c.Check(err, gc.ErrorMatches, "failed to watch leadership settings: blah") 253 c.Check(watcher, gc.IsNil) 254 }) 255 } 256 257 func (s *leadershipSuite) TestWatchError(c *gc.C) { 258 s.CheckCalls(c, s.expectWatchCalls(), func() { 259 s.addResponder(nil) 260 s.stub.SetErrors(errors.New("snerk")) 261 watcher, err := s.lsa.WatchLeadershipSettings("foobar") 262 c.Check(err, gc.ErrorMatches, "failed to call leadership api: snerk") 263 c.Check(watcher, gc.IsNil) 264 }) 265 } 266 267 func (s *leadershipSuite) TestWatchNoResults(c *gc.C) { 268 s.CheckCalls(c, s.expectWatchCalls(), func() { 269 s.addResponder(nil) 270 watcher, err := s.lsa.WatchLeadershipSettings("foobar") 271 c.Check(err, gc.ErrorMatches, "expected 1 result from leadership api, got 0") 272 c.Check(watcher, gc.IsNil) 273 }) 274 }