github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/controller/crossmodelrelations/mock_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package crossmodelrelations_test 5 6 import ( 7 "fmt" 8 "sync" 9 "time" 10 11 "github.com/juju/errors" 12 "github.com/juju/testing" 13 "gopkg.in/juju/names.v2" 14 "gopkg.in/macaroon-bakery.v2-unstable/bakery/checkers" 15 "gopkg.in/macaroon.v2-unstable" 16 17 apitesting "github.com/juju/juju/api/testing" 18 "github.com/juju/juju/apiserver/authentication" 19 "github.com/juju/juju/apiserver/common" 20 commoncrossmodel "github.com/juju/juju/apiserver/common/crossmodel" 21 "github.com/juju/juju/apiserver/common/firewall" 22 "github.com/juju/juju/apiserver/facades/controller/crossmodelrelations" 23 "github.com/juju/juju/core/crossmodel" 24 "github.com/juju/juju/core/status" 25 "github.com/juju/juju/state" 26 coretesting "github.com/juju/juju/testing" 27 ) 28 29 type mockStatePool struct { 30 st map[string]commoncrossmodel.Backend 31 } 32 33 func (st *mockStatePool) Get(modelUUID string) (commoncrossmodel.Backend, func(), error) { 34 backend, ok := st.st[modelUUID] 35 if !ok { 36 return nil, nil, errors.NotFoundf("model for uuid %s", modelUUID) 37 } 38 return backend, func() {}, nil 39 } 40 41 type mockState struct { 42 testing.Stub 43 crossmodelrelations.CrossModelRelationsState 44 relations map[string]*mockRelation 45 remoteApplications map[string]*mockRemoteApplication 46 applications map[string]*mockApplication 47 offers map[string]*crossmodel.ApplicationOffer 48 offerConnections map[int]*mockOfferConnection 49 offerConnectionsByKey map[string]*mockOfferConnection 50 remoteEntities map[names.Tag]string 51 firewallRules map[state.WellKnownServiceType]*state.FirewallRule 52 ingressNetworks map[string][]string 53 } 54 55 func newMockState() *mockState { 56 return &mockState{ 57 relations: make(map[string]*mockRelation), 58 remoteApplications: make(map[string]*mockRemoteApplication), 59 applications: make(map[string]*mockApplication), 60 remoteEntities: make(map[names.Tag]string), 61 offers: make(map[string]*crossmodel.ApplicationOffer), 62 offerConnections: make(map[int]*mockOfferConnection), 63 offerConnectionsByKey: make(map[string]*mockOfferConnection), 64 firewallRules: make(map[state.WellKnownServiceType]*state.FirewallRule), 65 ingressNetworks: make(map[string][]string), 66 } 67 } 68 69 func (st *mockState) ApplicationOfferForUUID(offerUUID string) (*crossmodel.ApplicationOffer, error) { 70 offer, ok := st.offers[offerUUID] 71 if !ok { 72 return nil, errors.NotFoundf("offer %v", offerUUID) 73 } 74 return offer, nil 75 } 76 77 func (st *mockState) ApplicationOffer(offerName string) (*crossmodel.ApplicationOffer, error) { 78 for _, offer := range st.offers { 79 if offer.OfferName == offerName { 80 return offer, nil 81 } 82 } 83 return nil, errors.NotFoundf("offer %v", offerName) 84 } 85 86 func (st *mockState) ModelUUID() string { 87 return coretesting.ModelTag.Id() 88 } 89 90 func (st *mockState) Model() (crossmodelrelations.Model, error) { 91 return &mockModel{}, nil 92 } 93 94 func (st *mockState) AddRelation(eps ...state.Endpoint) (commoncrossmodel.Relation, error) { 95 rel := &mockRelation{ 96 id: len(st.relations), 97 key: fmt.Sprintf("%v:%v %v:%v", eps[0].ApplicationName, eps[0].Name, eps[1].ApplicationName, eps[1].Name), 98 } 99 if _, ok := st.relations[rel.key]; ok { 100 return nil, errors.AlreadyExistsf("relation %q", rel.key) 101 } 102 st.relations[rel.key] = rel 103 return rel, nil 104 } 105 106 func (st *mockState) AddOfferConnection(arg state.AddOfferConnectionParams) (crossmodelrelations.OfferConnection, error) { 107 if _, ok := st.offerConnections[arg.RelationId]; ok { 108 return nil, errors.AlreadyExistsf("offer connection for relation %d", arg.RelationId) 109 } 110 oc := &mockOfferConnection{ 111 sourcemodelUUID: arg.SourceModelUUID, 112 relationId: arg.RelationId, 113 relationKey: arg.RelationKey, 114 username: arg.Username, 115 offerUUID: arg.OfferUUID, 116 } 117 st.offerConnections[arg.RelationId] = oc 118 st.offerConnectionsByKey[arg.RelationKey] = oc 119 return oc, nil 120 } 121 122 func (st *mockState) FirewallRule(service state.WellKnownServiceType) (*state.FirewallRule, error) { 123 if r, ok := st.firewallRules[service]; ok { 124 return r, nil 125 } 126 return nil, errors.NotFoundf("firewall rule for %v", service) 127 } 128 129 func (st *mockState) SaveIngressNetworks(relationKey string, cidrs []string) (state.RelationNetworks, error) { 130 st.ingressNetworks[relationKey] = cidrs 131 return nil, nil 132 } 133 134 func (st *mockState) OfferConnectionForRelation(relationKey string) (crossmodelrelations.OfferConnection, error) { 135 oc, ok := st.offerConnectionsByKey[relationKey] 136 if !ok { 137 return nil, errors.NotFoundf("offer connection details for relation %v", relationKey) 138 } 139 return oc, nil 140 } 141 142 func (st *mockState) EndpointsRelation(eps ...state.Endpoint) (commoncrossmodel.Relation, error) { 143 key := fmt.Sprintf("%v:%v %v:%v", eps[0].ApplicationName, eps[0].Name, eps[1].ApplicationName, eps[1].Name) 144 if rel, ok := st.relations[key]; ok { 145 return rel, nil 146 } 147 return nil, errors.NotFoundf("relation with key %q", key) 148 } 149 150 func (st *mockState) AddRemoteApplication(params state.AddRemoteApplicationParams) (commoncrossmodel.RemoteApplication, error) { 151 app := &mockRemoteApplication{ 152 sourceModelUUID: params.SourceModel.Id(), 153 consumerproxy: params.IsConsumerProxy} 154 st.remoteApplications[params.Name] = app 155 return app, nil 156 } 157 158 func (st *mockState) ImportRemoteEntity(entity names.Tag, token string) error { 159 st.MethodCall(st, "ImportRemoteEntity", entity, token) 160 if err := st.NextErr(); err != nil { 161 return err 162 } 163 if _, ok := st.remoteEntities[entity]; ok { 164 return errors.AlreadyExistsf(entity.Id()) 165 } 166 st.remoteEntities[entity] = token 167 return nil 168 } 169 170 func (st *mockState) ExportLocalEntity(entity names.Tag) (string, error) { 171 st.MethodCall(st, "ExportLocalEntity", entity) 172 if err := st.NextErr(); err != nil { 173 return "", err 174 } 175 if token, ok := st.remoteEntities[entity]; ok { 176 return token, errors.AlreadyExistsf(entity.Id()) 177 } 178 token := "token-" + entity.Id() 179 st.remoteEntities[entity] = token 180 return token, nil 181 } 182 183 func (st *mockState) GetRemoteEntity(token string) (names.Tag, error) { 184 st.MethodCall(st, "GetRemoteEntity", token) 185 if err := st.NextErr(); err != nil { 186 return nil, err 187 } 188 for e, t := range st.remoteEntities { 189 if t == token { 190 return e, nil 191 } 192 } 193 return nil, errors.NotFoundf("token %v", token) 194 } 195 196 func (st *mockState) GetToken(entity names.Tag) (string, error) { 197 st.MethodCall(st, "GetToken", entity) 198 if err := st.NextErr(); err != nil { 199 return "", err 200 } 201 for e, t := range st.remoteEntities { 202 if e.Id() == entity.Id() { 203 return t, nil 204 } 205 } 206 return "", errors.NotFoundf("entity %v", entity) 207 } 208 209 func (st *mockState) KeyRelation(key string) (commoncrossmodel.Relation, error) { 210 st.MethodCall(st, "KeyRelation", key) 211 if err := st.NextErr(); err != nil { 212 return nil, err 213 } 214 r, ok := st.relations[key] 215 if !ok { 216 return nil, errors.NotFoundf("relation %q", key) 217 } 218 return r, nil 219 } 220 221 func (st *mockState) RemoteApplication(id string) (commoncrossmodel.RemoteApplication, error) { 222 st.MethodCall(st, "RemoteApplication", id) 223 if err := st.NextErr(); err != nil { 224 return nil, err 225 } 226 a, ok := st.remoteApplications[id] 227 if !ok { 228 return nil, errors.NotFoundf("remote application %q", id) 229 } 230 return a, nil 231 } 232 233 func (st *mockState) Application(id string) (commoncrossmodel.Application, error) { 234 st.MethodCall(st, "Application", id) 235 if err := st.NextErr(); err != nil { 236 return nil, err 237 } 238 a, ok := st.applications[id] 239 if !ok { 240 return nil, errors.NotFoundf("application %q", id) 241 } 242 return a, nil 243 } 244 245 type mockFirewallState struct { 246 firewall.State 247 } 248 249 type mockWatcher struct { 250 mu sync.Mutex 251 stopped chan struct{} 252 } 253 254 func (w *mockWatcher) Kill() { 255 w.mu.Lock() 256 defer w.mu.Unlock() 257 if !w.Stopped() { 258 close(w.stopped) 259 } 260 } 261 262 func (w *mockWatcher) Stop() error { 263 return nil 264 } 265 266 func (w *mockWatcher) Wait() error { 267 <-w.stopped 268 return nil 269 } 270 271 func (w *mockWatcher) Err() error { 272 return nil 273 } 274 275 func (w *mockWatcher) Stopped() bool { 276 select { 277 case <-w.stopped: 278 return true 279 default: 280 return false 281 } 282 } 283 284 type mockRelationStatusWatcher struct { 285 *mockWatcher 286 changes chan []string 287 } 288 289 func (w *mockRelationStatusWatcher) Changes() <-chan []string { 290 return w.changes 291 } 292 293 type mockOfferStatusWatcher struct { 294 *mockWatcher 295 offerUUID string 296 changes chan struct{} 297 } 298 299 func (w *mockOfferStatusWatcher) Changes() <-chan struct{} { 300 return w.changes 301 } 302 303 func (w *mockOfferStatusWatcher) OfferUUID() string { 304 return w.offerUUID 305 } 306 307 type mockModel struct { 308 } 309 310 func (m *mockModel) Name() string { 311 return "prod" 312 } 313 314 func (m *mockModel) Owner() names.UserTag { 315 return names.NewUserTag("fred") 316 } 317 318 type mockRelation struct { 319 commoncrossmodel.Relation 320 testing.Stub 321 id int 322 key string 323 suspended bool 324 suspendedReason string 325 status status.Status 326 message string 327 units map[string]commoncrossmodel.RelationUnit 328 } 329 330 func newMockRelation(id int) *mockRelation { 331 return &mockRelation{ 332 id: id, 333 units: make(map[string]commoncrossmodel.RelationUnit), 334 } 335 } 336 337 func (r *mockRelation) Id() int { 338 r.MethodCall(r, "Id") 339 return r.id 340 } 341 342 func (r *mockRelation) Tag() names.Tag { 343 r.MethodCall(r, "Tag") 344 return names.NewRelationTag(r.key) 345 } 346 347 func (r *mockRelation) Destroy() error { 348 r.MethodCall(r, "Destroy") 349 return r.NextErr() 350 } 351 352 func (r *mockRelation) Life() state.Life { 353 return state.Alive 354 } 355 356 func (r *mockRelation) SetStatus(statusInfo status.StatusInfo) error { 357 r.MethodCall(r, "SetStatus") 358 r.status = statusInfo.Status 359 r.message = statusInfo.Message 360 return nil 361 } 362 363 func (r *mockRelation) SetSuspended(suspended bool, reason string) error { 364 r.MethodCall(r, "SetSuspended") 365 r.suspended = suspended 366 r.suspendedReason = reason 367 return nil 368 } 369 370 func (r *mockRelation) Suspended() bool { 371 r.MethodCall(r, "Suspended") 372 return r.suspended 373 } 374 375 func (r *mockRelation) SuspendedReason() string { 376 r.MethodCall(r, "SuspendedReason") 377 return r.suspendedReason 378 } 379 380 func (r *mockRelation) RemoteUnit(unitId string) (commoncrossmodel.RelationUnit, error) { 381 r.MethodCall(r, "RemoteUnit", unitId) 382 if err := r.NextErr(); err != nil { 383 return nil, err 384 } 385 u, ok := r.units[unitId] 386 if !ok { 387 return nil, errors.NotFoundf("unit %q", unitId) 388 } 389 return u, nil 390 } 391 392 func (r *mockRelation) AllRemoteUnits(appName string) ([]commoncrossmodel.RelationUnit, error) { 393 r.MethodCall(r, "AllRemoteUnits", appName) 394 if err := r.NextErr(); err != nil { 395 return nil, err 396 } 397 var result []commoncrossmodel.RelationUnit 398 for _, ru := range r.units { 399 result = append(result, ru) 400 } 401 return result, nil 402 } 403 404 func (r *mockRelation) Unit(unitId string) (commoncrossmodel.RelationUnit, error) { 405 r.MethodCall(r, "Unit", unitId) 406 if err := r.NextErr(); err != nil { 407 return nil, err 408 } 409 u, ok := r.units[unitId] 410 if !ok { 411 return nil, errors.NotFoundf("unit %q", unitId) 412 } 413 return u, nil 414 } 415 416 func (u *mockRelationUnit) Settings() (map[string]interface{}, error) { 417 u.MethodCall(u, "Settings") 418 return u.settings, u.NextErr() 419 } 420 421 type mockRemoteApplication struct { 422 commoncrossmodel.RemoteApplication 423 testing.Stub 424 consumerproxy bool 425 sourceModelUUID string 426 } 427 428 func (r *mockRemoteApplication) IsConsumerProxy() bool { 429 r.MethodCall(r, "IsConsumerProxy") 430 return r.consumerproxy 431 } 432 433 func (r *mockRemoteApplication) Destroy() error { 434 r.MethodCall(r, "Destroy") 435 return r.NextErr() 436 } 437 438 type mockApplication struct { 439 commoncrossmodel.Application 440 testing.Stub 441 life state.Life 442 eps []state.Endpoint 443 } 444 445 func (a *mockApplication) Endpoints() ([]state.Endpoint, error) { 446 a.MethodCall(a, "Endpoints") 447 return a.eps, nil 448 } 449 450 func (a *mockApplication) Life() state.Life { 451 a.MethodCall(a, "Life") 452 return a.life 453 } 454 455 func (a *mockApplication) Status() (status.StatusInfo, error) { 456 a.MethodCall(a, "Status") 457 return status.StatusInfo{}, nil 458 } 459 460 type mockOfferConnection struct { 461 crossmodelrelations.OfferConnection 462 sourcemodelUUID string 463 relationId int 464 relationKey string 465 username string 466 offerUUID string 467 } 468 469 func (m *mockOfferConnection) OfferUUID() string { 470 return m.offerUUID 471 } 472 473 type mockRelationUnit struct { 474 commoncrossmodel.RelationUnit 475 testing.Stub 476 inScope bool 477 settings map[string]interface{} 478 } 479 480 func newMockRelationUnit() *mockRelationUnit { 481 return &mockRelationUnit{ 482 settings: make(map[string]interface{}), 483 } 484 } 485 486 func (u *mockRelationUnit) InScope() (bool, error) { 487 u.MethodCall(u, "InScope") 488 return u.inScope, u.NextErr() 489 } 490 491 func (u *mockRelationUnit) LeaveScope() error { 492 u.MethodCall(u, "LeaveScope") 493 if err := u.NextErr(); err != nil { 494 return err 495 } 496 u.inScope = false 497 return nil 498 } 499 500 func (u *mockRelationUnit) EnterScope(settings map[string]interface{}) error { 501 u.MethodCall(u, "EnterScope", settings) 502 if err := u.NextErr(); err != nil { 503 return err 504 } 505 u.inScope = true 506 u.settings = make(map[string]interface{}) 507 for k, v := range settings { 508 u.settings[k] = v 509 } 510 return nil 511 } 512 513 func (u *mockRelationUnit) ReplaceSettings(settings map[string]interface{}) error { 514 u.MethodCall(u, "ReplaceSettings", settings) 515 if err := u.NextErr(); err != nil { 516 return err 517 } 518 u.settings = make(map[string]interface{}) 519 for k, v := range settings { 520 u.settings[k] = v 521 } 522 return nil 523 } 524 525 type mockBakeryService struct { 526 testing.Stub 527 authentication.ExpirableStorageBakeryService 528 } 529 530 func (s *mockBakeryService) NewMacaroon(caveats []checkers.Caveat) (*macaroon.Macaroon, error) { 531 s.MethodCall(s, "NewMacaroon", caveats) 532 mac, err := apitesting.NewMacaroon("id") 533 if err != nil { 534 return nil, err 535 } 536 for _, cav := range caveats { 537 if err := mac.AddFirstPartyCaveat(cav.Condition); err != nil { 538 return nil, err 539 } 540 } 541 return mac, nil 542 } 543 544 func (s *mockBakeryService) CheckAny(ms []macaroon.Slice, assert map[string]string, checker checkers.Checker) (map[string]string, error) { 545 if len(ms) != 1 { 546 return nil, errors.New("unexpected macaroons") 547 } 548 if len(ms[0]) == 0 { 549 return nil, errors.New("no macaroons") 550 } 551 declared := checkers.InferDeclared(ms[0]) 552 for k, v := range assert { 553 if declared[k] != v { 554 return nil, common.ErrPerm 555 } 556 } 557 return declared, nil 558 } 559 560 func (s *mockBakeryService) ExpireStorageAfter(when time.Duration) (authentication.ExpirableStorageBakeryService, error) { 561 s.MethodCall(s, "ExpireStorageAfter", when) 562 return s, nil 563 }