github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/controller/instancepoller/mock_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package instancepoller_test
     5  
     6  import (
     7  	"sort"
     8  	"sync"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/testing"
    12  	gc "gopkg.in/check.v1"
    13  	"gopkg.in/juju/names.v2"
    14  
    15  	"github.com/juju/juju/apiserver/facades/controller/instancepoller"
    16  	"github.com/juju/juju/core/instance"
    17  	"github.com/juju/juju/core/status"
    18  	"github.com/juju/juju/environs/config"
    19  	"github.com/juju/juju/network"
    20  	"github.com/juju/juju/state"
    21  )
    22  
    23  // mockState implements StateInterface and allows inspection of called
    24  // methods.
    25  type mockState struct {
    26  	*testing.Stub
    27  
    28  	mu sync.Mutex
    29  
    30  	configWatchers   []*mockConfigWatcher
    31  	machinesWatchers []*mockMachinesWatcher
    32  
    33  	config   *config.Config
    34  	machines map[string]*mockMachine
    35  }
    36  
    37  func NewMockState() *mockState {
    38  	return &mockState{
    39  		Stub:     &testing.Stub{},
    40  		machines: make(map[string]*mockMachine),
    41  	}
    42  }
    43  
    44  var _ instancepoller.StateInterface = (*mockState)(nil)
    45  
    46  // CheckFindEntityCall is a helper wrapper around
    47  // testing.Stub.CheckCall for FindEntity.
    48  func (m *mockState) CheckFindEntityCall(c *gc.C, index int, machineId string) {
    49  	m.CheckCall(c, index, "FindEntity", interface{}(names.NewMachineTag(machineId)))
    50  }
    51  
    52  // CheckSetProviderAddressesCall is a helper wrapper around
    53  // testing.Stub.CheckCall for SetProviderAddresses.
    54  func (m *mockState) CheckSetProviderAddressesCall(c *gc.C, index int, addrs []network.Address) {
    55  	args := make([]interface{}, len(addrs))
    56  	for i, addr := range addrs {
    57  		args[i] = addr
    58  	}
    59  	m.CheckCall(c, index, "SetProviderAddresses", args...)
    60  }
    61  
    62  // WatchForModelConfigChanges implements StateInterface.
    63  func (m *mockState) WatchForModelConfigChanges() state.NotifyWatcher {
    64  	m.mu.Lock()
    65  	defer m.mu.Unlock()
    66  
    67  	m.MethodCall(m, "WatchForModelConfigChanges")
    68  
    69  	w := NewMockConfigWatcher(m.NextErr())
    70  	m.configWatchers = append(m.configWatchers, w)
    71  	return w
    72  }
    73  
    74  // ModelConfig implements StateInterface.
    75  func (m *mockState) ModelConfig() (*config.Config, error) {
    76  	m.mu.Lock()
    77  	defer m.mu.Unlock()
    78  
    79  	m.MethodCall(m, "ModelConfig")
    80  
    81  	if err := m.NextErr(); err != nil {
    82  		return nil, err
    83  	}
    84  	return m.config, nil
    85  }
    86  
    87  // SetConfig updates the model config stored internally. Triggers a
    88  // change event for all created config watchers.
    89  func (m *mockState) SetConfig(c *gc.C, newConfig *config.Config) {
    90  	m.mu.Lock()
    91  	defer m.mu.Unlock()
    92  
    93  	m.config = newConfig
    94  
    95  	// Notify any watchers for the changes.
    96  	for _, w := range m.configWatchers {
    97  		w.incoming <- struct{}{}
    98  	}
    99  }
   100  
   101  // WatchModelMachines implements StateInterface.
   102  func (m *mockState) WatchModelMachines() state.StringsWatcher {
   103  	m.mu.Lock()
   104  	defer m.mu.Unlock()
   105  
   106  	m.MethodCall(m, "WatchModelMachines")
   107  
   108  	ids := make([]string, 0, len(m.machines))
   109  	// Initial event - all machine ids, sorted.
   110  	for id := range m.machines {
   111  		ids = append(ids, id)
   112  	}
   113  	sort.Strings(ids)
   114  
   115  	w := NewMockMachinesWatcher(ids, m.NextErr())
   116  	m.machinesWatchers = append(m.machinesWatchers, w)
   117  	return w
   118  }
   119  
   120  // FindEntity implements StateInterface.
   121  func (m *mockState) FindEntity(tag names.Tag) (state.Entity, error) {
   122  	m.mu.Lock()
   123  	defer m.mu.Unlock()
   124  
   125  	m.MethodCall(m, "FindEntity", tag)
   126  
   127  	if err := m.NextErr(); err != nil {
   128  		return nil, err
   129  	}
   130  	if tag == nil {
   131  		return nil, errors.NotValidf("nil tag is") // +" not valid"
   132  	}
   133  	machine, found := m.machines[tag.Id()]
   134  	if !found {
   135  		return nil, errors.NotFoundf("machine %s", tag.Id())
   136  	}
   137  	return machine, nil
   138  }
   139  
   140  // SetMachineInfo adds a new or updates existing mockMachine info.
   141  // Triggers any created mock machines watchers to return a change.
   142  func (m *mockState) SetMachineInfo(c *gc.C, args machineInfo) {
   143  	m.mu.Lock()
   144  	defer m.mu.Unlock()
   145  
   146  	c.Assert(args.id, gc.Not(gc.Equals), "")
   147  
   148  	machine, found := m.machines[args.id]
   149  	if !found {
   150  		machine = &mockMachine{
   151  			Stub:        m.Stub, // reuse parent stub.
   152  			machineInfo: args,
   153  		}
   154  	} else {
   155  		machine.machineInfo = args
   156  	}
   157  	m.machines[args.id] = machine
   158  
   159  	// Notify any watchers for the changes.
   160  	ids := []string{args.id}
   161  	for _, w := range m.machinesWatchers {
   162  		w.incoming <- ids
   163  	}
   164  }
   165  
   166  // RemoveMachine removes an existing mockMachine with the given id.
   167  // Triggers the machines watchers on success. If the id is not found
   168  // no error occurs and no change is reported by the watchers.
   169  func (m *mockState) RemoveMachine(c *gc.C, id string) {
   170  	m.mu.Lock()
   171  	defer m.mu.Unlock()
   172  
   173  	if _, found := m.machines[id]; !found {
   174  		return
   175  	}
   176  
   177  	delete(m.machines, id)
   178  
   179  	// Notify any watchers for the changes.
   180  	ids := []string{id}
   181  	for _, w := range m.machinesWatchers {
   182  		w.incoming <- ids
   183  	}
   184  }
   185  
   186  // Machine implements StateInterface.
   187  func (m *mockState) Machine(id string) (instancepoller.StateMachine, error) {
   188  	m.mu.Lock()
   189  	defer m.mu.Unlock()
   190  
   191  	m.MethodCall(m, "Machine", id)
   192  
   193  	if err := m.NextErr(); err != nil {
   194  		return nil, err
   195  	}
   196  	machine, found := m.machines[id]
   197  	if !found {
   198  		return nil, errors.NotFoundf("machine %s", id)
   199  	}
   200  	return machine, nil
   201  }
   202  
   203  // StartSync implements statetesting.SyncStarter, so mockState can be
   204  // used with watcher helpers/checkers.
   205  func (m *mockState) StartSync() {}
   206  
   207  type machineInfo struct {
   208  	id                string
   209  	instanceId        instance.Id
   210  	status            status.StatusInfo
   211  	instanceStatus    status.StatusInfo
   212  	providerAddresses []network.Address
   213  	life              state.Life
   214  	isManual          bool
   215  }
   216  
   217  type mockMachine struct {
   218  	*testing.Stub
   219  	instancepoller.StateMachine
   220  
   221  	mu sync.Mutex
   222  
   223  	machineInfo
   224  }
   225  
   226  var _ instancepoller.StateMachine = (*mockMachine)(nil)
   227  
   228  // InstanceId implements StateMachine.
   229  func (m *mockMachine) InstanceId() (instance.Id, error) {
   230  	m.mu.Lock()
   231  	defer m.mu.Unlock()
   232  
   233  	m.MethodCall(m, "InstanceId")
   234  	if err := m.NextErr(); err != nil {
   235  		return "", err
   236  	}
   237  	return m.instanceId, nil
   238  }
   239  
   240  // ProviderAddresses implements StateMachine.
   241  func (m *mockMachine) ProviderAddresses() []network.Address {
   242  	m.mu.Lock()
   243  	defer m.mu.Unlock()
   244  
   245  	m.MethodCall(m, "ProviderAddresses")
   246  	m.NextErr() // consume the unused error
   247  	return m.providerAddresses
   248  }
   249  
   250  // SetProviderAddresses implements StateMachine.
   251  func (m *mockMachine) SetProviderAddresses(addrs ...network.Address) error {
   252  	m.mu.Lock()
   253  	defer m.mu.Unlock()
   254  
   255  	args := make([]interface{}, len(addrs))
   256  	for i, addr := range addrs {
   257  		args[i] = addr
   258  	}
   259  	m.MethodCall(m, "SetProviderAddresses", args...)
   260  	if err := m.NextErr(); err != nil {
   261  		return err
   262  	}
   263  	m.providerAddresses = addrs
   264  	return nil
   265  }
   266  
   267  // InstanceStatus implements StateMachine.
   268  func (m *mockMachine) InstanceStatus() (status.StatusInfo, error) {
   269  	m.mu.Lock()
   270  	defer m.mu.Unlock()
   271  
   272  	m.MethodCall(m, "InstanceStatus")
   273  	if err := m.NextErr(); err != nil {
   274  		return status.StatusInfo{}, err
   275  	}
   276  	return m.instanceStatus, nil
   277  }
   278  
   279  // SetInstanceStatus implements StateMachine.
   280  func (m *mockMachine) SetInstanceStatus(instanceStatus status.StatusInfo) error {
   281  	m.mu.Lock()
   282  	defer m.mu.Unlock()
   283  
   284  	m.MethodCall(m, "SetInstanceStatus", instanceStatus)
   285  	if err := m.NextErr(); err != nil {
   286  		return err
   287  	}
   288  	m.instanceStatus = instanceStatus
   289  	return nil
   290  }
   291  
   292  // Life implements StateMachine.
   293  func (m *mockMachine) Life() state.Life {
   294  	m.mu.Lock()
   295  	defer m.mu.Unlock()
   296  
   297  	m.MethodCall(m, "Life")
   298  	m.NextErr() // consume the unused error
   299  	return m.life
   300  }
   301  
   302  // IsManual implements StateMachine.
   303  func (m *mockMachine) IsManual() (bool, error) {
   304  	m.mu.Lock()
   305  	defer m.mu.Unlock()
   306  
   307  	m.MethodCall(m, "IsManual")
   308  	return m.isManual, m.NextErr()
   309  }
   310  
   311  // Status implements StateMachine.
   312  func (m *mockMachine) Status() (status.StatusInfo, error) {
   313  	m.mu.Lock()
   314  	defer m.mu.Unlock()
   315  
   316  	m.MethodCall(m, "Status")
   317  	return m.status, m.NextErr()
   318  }
   319  
   320  type mockBaseWatcher struct {
   321  	err error
   322  
   323  	closeChanges func()
   324  	done         chan struct{}
   325  }
   326  
   327  var _ state.Watcher = (*mockBaseWatcher)(nil)
   328  
   329  func NewMockBaseWatcher(err error, closeChanges func()) *mockBaseWatcher {
   330  	w := &mockBaseWatcher{
   331  		err:          err,
   332  		closeChanges: closeChanges,
   333  		done:         make(chan struct{}),
   334  	}
   335  	if err != nil {
   336  		// Don't start the loop if we should fail.
   337  		w.Stop()
   338  	}
   339  	return w
   340  }
   341  
   342  // Kill implements state.Watcher.
   343  func (m *mockBaseWatcher) Kill() {}
   344  
   345  // Stop implements state.Watcher.
   346  func (m *mockBaseWatcher) Stop() error {
   347  	select {
   348  	case <-m.done:
   349  		// already closed
   350  	default:
   351  		// Signal the loop we want to stop.
   352  		close(m.done)
   353  		// Signal the clients we've closed.
   354  		m.closeChanges()
   355  	}
   356  	return m.err
   357  }
   358  
   359  // Wait implements state.Watcher.
   360  func (m *mockBaseWatcher) Wait() error {
   361  	return m.Stop()
   362  }
   363  
   364  // Err implements state.Watcher.
   365  func (m *mockBaseWatcher) Err() error {
   366  	return m.err
   367  }
   368  
   369  type mockConfigWatcher struct {
   370  	*mockBaseWatcher
   371  
   372  	incoming chan struct{}
   373  	changes  chan struct{}
   374  }
   375  
   376  var _ state.NotifyWatcher = (*mockConfigWatcher)(nil)
   377  
   378  func NewMockConfigWatcher(err error) *mockConfigWatcher {
   379  	changes := make(chan struct{})
   380  	w := &mockConfigWatcher{
   381  		changes:         changes,
   382  		incoming:        make(chan struct{}),
   383  		mockBaseWatcher: NewMockBaseWatcher(err, func() { close(changes) }),
   384  	}
   385  	if err == nil {
   386  		go w.loop()
   387  	}
   388  	return w
   389  }
   390  
   391  func (m *mockConfigWatcher) loop() {
   392  	// Prepare initial event.
   393  	outChanges := m.changes
   394  	// Forward any incoming changes until stopped.
   395  	for {
   396  		select {
   397  		case <-m.done:
   398  			// We're about to quit.
   399  			return
   400  		case outChanges <- struct{}{}:
   401  			outChanges = nil
   402  		case <-m.incoming:
   403  			outChanges = m.changes
   404  		}
   405  	}
   406  }
   407  
   408  // Changes implements state.NotifyWatcher.
   409  func (m *mockConfigWatcher) Changes() <-chan struct{} {
   410  	return m.changes
   411  }
   412  
   413  type mockMachinesWatcher struct {
   414  	*mockBaseWatcher
   415  
   416  	initial  []string
   417  	incoming chan []string
   418  	changes  chan []string
   419  }
   420  
   421  func NewMockMachinesWatcher(initial []string, err error) *mockMachinesWatcher {
   422  	changes := make(chan []string)
   423  	w := &mockMachinesWatcher{
   424  		initial:         initial,
   425  		changes:         changes,
   426  		incoming:        make(chan []string),
   427  		mockBaseWatcher: NewMockBaseWatcher(err, func() { close(changes) }),
   428  	}
   429  	if err == nil {
   430  		go w.loop()
   431  	}
   432  	return w
   433  }
   434  
   435  func (m *mockMachinesWatcher) loop() {
   436  	// Prepare initial event.
   437  	unsent := m.initial
   438  	outChanges := m.changes
   439  	// Forward any incoming changes until stopped.
   440  	for {
   441  		select {
   442  		case <-m.done:
   443  			// We're about to quit.
   444  			return
   445  		case outChanges <- unsent:
   446  			outChanges = nil
   447  			unsent = nil
   448  		case ids := <-m.incoming:
   449  			unsent = append(unsent, ids...)
   450  			outChanges = m.changes
   451  		}
   452  	}
   453  }
   454  
   455  // Changes implements state.StringsWatcher.
   456  func (m *mockMachinesWatcher) Changes() <-chan []string {
   457  	return m.changes
   458  }
   459  
   460  var _ state.StringsWatcher = (*mockMachinesWatcher)(nil)