github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/environ/fixture_test.go (about)

     1  // Copyright 2012-2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package environ_test
     5  
     6  import (
     7  	"sync"
     8  
     9  	"github.com/juju/testing"
    10  	gc "gopkg.in/check.v1"
    11  	names "gopkg.in/juju/names.v2"
    12  	"gopkg.in/juju/worker.v1"
    13  	"gopkg.in/juju/worker.v1/workertest"
    14  
    15  	"github.com/juju/juju/core/watcher"
    16  	"github.com/juju/juju/environs"
    17  	"github.com/juju/juju/environs/config"
    18  	coretesting "github.com/juju/juju/testing"
    19  )
    20  
    21  type fixture struct {
    22  	watcherErr    error
    23  	observerErrs  []error
    24  	cloud         environs.CloudSpec
    25  	initialConfig map[string]interface{}
    26  }
    27  
    28  func (fix *fixture) Run(c *gc.C, test func(*runContext)) {
    29  	watcher := newNotifyWatcher(fix.watcherErr)
    30  	defer workertest.DirtyKill(c, watcher)
    31  	context := &runContext{
    32  		cloud:   fix.cloud,
    33  		config:  newModelConfig(c, fix.initialConfig),
    34  		watcher: watcher,
    35  	}
    36  	context.stub.SetErrors(fix.observerErrs...)
    37  	test(context)
    38  }
    39  
    40  type runContext struct {
    41  	mu          sync.Mutex
    42  	stub        testing.Stub
    43  	cloud       environs.CloudSpec
    44  	config      map[string]interface{}
    45  	watcher     *notifyWatcher
    46  	credWatcher *notifyWatcher
    47  }
    48  
    49  // SetConfig updates the configuration returned by ModelConfig.
    50  func (context *runContext) SetConfig(c *gc.C, extraAttrs coretesting.Attrs) {
    51  	context.mu.Lock()
    52  	defer context.mu.Unlock()
    53  	context.config = newModelConfig(c, extraAttrs)
    54  }
    55  
    56  // CloudSpec is part of the environ.ConfigObserver interface.
    57  func (context *runContext) CloudSpec() (environs.CloudSpec, error) {
    58  	context.mu.Lock()
    59  	defer context.mu.Unlock()
    60  	context.stub.AddCall("CloudSpec")
    61  	if err := context.stub.NextErr(); err != nil {
    62  		return environs.CloudSpec{}, err
    63  	}
    64  	return context.cloud, nil
    65  }
    66  
    67  // ModelConfig is part of the environ.ConfigObserver interface.
    68  func (context *runContext) ModelConfig() (*config.Config, error) {
    69  	context.mu.Lock()
    70  	defer context.mu.Unlock()
    71  	context.stub.AddCall("ModelConfig")
    72  	if err := context.stub.NextErr(); err != nil {
    73  		return nil, err
    74  	}
    75  	return config.New(config.NoDefaults, context.config)
    76  }
    77  
    78  // KillModelConfigNotify kills the watcher returned from WatchForModelConfigChanges with
    79  // the error configured in the enclosing fixture.
    80  func (context *runContext) KillModelConfigNotify() {
    81  	context.watcher.Kill()
    82  }
    83  
    84  // SendModelConfigNotify sends a value on the channel used by WatchForModelConfigChanges
    85  // results.
    86  func (context *runContext) SendModelConfigNotify() {
    87  	context.watcher.changes <- struct{}{}
    88  }
    89  
    90  // CloseModelConfigNotify closes the channel used by WatchForModelConfigChanges results.
    91  func (context *runContext) CloseModelConfigNotify() {
    92  	close(context.watcher.changes)
    93  }
    94  
    95  // WatchForModelConfigChanges is part of the environ.ConfigObserver interface.
    96  func (context *runContext) WatchForModelConfigChanges() (watcher.NotifyWatcher, error) {
    97  	context.mu.Lock()
    98  	defer context.mu.Unlock()
    99  	context.stub.AddCall("WatchForModelConfigChanges")
   100  	if err := context.stub.NextErr(); err != nil {
   101  		return nil, err
   102  	}
   103  	return context.watcher, nil
   104  }
   105  
   106  // KillCredentialNotify kills the watcher returned from WatchCredentialChanges with
   107  // the error configured in the enclosing fixture.
   108  func (context *runContext) KillCredentialNotify() {
   109  	context.credWatcher.Kill()
   110  }
   111  
   112  // SendCredentialNotify sends a value on the channel used by WatchCredentialChanges
   113  // results.
   114  func (context *runContext) SendCredentialNotify() {
   115  	context.credWatcher.changes <- struct{}{}
   116  }
   117  
   118  // CloseCredentialNotify closes the channel used by WatchCredentialChanges results.
   119  func (context *runContext) CloseCredentialNotify() {
   120  	close(context.credWatcher.changes)
   121  }
   122  
   123  // WatchCredential is part of the environ.ConfigObserver interface.
   124  func (context *runContext) WatchCredential(cred names.CloudCredentialTag) (watcher.NotifyWatcher, error) {
   125  	context.mu.Lock()
   126  	defer context.mu.Unlock()
   127  	context.stub.AddCall("WatchCredential")
   128  	if err := context.stub.NextErr(); err != nil {
   129  		return nil, err
   130  	}
   131  	return context.watcher, nil
   132  }
   133  
   134  func (context *runContext) CheckCallNames(c *gc.C, names ...string) {
   135  	context.mu.Lock()
   136  	defer context.mu.Unlock()
   137  	context.stub.CheckCallNames(c, names...)
   138  }
   139  
   140  // newNotifyWatcher returns a watcher.NotifyWatcher that will fail with the
   141  // supplied error when Kill()ed.
   142  func newNotifyWatcher(err error) *notifyWatcher {
   143  	return &notifyWatcher{
   144  		Worker:  workertest.NewErrorWorker(err),
   145  		changes: make(chan struct{}, 1000),
   146  	}
   147  }
   148  
   149  type notifyWatcher struct {
   150  	worker.Worker
   151  	changes chan struct{}
   152  }
   153  
   154  // Changes is part of the watcher.NotifyWatcher interface.
   155  func (w *notifyWatcher) Changes() watcher.NotifyChannel {
   156  	return w.changes
   157  }
   158  
   159  // newModelConfig returns an environment config map with the supplied attrs
   160  // (on top of some default set), or fails the test.
   161  func newModelConfig(c *gc.C, extraAttrs coretesting.Attrs) map[string]interface{} {
   162  	return coretesting.CustomModelConfig(c, extraAttrs).AllAttrs()
   163  }
   164  
   165  type mockEnviron struct {
   166  	environs.Environ
   167  	testing.Stub
   168  	cfg *config.Config
   169  	mu  sync.Mutex
   170  }
   171  
   172  func (e *mockEnviron) Config() *config.Config {
   173  	e.mu.Lock()
   174  	defer e.mu.Unlock()
   175  	e.MethodCall(e, "Config")
   176  	e.PopNoErr()
   177  	return e.cfg
   178  }
   179  
   180  func (e *mockEnviron) SetConfig(cfg *config.Config) error {
   181  	e.mu.Lock()
   182  	defer e.mu.Unlock()
   183  	e.MethodCall(e, "SetConfig", cfg)
   184  	if err := e.NextErr(); err != nil {
   185  		return err
   186  	}
   187  	e.cfg = cfg
   188  	return nil
   189  }
   190  
   191  func newMockEnviron(args environs.OpenParams) (environs.Environ, error) {
   192  	return &mockEnviron{cfg: args.Config}, nil
   193  }