github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/environ_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package worker_test
     5  
     6  import (
     7  	"errors"
     8  	"strings"
     9  	"sync"
    10  	stdtesting "testing"
    11  	"time"
    12  
    13  	"github.com/juju/loggo"
    14  	"github.com/juju/testing"
    15  	jc "github.com/juju/testing/checkers"
    16  	gc "gopkg.in/check.v1"
    17  	"launchpad.net/tomb"
    18  
    19  	apiwatcher "github.com/juju/juju/api/watcher"
    20  	"github.com/juju/juju/environs"
    21  	"github.com/juju/juju/environs/config"
    22  	"github.com/juju/juju/provider/dummy"
    23  	coretesting "github.com/juju/juju/testing"
    24  	"github.com/juju/juju/worker"
    25  )
    26  
    27  func TestPackage(t *stdtesting.T) {
    28  	gc.TestingT(t)
    29  }
    30  
    31  type environSuite struct {
    32  	coretesting.BaseSuite
    33  
    34  	st *fakeState
    35  }
    36  
    37  var _ = gc.Suite(&environSuite{})
    38  
    39  func (s *environSuite) SetUpTest(c *gc.C) {
    40  	s.BaseSuite.SetUpTest(c)
    41  	s.st = &fakeState{
    42  		Stub:    &testing.Stub{},
    43  		changes: make(chan struct{}, 100),
    44  	}
    45  }
    46  
    47  func (s *environSuite) TestStop(c *gc.C) {
    48  	s.st.SetErrors(
    49  		nil,                // WatchForEnvironConfigChanges
    50  		errors.New("err1"), // Changes (closing the channel)
    51  	)
    52  	s.st.SetConfig(c, coretesting.Attrs{
    53  		"type": "invalid",
    54  	})
    55  
    56  	w, err := s.st.WatchForEnvironConfigChanges()
    57  	c.Assert(err, jc.ErrorIsNil)
    58  	defer stopWatcher(c, w)
    59  	stop := make(chan struct{})
    60  	close(stop) // close immediately so the loop exits.
    61  	done := make(chan error)
    62  	go func() {
    63  		env, err := worker.WaitForEnviron(w, s.st, stop)
    64  		c.Check(env, gc.IsNil)
    65  		done <- err
    66  	}()
    67  	select {
    68  	case <-worker.LoadedInvalid:
    69  		c.Errorf("expected changes watcher to be closed")
    70  	case err := <-done:
    71  		c.Assert(err, gc.Equals, tomb.ErrDying)
    72  	case <-time.After(coretesting.LongWait):
    73  		c.Fatalf("timeout waiting for the WaitForEnviron to stop")
    74  	}
    75  	s.st.CheckCallNames(c, "WatchForEnvironConfigChanges", "Changes")
    76  }
    77  
    78  func stopWatcher(c *gc.C, w apiwatcher.NotifyWatcher) {
    79  	err := w.Stop()
    80  	c.Check(err, jc.ErrorIsNil)
    81  }
    82  
    83  func (s *environSuite) TestInvalidConfig(c *gc.C) {
    84  	s.st.SetConfig(c, coretesting.Attrs{
    85  		"type": "unknown",
    86  	})
    87  
    88  	w, err := s.st.WatchForEnvironConfigChanges()
    89  	c.Assert(err, jc.ErrorIsNil)
    90  	defer stopWatcher(c, w)
    91  	done := make(chan environs.Environ)
    92  	go func() {
    93  		env, err := worker.WaitForEnviron(w, s.st, nil)
    94  		c.Check(err, jc.ErrorIsNil)
    95  		done <- env
    96  	}()
    97  	<-worker.LoadedInvalid
    98  	s.st.CheckCallNames(c,
    99  		"WatchForEnvironConfigChanges",
   100  		"Changes",
   101  		"EnvironConfig",
   102  		"Changes",
   103  	)
   104  }
   105  
   106  func (s *environSuite) TestErrorWhenEnvironIsInvalid(c *gc.C) {
   107  	s.st.SetConfig(c, coretesting.Attrs{
   108  		"type": "unknown",
   109  	})
   110  
   111  	obs, err := worker.NewEnvironObserver(s.st)
   112  	c.Assert(err, gc.ErrorMatches,
   113  		`cannot create an environment: no registered provider for "unknown"`,
   114  	)
   115  	c.Assert(obs, gc.IsNil)
   116  	s.st.CheckCallNames(c, "EnvironConfig")
   117  }
   118  
   119  func (s *environSuite) TestEnvironmentChanges(c *gc.C) {
   120  	s.st.SetConfig(c, nil)
   121  
   122  	logc := make(logChan, 1009)
   123  	c.Assert(loggo.RegisterWriter("testing", logc, loggo.WARNING), gc.IsNil)
   124  	defer loggo.RemoveWriter("testing")
   125  
   126  	obs, err := worker.NewEnvironObserver(s.st)
   127  	c.Assert(err, jc.ErrorIsNil)
   128  
   129  	env := obs.Environ()
   130  	s.st.AssertConfig(c, env.Config())
   131  
   132  	// Change to an invalid configuration and check
   133  	// that the observer's environment remains the same.
   134  	originalConfig, err := s.st.EnvironConfig()
   135  	c.Assert(err, jc.ErrorIsNil)
   136  
   137  	s.st.SetConfig(c, coretesting.Attrs{
   138  		"type": "invalid",
   139  	})
   140  
   141  	// Wait for the observer to register the invalid environment
   142  loop:
   143  	for {
   144  		select {
   145  		case msg := <-logc:
   146  			if strings.Contains(msg, "error creating an environment") {
   147  				break loop
   148  			}
   149  		case <-time.After(coretesting.LongWait):
   150  			c.Fatalf("timed out waiting to see broken environment")
   151  		}
   152  	}
   153  	// Check that the returned environ is still the same.
   154  	env = obs.Environ()
   155  	c.Assert(env.Config().AllAttrs(), jc.DeepEquals, originalConfig.AllAttrs())
   156  
   157  	// Change the environment back to a valid configuration
   158  	// with a different name and check that we see it.
   159  	s.st.SetConfig(c, coretesting.Attrs{
   160  		"name": "a-new-name",
   161  	})
   162  
   163  	for a := coretesting.LongAttempt.Start(); a.Next(); {
   164  		env := obs.Environ()
   165  		if !a.HasNext() {
   166  			c.Fatalf("timed out waiting for new environ")
   167  		}
   168  		if env.Config().Name() == "a-new-name" {
   169  			break
   170  		}
   171  	}
   172  }
   173  
   174  type logChan chan string
   175  
   176  func (logc logChan) Write(level loggo.Level, name, filename string, line int, timestamp time.Time, message string) {
   177  	logc <- message
   178  }
   179  
   180  type fakeState struct {
   181  	*testing.Stub
   182  	apiwatcher.NotifyWatcher
   183  
   184  	mu sync.Mutex
   185  
   186  	changes chan struct{}
   187  	config  map[string]interface{}
   188  }
   189  
   190  var _ worker.EnvironConfigObserver = (*fakeState)(nil)
   191  
   192  // WatchForEnvironConfigChanges implements EnvironConfigObserver.
   193  func (s *fakeState) WatchForEnvironConfigChanges() (apiwatcher.NotifyWatcher, error) {
   194  	s.MethodCall(s, "WatchForEnvironConfigChanges")
   195  	if err := s.NextErr(); err != nil {
   196  		return nil, err
   197  	}
   198  	return s, nil
   199  }
   200  
   201  // EnvironConfig implements EnvironConfigObserver.
   202  func (s *fakeState) EnvironConfig() (*config.Config, error) {
   203  	s.mu.Lock()
   204  	defer s.mu.Unlock()
   205  
   206  	s.MethodCall(s, "EnvironConfig")
   207  	if err := s.NextErr(); err != nil {
   208  		return nil, err
   209  	}
   210  	return config.New(config.NoDefaults, s.config)
   211  }
   212  
   213  // SetConfig changes the stored environment config with the given
   214  // extraAttrs and triggers a change for the watcher.
   215  func (s *fakeState) SetConfig(c *gc.C, extraAttrs coretesting.Attrs) {
   216  	s.mu.Lock()
   217  	defer s.mu.Unlock()
   218  
   219  	attrs := dummy.SampleConfig()
   220  	for k, v := range extraAttrs {
   221  		attrs[k] = v
   222  	}
   223  
   224  	// Simulate it's prepared.
   225  	attrs["broken"] = ""
   226  	attrs["state-id"] = "42"
   227  
   228  	s.config = coretesting.CustomEnvironConfig(c, attrs).AllAttrs()
   229  	s.changes <- struct{}{}
   230  }
   231  
   232  // Err implements apiwatcher.NotifyWatcher.
   233  func (s *fakeState) Err() error {
   234  	s.MethodCall(s, "Err")
   235  	return s.NextErr()
   236  }
   237  
   238  // Stop implements apiwatcher.NotifyWatcher.
   239  func (s *fakeState) Stop() error {
   240  	s.MethodCall(s, "Stop")
   241  	return s.NextErr()
   242  }
   243  
   244  // Changes implements apiwatcher.NotifyWatcher.
   245  func (s *fakeState) Changes() <-chan struct{} {
   246  	s.mu.Lock()
   247  	defer s.mu.Unlock()
   248  
   249  	s.MethodCall(s, "Changes")
   250  	if err := s.NextErr(); err != nil && s.changes != nil {
   251  		close(s.changes) // simulate the watcher died.
   252  		s.changes = nil
   253  	}
   254  	return s.changes
   255  }
   256  
   257  func (s *fakeState) AssertConfig(c *gc.C, expected *config.Config) {
   258  	s.mu.Lock()
   259  	defer s.mu.Unlock()
   260  
   261  	c.Assert(s.config, jc.DeepEquals, expected.AllAttrs())
   262  }