github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/uniter/remotestate/mock_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package remotestate_test 5 6 import ( 7 "sync" 8 "time" 9 10 "github.com/juju/errors" 11 "github.com/juju/names/v5" 12 13 "github.com/juju/juju/core/leadership" 14 "github.com/juju/juju/core/life" 15 "github.com/juju/juju/core/model" 16 "github.com/juju/juju/core/secrets" 17 "github.com/juju/juju/core/watcher" 18 "github.com/juju/juju/rpc/params" 19 "github.com/juju/juju/worker/uniter/remotestate" 20 ) 21 22 func newMockWatcher() *mockWatcher { 23 return &mockWatcher{ 24 stopped: make(chan struct{}), 25 } 26 } 27 28 type mockWatcher struct { 29 mu sync.Mutex 30 stopped chan struct{} 31 } 32 33 func (w *mockWatcher) Kill() { 34 w.mu.Lock() 35 defer w.mu.Unlock() 36 if !w.Stopped() { 37 close(w.stopped) 38 } 39 } 40 41 func (w *mockWatcher) Wait() error { 42 <-w.stopped 43 return nil 44 } 45 46 func (w *mockWatcher) Stopped() bool { 47 select { 48 case <-w.stopped: 49 return true 50 default: 51 return false 52 } 53 } 54 55 func newMockNotifyWatcher() *mockNotifyWatcher { 56 return &mockNotifyWatcher{ 57 mockWatcher: newMockWatcher(), 58 changes: make(chan struct{}, 1), 59 } 60 } 61 62 type mockNotifyWatcher struct { 63 *mockWatcher 64 changes chan struct{} 65 } 66 67 func (w *mockNotifyWatcher) Changes() watcher.NotifyChannel { 68 return w.changes 69 } 70 71 func newMockStringsWatcher() *mockStringsWatcher { 72 return &mockStringsWatcher{ 73 mockWatcher: newMockWatcher(), 74 changes: make(chan []string, 1), 75 } 76 } 77 78 type mockStringsWatcher struct { 79 *mockWatcher 80 changes chan []string 81 } 82 83 func (w *mockStringsWatcher) Changes() watcher.StringsChannel { 84 return w.changes 85 } 86 87 func newMockRelationUnitsWatcher() *mockRelationUnitsWatcher { 88 return &mockRelationUnitsWatcher{ 89 mockWatcher: newMockWatcher(), 90 changes: make(chan watcher.RelationUnitsChange, 1), 91 } 92 } 93 94 type mockRelationUnitsWatcher struct { 95 *mockWatcher 96 changes chan watcher.RelationUnitsChange 97 } 98 99 func (w *mockRelationUnitsWatcher) Changes() watcher.RelationUnitsChannel { 100 return w.changes 101 } 102 103 type mockState struct { 104 modelType model.ModelType 105 unit mockUnit 106 relations map[names.RelationTag]*mockRelation 107 storageAttachment map[params.StorageAttachmentId]params.StorageAttachment 108 relationUnitsWatchers map[names.RelationTag]*mockRelationUnitsWatcher 109 relationAppWatchers map[names.RelationTag]map[string]*mockNotifyWatcher 110 storageAttachmentWatchers map[names.StorageTag]*mockNotifyWatcher 111 updateStatusInterval time.Duration 112 updateStatusIntervalWatcher *mockNotifyWatcher 113 charm *mockCharm 114 } 115 116 func (st *mockState) Charm(string) (remotestate.Charm, error) { 117 if st.charm != nil { 118 return st.charm, nil 119 } 120 return &mockCharm{}, nil 121 } 122 123 type mockCharm struct { 124 required bool 125 } 126 127 func (c *mockCharm) LXDProfileRequired() (bool, error) { 128 return c.required, nil 129 } 130 131 func (st *mockState) Relation(tag names.RelationTag) (remotestate.Relation, error) { 132 r, ok := st.relations[tag] 133 if !ok { 134 return nil, ¶ms.Error{Code: params.CodeNotFound} 135 } 136 return r, nil 137 } 138 139 func (st *mockState) StorageAttachment( 140 storageTag names.StorageTag, unitTag names.UnitTag, 141 ) (params.StorageAttachment, error) { 142 if unitTag != st.unit.tag { 143 return params.StorageAttachment{}, errors.NewNotFound(¶ms.Error{Code: params.CodeNotFound}, "") 144 } 145 attachment, ok := st.storageAttachment[params.StorageAttachmentId{ 146 UnitTag: unitTag.String(), 147 StorageTag: storageTag.String(), 148 }] 149 if !ok { 150 return params.StorageAttachment{}, errors.NewNotFound(¶ms.Error{Code: params.CodeNotFound}, "") 151 } 152 if attachment.Kind == params.StorageKindUnknown { 153 return params.StorageAttachment{}, errors.NewNotProvisioned(¶ms.Error{Code: params.CodeNotProvisioned}, "") 154 } 155 return attachment, nil 156 } 157 158 func (st *mockState) StorageAttachmentLife( 159 ids []params.StorageAttachmentId, 160 ) ([]params.LifeResult, error) { 161 results := make([]params.LifeResult, len(ids)) 162 for i, id := range ids { 163 attachment, ok := st.storageAttachment[id] 164 if !ok { 165 results[i] = params.LifeResult{ 166 Error: ¶ms.Error{Code: params.CodeNotFound}, 167 } 168 continue 169 } 170 results[i] = params.LifeResult{Life: attachment.Life} 171 } 172 return results, nil 173 } 174 175 func (st *mockState) Unit(tag names.UnitTag) (remotestate.Unit, error) { 176 if tag != st.unit.tag { 177 return nil, ¶ms.Error{Code: params.CodeNotFound} 178 } 179 return &st.unit, nil 180 } 181 182 func (st *mockState) WatchRelationUnits( 183 relationTag names.RelationTag, unitTag names.UnitTag, 184 ) (watcher.RelationUnitsWatcher, error) { 185 if unitTag != st.unit.tag { 186 return nil, ¶ms.Error{Code: params.CodeNotFound} 187 } 188 watcher, ok := st.relationUnitsWatchers[relationTag] 189 if !ok { 190 return nil, ¶ms.Error{Code: params.CodeNotFound} 191 } 192 return watcher, nil 193 } 194 195 func (st *mockState) WatchStorageAttachment( 196 storageTag names.StorageTag, unitTag names.UnitTag, 197 ) (watcher.NotifyWatcher, error) { 198 if unitTag != st.unit.tag { 199 return nil, ¶ms.Error{Code: params.CodeNotFound} 200 } 201 watcher, ok := st.storageAttachmentWatchers[storageTag] 202 if !ok { 203 return nil, ¶ms.Error{Code: params.CodeNotFound} 204 } 205 return watcher, nil 206 } 207 208 func (st *mockState) UpdateStatusHookInterval() (time.Duration, error) { 209 return st.updateStatusInterval, nil 210 } 211 212 func (st *mockState) WatchUpdateStatusHookInterval() (watcher.NotifyWatcher, error) { 213 return st.updateStatusIntervalWatcher, nil 214 } 215 216 type mockUnit struct { 217 tag names.UnitTag 218 life life.Value 219 providerID string 220 resolved params.ResolvedMode 221 application mockApplication 222 unitWatcher *mockNotifyWatcher 223 addressesWatcher *mockStringsWatcher 224 configSettingsWatcher *mockStringsWatcher 225 applicationConfigSettingsWatcher *mockStringsWatcher 226 upgradeSeriesWatcher *mockNotifyWatcher 227 storageWatcher *mockStringsWatcher 228 actionWatcher *mockStringsWatcher 229 relationsWatcher *mockStringsWatcher 230 instanceDataWatcher *mockNotifyWatcher 231 lxdProfileName string 232 } 233 234 func (u *mockUnit) Life() life.Value { 235 return u.life 236 } 237 238 func (u *mockUnit) LXDProfileName() (string, error) { 239 return u.lxdProfileName, nil 240 } 241 242 func (u *mockUnit) Refresh() error { 243 return nil 244 } 245 246 func (u *mockUnit) ProviderID() string { 247 return u.providerID 248 } 249 250 func (u *mockUnit) Resolved() params.ResolvedMode { 251 return u.resolved 252 } 253 254 func (u *mockUnit) Application() (remotestate.Application, error) { 255 return &u.application, nil 256 } 257 258 func (u *mockUnit) Tag() names.UnitTag { 259 return u.tag 260 } 261 262 func (u *mockUnit) Watch() (watcher.NotifyWatcher, error) { 263 return u.unitWatcher, nil 264 } 265 266 func (u *mockUnit) WatchAddressesHash() (watcher.StringsWatcher, error) { 267 return u.addressesWatcher, nil 268 } 269 270 func (u *mockUnit) WatchConfigSettingsHash() (watcher.StringsWatcher, error) { 271 return u.configSettingsWatcher, nil 272 } 273 274 func (u *mockUnit) WatchTrustConfigSettingsHash() (watcher.StringsWatcher, error) { 275 return u.applicationConfigSettingsWatcher, nil 276 } 277 278 func (u *mockUnit) WatchStorage() (watcher.StringsWatcher, error) { 279 return u.storageWatcher, nil 280 } 281 282 func (u *mockUnit) WatchActionNotifications() (watcher.StringsWatcher, error) { 283 return u.actionWatcher, nil 284 } 285 286 func (u *mockUnit) WatchRelations() (watcher.StringsWatcher, error) { 287 return u.relationsWatcher, nil 288 } 289 290 func (u *mockUnit) WatchUpgradeSeriesNotifications() (watcher.NotifyWatcher, error) { 291 return u.upgradeSeriesWatcher, nil 292 } 293 294 func (u *mockUnit) WatchInstanceData() (watcher.NotifyWatcher, error) { 295 return u.instanceDataWatcher, nil 296 } 297 298 func (u *mockUnit) UpgradeSeriesStatus() (model.UpgradeSeriesStatus, string, error) { 299 return model.UpgradeSeriesPrepareStarted, "ubuntu@20.04", nil 300 } 301 302 func (u *mockUnit) SetUpgradeSeriesStatus(status model.UpgradeSeriesStatus) error { 303 return nil 304 } 305 306 type mockApplication struct { 307 tag names.ApplicationTag 308 life life.Value 309 curl string 310 charmModifiedVersion int 311 forceUpgrade bool 312 applicationWatcher *mockNotifyWatcher 313 leaderSettingsWatcher *mockNotifyWatcher 314 } 315 316 func (s *mockApplication) CharmModifiedVersion() (int, error) { 317 return s.charmModifiedVersion, nil 318 } 319 320 func (s *mockApplication) CharmURL() (string, bool, error) { 321 return s.curl, s.forceUpgrade, nil 322 } 323 324 func (s *mockApplication) Life() life.Value { 325 return s.life 326 } 327 328 func (s *mockApplication) Refresh() error { 329 return nil 330 } 331 332 func (s *mockApplication) Tag() names.ApplicationTag { 333 return s.tag 334 } 335 336 func (s *mockApplication) Watch() (watcher.NotifyWatcher, error) { 337 return s.applicationWatcher, nil 338 } 339 340 func (s *mockApplication) WatchLeadershipSettings() (watcher.NotifyWatcher, error) { 341 return s.leaderSettingsWatcher, nil 342 } 343 344 type mockRelation struct { 345 tag names.RelationTag 346 id int 347 life life.Value 348 suspended bool 349 } 350 351 func (r *mockRelation) Tag() names.RelationTag { 352 return r.tag 353 } 354 355 func (r *mockRelation) Id() int { 356 return r.id 357 } 358 359 func (r *mockRelation) Life() life.Value { 360 return r.life 361 } 362 363 func (r *mockRelation) Suspended() bool { 364 return r.suspended 365 } 366 367 func (r *mockRelation) UpdateSuspended(suspended bool) { 368 r.suspended = suspended 369 } 370 371 type mockLeadershipTracker struct { 372 leadership.Tracker 373 claimTicket mockTicket 374 leaderTicket mockTicket 375 minionTicket mockTicket 376 } 377 378 func (mock *mockLeadershipTracker) ClaimLeader() leadership.Ticket { 379 return &mock.claimTicket 380 } 381 382 func (mock *mockLeadershipTracker) WaitLeader() leadership.Ticket { 383 return &mock.leaderTicket 384 } 385 386 func (mock *mockLeadershipTracker) WaitMinion() leadership.Ticket { 387 return &mock.minionTicket 388 } 389 390 type mockTicket struct { 391 ch chan struct{} 392 result bool 393 } 394 395 func (t *mockTicket) Ready() <-chan struct{} { 396 return t.ch 397 } 398 399 func (t *mockTicket) Wait() bool { 400 return t.result 401 } 402 403 type mockSecretTriggerWatcher struct { 404 ch chan []string 405 stopCh chan struct{} 406 } 407 408 func (w *mockSecretTriggerWatcher) Kill() { 409 select { 410 case <-w.stopCh: 411 default: 412 close(w.stopCh) 413 } 414 } 415 416 func (*mockSecretTriggerWatcher) Wait() error { 417 return nil 418 } 419 420 type mockSecretsClient struct { 421 secretsWatcher *mockStringsWatcher 422 secretsRevisionsWatcher *mockStringsWatcher 423 unitName string 424 owners []names.Tag 425 } 426 427 func (m *mockSecretsClient) WatchConsumedSecretsChanges(unitName string) (watcher.StringsWatcher, error) { 428 m.unitName = unitName 429 return m.secretsWatcher, nil 430 } 431 432 func (m *mockSecretsClient) GetConsumerSecretsRevisionInfo(unitName string, uris []string) (map[string]secrets.SecretRevisionInfo, error) { 433 if unitName != m.unitName { 434 return nil, errors.NotFoundf("unit %q", unitName) 435 } 436 result := make(map[string]secrets.SecretRevisionInfo) 437 for i, uri := range uris { 438 if i == 0 { 439 continue 440 } 441 result[uri] = secrets.SecretRevisionInfo{ 442 Revision: 665 + i, 443 Label: "label-" + uri, 444 } 445 } 446 return result, nil 447 } 448 449 func (m *mockSecretsClient) WatchObsolete(owners ...names.Tag) (watcher.StringsWatcher, error) { 450 m.owners = owners 451 return m.secretsRevisionsWatcher, nil 452 }