github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/worker/upgrader/upgrader_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package upgrader_test 5 6 import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 stdtesting "testing" 11 "time" 12 13 "github.com/juju/errors" 14 jc "github.com/juju/testing/checkers" 15 "github.com/juju/utils" 16 gc "launchpad.net/gocheck" 17 18 "github.com/juju/juju/agent" 19 agenttools "github.com/juju/juju/agent/tools" 20 envtesting "github.com/juju/juju/environs/testing" 21 envtools "github.com/juju/juju/environs/tools" 22 jujutesting "github.com/juju/juju/juju/testing" 23 "github.com/juju/juju/provider/dummy" 24 "github.com/juju/juju/state" 25 "github.com/juju/juju/state/api" 26 statetesting "github.com/juju/juju/state/testing" 27 coretesting "github.com/juju/juju/testing" 28 coretools "github.com/juju/juju/tools" 29 "github.com/juju/juju/version" 30 "github.com/juju/juju/worker/upgrader" 31 ) 32 33 func TestPackage(t *stdtesting.T) { 34 coretesting.MgoTestPackage(t) 35 } 36 37 type UpgraderSuite struct { 38 jujutesting.JujuConnSuite 39 40 machine *state.Machine 41 state *api.State 42 oldRetryAfter func() <-chan time.Time 43 } 44 45 type AllowedTargetVersionSuite struct{} 46 47 var _ = gc.Suite(&UpgraderSuite{}) 48 var _ = gc.Suite(&AllowedTargetVersionSuite{}) 49 50 func (s *UpgraderSuite) SetUpTest(c *gc.C) { 51 s.JujuConnSuite.SetUpTest(c) 52 // s.machine needs to have IsManager() so that it can get the actual 53 // current revision to upgrade to. 54 s.state, s.machine = s.OpenAPIAsNewMachine(c, state.JobManageEnviron) 55 // Capture the value of RetryAfter, and use that captured 56 // value in the cleanup lambda. 57 oldRetryAfter := *upgrader.RetryAfter 58 s.AddCleanup(func(*gc.C) { 59 *upgrader.RetryAfter = oldRetryAfter 60 }) 61 } 62 63 type mockConfig struct { 64 agent.Config 65 tag string 66 datadir string 67 } 68 69 func (mock *mockConfig) Tag() string { 70 return mock.tag 71 } 72 73 func (mock *mockConfig) DataDir() string { 74 return mock.datadir 75 } 76 77 func agentConfig(tag, datadir string) agent.Config { 78 return &mockConfig{tag: tag, datadir: datadir} 79 } 80 81 func (s *UpgraderSuite) makeUpgrader() *upgrader.Upgrader { 82 config := agentConfig(s.machine.Tag(), s.DataDir()) 83 return upgrader.NewUpgrader(s.state.Upgrader(), config) 84 } 85 86 func (s *UpgraderSuite) TestUpgraderSetsTools(c *gc.C) { 87 vers := version.MustParseBinary("5.4.3-precise-amd64") 88 err := statetesting.SetAgentVersion(s.State, vers.Number) 89 c.Assert(err, gc.IsNil) 90 stor := s.Conn.Environ.Storage() 91 agentTools := envtesting.PrimeTools(c, stor, s.DataDir(), vers) 92 s.PatchValue(&version.Current, agentTools.Version) 93 err = envtools.MergeAndWriteMetadata(stor, coretools.List{agentTools}, envtools.DoNotWriteMirrors) 94 _, err = s.machine.AgentTools() 95 c.Assert(err, jc.Satisfies, errors.IsNotFound) 96 97 u := s.makeUpgrader() 98 statetesting.AssertStop(c, u) 99 s.machine.Refresh() 100 gotTools, err := s.machine.AgentTools() 101 c.Assert(err, gc.IsNil) 102 envtesting.CheckTools(c, gotTools, agentTools) 103 } 104 105 func (s *UpgraderSuite) TestUpgraderSetVersion(c *gc.C) { 106 vers := version.MustParseBinary("5.4.3-precise-amd64") 107 agentTools := envtesting.PrimeTools(c, s.Conn.Environ.Storage(), s.DataDir(), vers) 108 s.PatchValue(&version.Current, agentTools.Version) 109 err := os.RemoveAll(filepath.Join(s.DataDir(), "tools")) 110 c.Assert(err, gc.IsNil) 111 112 _, err = s.machine.AgentTools() 113 c.Assert(err, jc.Satisfies, errors.IsNotFound) 114 err = statetesting.SetAgentVersion(s.State, vers.Number) 115 c.Assert(err, gc.IsNil) 116 117 u := s.makeUpgrader() 118 statetesting.AssertStop(c, u) 119 s.machine.Refresh() 120 gotTools, err := s.machine.AgentTools() 121 c.Assert(err, gc.IsNil) 122 c.Assert(gotTools, gc.DeepEquals, &coretools.Tools{Version: version.Current}) 123 } 124 125 func (s *UpgraderSuite) TestUpgraderUpgradesImmediately(c *gc.C) { 126 stor := s.Conn.Environ.Storage() 127 oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), version.MustParseBinary("5.4.3-precise-amd64")) 128 s.PatchValue(&version.Current, oldTools.Version) 129 newTools := envtesting.AssertUploadFakeToolsVersions( 130 c, stor, version.MustParseBinary("5.4.5-precise-amd64"))[0] 131 err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) 132 c.Assert(err, gc.IsNil) 133 134 // Make the download take a while so that we verify that 135 // the download happens before the upgrader checks if 136 // it's been stopped. 137 dummy.SetStorageDelay(coretesting.ShortWait) 138 139 u := s.makeUpgrader() 140 err = u.Stop() 141 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 142 AgentName: s.machine.Tag(), 143 OldTools: oldTools.Version, 144 NewTools: newTools.Version, 145 DataDir: s.DataDir(), 146 }) 147 foundTools, err := agenttools.ReadTools(s.DataDir(), newTools.Version) 148 c.Assert(err, gc.IsNil) 149 envtesting.CheckTools(c, foundTools, newTools) 150 } 151 152 func (s *UpgraderSuite) TestUpgraderRetryAndChanged(c *gc.C) { 153 stor := s.Conn.Environ.Storage() 154 oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), version.MustParseBinary("5.4.3-precise-amd64")) 155 s.PatchValue(&version.Current, oldTools.Version) 156 newTools := envtesting.AssertUploadFakeToolsVersions( 157 c, stor, version.MustParseBinary("5.4.5-precise-amd64"))[0] 158 err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) 159 c.Assert(err, gc.IsNil) 160 161 retryc := make(chan time.Time) 162 *upgrader.RetryAfter = func() <-chan time.Time { 163 c.Logf("replacement retry after") 164 return retryc 165 } 166 dummy.Poison(s.Conn.Environ.Storage(), envtools.StorageName(newTools.Version), fmt.Errorf("a non-fatal dose")) 167 u := s.makeUpgrader() 168 defer u.Stop() 169 170 for i := 0; i < 3; i++ { 171 select { 172 case retryc <- time.Now(): 173 case <-time.After(coretesting.LongWait): 174 c.Fatalf("upgrader did not retry (attempt %d)", i) 175 } 176 } 177 178 // Make it upgrade to some newer tools that can be 179 // downloaded ok; it should stop retrying, download 180 // the newer tools and exit. 181 newerTools := envtesting.AssertUploadFakeToolsVersions( 182 c, s.Conn.Environ.Storage(), version.MustParseBinary("5.4.6-precise-amd64"))[0] 183 184 err = statetesting.SetAgentVersion(s.State, newerTools.Version.Number) 185 c.Assert(err, gc.IsNil) 186 187 s.BackingState.StartSync() 188 done := make(chan error) 189 go func() { 190 done <- u.Wait() 191 }() 192 select { 193 case err := <-done: 194 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 195 AgentName: s.machine.Tag(), 196 OldTools: oldTools.Version, 197 NewTools: newerTools.Version, 198 DataDir: s.DataDir(), 199 }) 200 case <-time.After(coretesting.LongWait): 201 c.Fatalf("upgrader did not quit after upgrading") 202 } 203 } 204 205 func (s *UpgraderSuite) TestChangeAgentTools(c *gc.C) { 206 oldTools := &coretools.Tools{ 207 Version: version.MustParseBinary("1.2.3-quantal-amd64"), 208 } 209 stor := s.Conn.Environ.Storage() 210 newTools := envtesting.PrimeTools(c, stor, s.DataDir(), version.MustParseBinary("5.4.3-precise-amd64")) 211 s.PatchValue(&version.Current, newTools.Version) 212 err := envtools.MergeAndWriteMetadata(stor, coretools.List{newTools}, envtools.DoNotWriteMirrors) 213 c.Assert(err, gc.IsNil) 214 ugErr := &upgrader.UpgradeReadyError{ 215 AgentName: "anAgent", 216 OldTools: oldTools.Version, 217 NewTools: newTools.Version, 218 DataDir: s.DataDir(), 219 } 220 err = ugErr.ChangeAgentTools() 221 c.Assert(err, gc.IsNil) 222 link, err := os.Readlink(agenttools.ToolsDir(s.DataDir(), "anAgent")) 223 c.Assert(err, gc.IsNil) 224 c.Assert(link, gc.Equals, newTools.Version.String()) 225 } 226 227 func (s *UpgraderSuite) TestEnsureToolsChecksBeforeDownloading(c *gc.C) { 228 stor := s.Conn.Environ.Storage() 229 newTools := envtesting.PrimeTools(c, stor, s.DataDir(), version.MustParseBinary("5.4.3-precise-amd64")) 230 s.PatchValue(&version.Current, newTools.Version) 231 // We've already downloaded the tools, so change the URL to be 232 // something invalid and ensure we don't actually get an error, because 233 // it doesn't actually do an HTTP request 234 u := s.makeUpgrader() 235 newTools.URL = "http://0.1.2.3/invalid/path/tools.tgz" 236 err := upgrader.EnsureTools(u, newTools, utils.VerifySSLHostnames) 237 c.Assert(err, gc.IsNil) 238 } 239 240 func (s *UpgraderSuite) TestUpgraderRefusesToDowngradeMinorVersions(c *gc.C) { 241 stor := s.Conn.Environ.Storage() 242 origTools := envtesting.PrimeTools(c, stor, s.DataDir(), version.MustParseBinary("5.4.3-precise-amd64")) 243 s.PatchValue(&version.Current, origTools.Version) 244 downgradeTools := envtesting.AssertUploadFakeToolsVersions( 245 c, stor, version.MustParseBinary("5.3.3-precise-amd64"))[0] 246 err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number) 247 c.Assert(err, gc.IsNil) 248 249 u := s.makeUpgrader() 250 err = u.Stop() 251 // If the upgrade would have triggered, we would have gotten an 252 // UpgradeReadyError, since it was skipped, we get no error 253 c.Check(err, gc.IsNil) 254 _, err = agenttools.ReadTools(s.DataDir(), downgradeTools.Version) 255 // TODO: ReadTools *should* be returning some form of errors.NotFound, 256 // however, it just passes back a fmt.Errorf so we live with it 257 // c.Assert(err, jc.Satisfies, errors.IsNotFound) 258 c.Check(err, gc.ErrorMatches, "cannot read tools metadata in tools directory.*no such file or directory") 259 } 260 261 func (s *UpgraderSuite) TestUpgraderAllowsDowngradingPatchVersions(c *gc.C) { 262 stor := s.Conn.Environ.Storage() 263 origTools := envtesting.PrimeTools(c, stor, s.DataDir(), version.MustParseBinary("5.4.3-precise-amd64")) 264 s.PatchValue(&version.Current, origTools.Version) 265 downgradeTools := envtesting.AssertUploadFakeToolsVersions( 266 c, stor, version.MustParseBinary("5.4.2-precise-amd64"))[0] 267 err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number) 268 c.Assert(err, gc.IsNil) 269 270 dummy.SetStorageDelay(coretesting.ShortWait) 271 272 u := s.makeUpgrader() 273 err = u.Stop() 274 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 275 AgentName: s.machine.Tag(), 276 OldTools: origTools.Version, 277 NewTools: downgradeTools.Version, 278 DataDir: s.DataDir(), 279 }) 280 foundTools, err := agenttools.ReadTools(s.DataDir(), downgradeTools.Version) 281 c.Assert(err, gc.IsNil) 282 envtesting.CheckTools(c, foundTools, downgradeTools) 283 } 284 285 type allowedTest struct { 286 current string 287 target string 288 allowed bool 289 } 290 291 func (s *AllowedTargetVersionSuite) TestAllowedTargetVersionSuite(c *gc.C) { 292 cases := []allowedTest{ 293 {current: "1.2.3", target: "1.3.3", allowed: true}, 294 {current: "1.2.3", target: "1.2.3", allowed: true}, 295 {current: "1.2.3", target: "2.2.3", allowed: true}, 296 {current: "1.2.3", target: "1.1.3", allowed: false}, 297 {current: "1.2.3", target: "1.2.2", allowed: true}, 298 {current: "1.2.3", target: "0.2.3", allowed: false}, 299 } 300 for i, test := range cases { 301 c.Logf("test case %d, %#v", i, test) 302 current := version.MustParse(test.current) 303 target := version.MustParse(test.target) 304 c.Check(upgrader.AllowedTargetVersion(current, target), gc.Equals, test.allowed) 305 } 306 }