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 }