github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/firewall/mock_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package firewall_test 5 6 import ( 7 "sync" 8 9 "github.com/juju/errors" 10 "github.com/juju/names/v5" 11 "github.com/juju/testing" 12 "gopkg.in/macaroon.v2" 13 "gopkg.in/tomb.v2" 14 15 "github.com/juju/juju/apiserver/common/firewall" 16 "github.com/juju/juju/controller" 17 "github.com/juju/juju/core/crossmodel" 18 "github.com/juju/juju/core/network" 19 "github.com/juju/juju/core/watcher" 20 "github.com/juju/juju/environs/config" 21 "github.com/juju/juju/state" 22 coretesting "github.com/juju/juju/testing" 23 ) 24 25 type mockState struct { 26 // TODO - implement when remaining firewaller tests become unit tests 27 state.ModelMachinesWatcher 28 29 testing.Stub 30 modelUUID string 31 remoteEntities map[names.Tag]string 32 macaroons map[names.Tag]*macaroon.Macaroon 33 applications map[string]*mockApplication 34 units map[string]*mockUnit 35 machines map[string]*mockMachine 36 relations map[string]*mockRelation 37 controllerInfo map[string]*mockControllerInfo 38 subnetsWatcher *mockStringsWatcher 39 modelWatcher *mockNotifyWatcher 40 configAttrs map[string]interface{} 41 } 42 43 func newMockState(modelUUID string) *mockState { 44 return &mockState{ 45 modelUUID: modelUUID, 46 relations: make(map[string]*mockRelation), 47 applications: make(map[string]*mockApplication), 48 units: make(map[string]*mockUnit), 49 machines: make(map[string]*mockMachine), 50 remoteEntities: make(map[names.Tag]string), 51 macaroons: make(map[names.Tag]*macaroon.Macaroon), 52 controllerInfo: make(map[string]*mockControllerInfo), 53 subnetsWatcher: newMockStringsWatcher(), 54 modelWatcher: newMockNotifyWatcher(), 55 configAttrs: coretesting.FakeConfig(), 56 } 57 } 58 59 func (st *mockState) WatchForModelConfigChanges() state.NotifyWatcher { 60 return st.modelWatcher 61 } 62 63 func (st *mockState) ModelConfig() (*config.Config, error) { 64 return config.New(config.UseDefaults, st.configAttrs) 65 } 66 67 func (st *mockState) ControllerConfig() (controller.Config, error) { 68 return nil, errors.NotImplementedf("ControllerConfig") 69 } 70 71 func (st *mockState) ControllerInfo(modelUUID string) ([]string, string, error) { 72 if info, ok := st.controllerInfo[modelUUID]; !ok { 73 return nil, "", errors.NotFoundf("controller info for %v", modelUUID) 74 } else { 75 return info.ControllerInfo().Addrs, info.ControllerInfo().CACert, nil 76 } 77 } 78 79 func (st *mockState) GetMacaroon(model names.ModelTag, entity names.Tag) (*macaroon.Macaroon, error) { 80 st.MethodCall(st, "GetMacaroon", model, entity) 81 if err := st.NextErr(); err != nil { 82 return nil, err 83 } 84 mac, ok := st.macaroons[entity] 85 if !ok { 86 return nil, errors.NotFoundf("macaroon for %v", entity) 87 } 88 return mac, nil 89 } 90 91 func (st *mockState) ModelUUID() string { 92 return st.modelUUID 93 } 94 95 func (st *mockState) Application(id string) (firewall.Application, error) { 96 st.MethodCall(st, "Application", id) 97 if err := st.NextErr(); err != nil { 98 return nil, err 99 } 100 a, ok := st.applications[id] 101 if !ok { 102 return nil, errors.NotFoundf("application %q", id) 103 } 104 return a, nil 105 } 106 107 func (st *mockState) Unit(name string) (firewall.Unit, error) { 108 st.MethodCall(st, "Unit", name) 109 if err := st.NextErr(); err != nil { 110 return nil, err 111 } 112 u, ok := st.units[name] 113 if !ok { 114 return nil, errors.NotFoundf("unit %q", name) 115 } 116 return u, nil 117 } 118 119 func (st *mockState) Machine(id string) (firewall.Machine, error) { 120 st.MethodCall(st, "Machine", id) 121 if err := st.NextErr(); err != nil { 122 return nil, err 123 } 124 m, ok := st.machines[id] 125 if !ok { 126 return nil, errors.NotFoundf("machine %q", id) 127 } 128 return m, nil 129 } 130 131 func (st *mockState) WatchSubnets(func(id interface{}) bool) state.StringsWatcher { 132 st.MethodCall(st, "WatchSubnets") 133 return st.subnetsWatcher 134 } 135 136 func (st *mockState) WatchOpenedPorts() state.StringsWatcher { 137 st.MethodCall(st, "WatchOpenedPorts") 138 // TODO - implement when remaining firewaller tests become unit tests 139 return nil 140 } 141 142 func (st *mockState) FindEntity(tag names.Tag) (state.Entity, error) { 143 st.MethodCall(st, "FindEntity") 144 // TODO - implement when remaining firewaller tests become unit tests 145 return nil, errors.NotImplementedf("FindEntity") 146 } 147 148 func (st *mockState) GetModel(tag names.ModelTag) (*state.Model, error) { 149 st.MethodCall(st, "GetModel", tag) 150 // TODO - implement when remaining firewaller tests become unit tests 151 return nil, errors.NotImplementedf("GetModel") 152 } 153 154 type mockWatcher struct { 155 testing.Stub 156 tomb.Tomb 157 } 158 159 func (w *mockWatcher) Kill() { 160 w.MethodCall(w, "Kill") 161 w.Tomb.Kill(nil) 162 } 163 164 func (w *mockWatcher) Stop() error { 165 w.MethodCall(w, "Stop") 166 if err := w.NextErr(); err != nil { 167 return err 168 } 169 w.Tomb.Kill(nil) 170 return w.Tomb.Wait() 171 } 172 173 func (w *mockWatcher) Err() error { 174 w.MethodCall(w, "Err") 175 return w.Tomb.Err() 176 } 177 178 type mockStringsWatcher struct { 179 mockWatcher 180 changes chan []string 181 } 182 183 func newMockStringsWatcher() *mockStringsWatcher { 184 w := &mockStringsWatcher{changes: make(chan []string, 1)} 185 w.Tomb.Go(func() error { 186 <-w.Tomb.Dying() 187 return nil 188 }) 189 return w 190 } 191 192 func (w *mockStringsWatcher) Changes() <-chan []string { 193 w.MethodCall(w, "Changes") 194 return w.changes 195 } 196 197 func newMockNotifyWatcher() *mockNotifyWatcher { 198 w := &mockNotifyWatcher{changes: make(chan struct{}, 1)} 199 // Initial event 200 w.changes <- struct{}{} 201 w.Tomb.Go(func() error { 202 <-w.Tomb.Dying() 203 return nil 204 }) 205 return w 206 } 207 208 type mockNotifyWatcher struct { 209 mockWatcher 210 changes chan struct{} 211 } 212 213 func (w *mockNotifyWatcher) Changes() <-chan struct{} { 214 w.MethodCall(w, "Changes") 215 return w.changes 216 } 217 218 type mockApplication struct { 219 testing.Stub 220 name string 221 units []*mockUnit 222 } 223 224 func newMockApplication(name string) *mockApplication { 225 return &mockApplication{ 226 name: name, 227 } 228 } 229 230 func (a *mockApplication) Name() string { 231 a.MethodCall(a, "Name") 232 return a.name 233 } 234 235 func (a *mockApplication) AllUnits() (results []firewall.Unit, err error) { 236 a.MethodCall(a, "AllUnits") 237 for _, unit := range a.units { 238 results = append(results, unit) 239 } 240 return results, a.NextErr() 241 } 242 243 type mockControllerInfo struct { 244 uuid string 245 info crossmodel.ControllerInfo 246 } 247 248 func (c *mockControllerInfo) Id() string { 249 return c.uuid 250 } 251 252 func (c *mockControllerInfo) ControllerInfo() crossmodel.ControllerInfo { 253 return c.info 254 } 255 256 type mockRelation struct { 257 testing.Stub 258 firewall.Relation 259 id int 260 endpoints []state.Endpoint 261 ruw *mockRelationUnitsWatcher 262 ew *mockStringsWatcher 263 ruwApp string 264 } 265 266 func newMockRelation(id int) *mockRelation { 267 return &mockRelation{ 268 id: id, 269 ruw: newMockRelationUnitsWatcher(), 270 ew: newMockStringsWatcher(), 271 } 272 } 273 274 func (r *mockRelation) Id() int { 275 r.MethodCall(r, "Id") 276 return r.id 277 } 278 279 func (r *mockRelation) Endpoints() []state.Endpoint { 280 r.MethodCall(r, "Endpoints") 281 return r.endpoints 282 } 283 284 func (r *mockRelation) WatchUnits(applicationName string) (state.RelationUnitsWatcher, error) { 285 if r.ruwApp != applicationName { 286 return nil, errors.Errorf("unexpected app %v", applicationName) 287 } 288 return r.ruw, nil 289 } 290 291 func (r *mockRelation) WatchRelationEgressNetworks() state.StringsWatcher { 292 return r.ew 293 } 294 295 func newMockRelationUnitsWatcher() *mockRelationUnitsWatcher { 296 w := &mockRelationUnitsWatcher{changes: make(chan watcher.RelationUnitsChange, 1)} 297 w.Tomb.Go(func() error { 298 <-w.Tomb.Dying() 299 return nil 300 }) 301 return w 302 } 303 304 type mockRelationUnitsWatcher struct { 305 mockWatcher 306 changes chan watcher.RelationUnitsChange 307 } 308 309 func (w *mockRelationUnitsWatcher) Changes() watcher.RelationUnitsChannel { 310 return w.changes 311 } 312 313 func (st *mockState) GetRemoteEntity(sourceModel names.ModelTag, token string) (names.Tag, error) { 314 st.MethodCall(st, "GetRemoteEntity", sourceModel, token) 315 if err := st.NextErr(); err != nil { 316 return nil, err 317 } 318 for e, t := range st.remoteEntities { 319 if t == token { 320 return e, nil 321 } 322 } 323 return nil, errors.NotFoundf("token %v", token) 324 } 325 326 func (st *mockState) KeyRelation(key string) (firewall.Relation, error) { 327 st.MethodCall(st, "KeyRelation", key) 328 if err := st.NextErr(); err != nil { 329 return nil, err 330 } 331 r, ok := st.relations[key] 332 if !ok { 333 return nil, errors.NotFoundf("relation %q", key) 334 } 335 return r, nil 336 } 337 338 type mockUnit struct { 339 testing.Stub 340 mu sync.Mutex 341 name string 342 assigned bool 343 publicAddress network.SpaceAddress 344 machineId string 345 } 346 347 func newMockUnit(name string) *mockUnit { 348 return &mockUnit{ 349 name: name, 350 assigned: true, 351 } 352 } 353 354 func (u *mockUnit) Name() string { 355 u.MethodCall(u, "Name") 356 return u.name 357 } 358 359 func (u *mockUnit) PublicAddress() (network.SpaceAddress, error) { 360 u.MethodCall(u, "PublicAddress") 361 u.mu.Lock() 362 defer u.mu.Unlock() 363 364 if err := u.NextErr(); err != nil { 365 return network.SpaceAddress{}, err 366 } 367 if !u.assigned { 368 return network.SpaceAddress{}, errors.NotAssignedf(u.name) 369 } 370 if u.publicAddress.Value == "" { 371 return network.SpaceAddress{}, network.NoAddressError("public") 372 } 373 return u.publicAddress, nil 374 } 375 376 func (u *mockUnit) AssignedMachineId() (string, error) { 377 u.MethodCall(u, "AssignedMachineId") 378 if err := u.NextErr(); err != nil { 379 return "", err 380 } 381 if !u.assigned { 382 return "", errors.NotAssignedf(u.name) 383 } 384 return u.machineId, nil 385 } 386 387 func (u *mockUnit) updateAddress(value string) { 388 u.mu.Lock() 389 defer u.mu.Unlock() 390 391 u.publicAddress = network.NewSpaceAddress(value) 392 } 393 394 type mockMachine struct { 395 firewall.Machine 396 397 testing.Stub 398 id string 399 watcher *mockAddressWatcher 400 } 401 402 func newMockMachine(id string) *mockMachine { 403 return &mockMachine{ 404 id: id, 405 watcher: newMockAddressWatcher(), 406 } 407 } 408 409 func (m *mockMachine) Id() string { 410 m.MethodCall(m, "Id") 411 return m.id 412 } 413 414 func (m *mockMachine) WatchAddresses() state.NotifyWatcher { 415 m.MethodCall(m, "WatchAddresses") 416 return m.watcher 417 } 418 419 type mockAddressWatcher struct { 420 mockWatcher 421 changes chan struct{} 422 } 423 424 func newMockAddressWatcher() *mockAddressWatcher { 425 w := &mockAddressWatcher{changes: make(chan struct{}, 1)} 426 w.Tomb.Go(func() error { 427 <-w.Tomb.Dying() 428 return nil 429 }) 430 return w 431 } 432 433 func (w *mockAddressWatcher) Changes() <-chan struct{} { 434 w.MethodCall(w, "Changes") 435 return w.changes 436 }