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