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, &params.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(&params.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(&params.Error{Code: params.CodeNotFound}, "")
   151  	}
   152  	if attachment.Kind == params.StorageKindUnknown {
   153  		return params.StorageAttachment{}, errors.NewNotProvisioned(&params.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: &params.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, &params.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, &params.Error{Code: params.CodeNotFound}
   187  	}
   188  	watcher, ok := st.relationUnitsWatchers[relationTag]
   189  	if !ok {
   190  		return nil, &params.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, &params.Error{Code: params.CodeNotFound}
   200  	}
   201  	watcher, ok := st.storageAttachmentWatchers[storageTag]
   202  	if !ok {
   203  		return nil, &params.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  }