launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/worker/uniter/charm/deployer_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package charm_test 5 6 import ( 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 11 "launchpad.net/errgo/errors" 12 gc "launchpad.net/gocheck" 13 14 corecharm "launchpad.net/juju-core/charm" 15 "launchpad.net/juju-core/testing" 16 "launchpad.net/juju-core/worker/uniter/charm" 17 ) 18 19 type DeployerSuite struct { 20 testing.GitSuite 21 } 22 23 var _ = gc.Suite(&DeployerSuite{}) 24 25 func (s *DeployerSuite) TestUnsetCharm(c *gc.C) { 26 d := charm.NewDeployer(filepath.Join(c.MkDir(), "deployer")) 27 err := d.Deploy(charm.NewGitDir(c.MkDir())) 28 c.Assert(err, gc.ErrorMatches, "charm deployment failed: no charm set") 29 } 30 31 func (s *DeployerSuite) TestInstall(c *gc.C) { 32 // Install. 33 d := charm.NewDeployer(filepath.Join(c.MkDir(), "deployer")) 34 bun := bundle(c, func(path string) { 35 err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("hello"), 0644) 36 c.Assert(err, gc.IsNil) 37 }) 38 err := d.Stage(bun, corecharm.MustParseURL("cs:s/c-1")) 39 c.Assert(err, gc.IsNil) 40 checkCleanup(c, d) 41 42 target := charm.NewGitDir(filepath.Join(c.MkDir(), "target")) 43 err = d.Deploy(target) 44 c.Assert(err, gc.IsNil) 45 checkCleanup(c, d) 46 47 // Check content. 48 data, err := ioutil.ReadFile(filepath.Join(target.Path(), "some-file")) 49 c.Assert(err, gc.IsNil) 50 c.Assert(string(data), gc.Equals, "hello") 51 url, err := charm.ReadCharmURL(target) 52 c.Assert(err, gc.IsNil) 53 c.Assert(url, gc.DeepEquals, corecharm.MustParseURL("cs:s/c-1")) 54 lines, err := target.Log() 55 c.Assert(err, gc.IsNil) 56 c.Assert(lines, gc.HasLen, 2) 57 c.Assert(lines[0], gc.Matches, `[0-9a-f]{7} Deployed charm "cs:s/c-1".`) 58 c.Assert(lines[1], gc.Matches, `[0-9a-f]{7} Imported charm "cs:s/c-1" from ".*".`) 59 } 60 61 func (s *DeployerSuite) TestUpgrade(c *gc.C) { 62 // Install. 63 d := charm.NewDeployer(filepath.Join(c.MkDir(), "deployer")) 64 bun1 := bundle(c, func(path string) { 65 err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("hello"), 0644) 66 c.Assert(err, gc.IsNil) 67 err = os.Symlink("./some-file", filepath.Join(path, "a-symlink")) 68 c.Assert(err, gc.IsNil) 69 }) 70 err := d.Stage(bun1, corecharm.MustParseURL("cs:s/c-1")) 71 c.Assert(err, gc.IsNil) 72 target := charm.NewGitDir(filepath.Join(c.MkDir(), "target")) 73 err = d.Deploy(target) 74 c.Assert(err, gc.IsNil) 75 76 // Upgrade. 77 bun2 := bundle(c, func(path string) { 78 err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("goodbye"), 0644) 79 c.Assert(err, gc.IsNil) 80 err = ioutil.WriteFile(filepath.Join(path, "a-symlink"), []byte("not any more!"), 0644) 81 c.Assert(err, gc.IsNil) 82 }) 83 err = d.Stage(bun2, corecharm.MustParseURL("cs:s/c-2")) 84 c.Assert(err, gc.IsNil) 85 checkCleanup(c, d) 86 87 err = d.Deploy(target) 88 c.Assert(err, gc.IsNil) 89 checkCleanup(c, d) 90 91 // Check content. 92 data, err := ioutil.ReadFile(filepath.Join(target.Path(), "some-file")) 93 c.Assert(err, gc.IsNil) 94 c.Assert(string(data), gc.Equals, "goodbye") 95 data, err = ioutil.ReadFile(filepath.Join(target.Path(), "a-symlink")) 96 c.Assert(err, gc.IsNil) 97 c.Assert(string(data), gc.Equals, "not any more!") 98 url, err := charm.ReadCharmURL(target) 99 c.Assert(err, gc.IsNil) 100 c.Assert(url, gc.DeepEquals, corecharm.MustParseURL("cs:s/c-2")) 101 lines, err := target.Log() 102 c.Assert(err, gc.IsNil) 103 c.Assert(lines, gc.HasLen, 5) 104 c.Assert(lines[0], gc.Matches, `[0-9a-f]{7} Upgraded charm to "cs:s/c-2".`) 105 } 106 107 func (s *DeployerSuite) TestConflict(c *gc.C) { 108 // Install. 109 d := charm.NewDeployer(filepath.Join(c.MkDir(), "deployer")) 110 bun1 := bundle(c, func(path string) { 111 err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("hello"), 0644) 112 c.Assert(err, gc.IsNil) 113 }) 114 err := d.Stage(bun1, corecharm.MustParseURL("cs:s/c-1")) 115 c.Assert(err, gc.IsNil) 116 target := charm.NewGitDir(filepath.Join(c.MkDir(), "target")) 117 err = d.Deploy(target) 118 c.Assert(err, gc.IsNil) 119 120 // Mess up target. 121 err = ioutil.WriteFile(filepath.Join(target.Path(), "some-file"), []byte("mu!"), 0644) 122 c.Assert(err, gc.IsNil) 123 124 // Upgrade. 125 bun2 := bundle(c, func(path string) { 126 err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("goodbye"), 0644) 127 c.Assert(err, gc.IsNil) 128 }) 129 err = d.Stage(bun2, corecharm.MustParseURL("cs:s/c-2")) 130 c.Assert(err, gc.IsNil) 131 err = d.Deploy(target) 132 c.Assert(errors.Cause(err), gc.Equals, charm.ErrConflict) 133 checkCleanup(c, d) 134 135 // Check state. 136 conflicted, err := target.Conflicted() 137 c.Assert(err, gc.IsNil) 138 c.Assert(conflicted, gc.Equals, true) 139 140 // Revert and check initial content. 141 err = target.Revert() 142 c.Assert(err, gc.IsNil) 143 data, err := ioutil.ReadFile(filepath.Join(target.Path(), "some-file")) 144 c.Assert(err, gc.IsNil) 145 c.Assert(string(data), gc.Equals, "mu!") 146 conflicted, err = target.Conflicted() 147 c.Assert(err, gc.IsNil) 148 c.Assert(conflicted, gc.Equals, false) 149 150 // Try to upgrade again. 151 err = d.Deploy(target) 152 c.Assert(errors.Cause(err), gc.Equals, charm.ErrConflict) 153 conflicted, err = target.Conflicted() 154 c.Assert(err, gc.IsNil) 155 c.Assert(conflicted, gc.Equals, true) 156 checkCleanup(c, d) 157 158 // And again. 159 err = d.Deploy(target) 160 c.Assert(errors.Cause(err), gc.Equals, charm.ErrConflict) 161 conflicted, err = target.Conflicted() 162 c.Assert(err, gc.IsNil) 163 c.Assert(conflicted, gc.Equals, true) 164 checkCleanup(c, d) 165 166 // Manually resolve, and commit. 167 err = ioutil.WriteFile(filepath.Join(target.Path(), "some-file"), []byte("nu!"), 0644) 168 c.Assert(err, gc.IsNil) 169 err = target.Snapshotf("user resolved conflicts") 170 c.Assert(err, gc.IsNil) 171 conflicted, err = target.Conflicted() 172 c.Assert(err, gc.IsNil) 173 c.Assert(conflicted, gc.Equals, false) 174 175 // Try a final upgrade to the same charm and check it doesn't write anything 176 // except the upgrade log line. 177 err = d.Deploy(target) 178 c.Assert(err, gc.IsNil) 179 checkCleanup(c, d) 180 181 data, err = ioutil.ReadFile(filepath.Join(target.Path(), "some-file")) 182 c.Assert(err, gc.IsNil) 183 c.Assert(string(data), gc.Equals, "nu!") 184 conflicted, err = target.Conflicted() 185 c.Assert(err, gc.IsNil) 186 c.Assert(conflicted, gc.Equals, false) 187 lines, err := target.Log() 188 c.Assert(err, gc.IsNil) 189 c.Assert(lines[0], gc.Matches, `[0-9a-f]{7} Upgraded charm to "cs:s/c-2".`) 190 } 191 192 func bundle(c *gc.C, customize func(path string)) *corecharm.Bundle { 193 base := c.MkDir() 194 dirpath := testing.Charms.ClonedDirPath(base, "dummy") 195 customize(dirpath) 196 dir, err := corecharm.ReadDir(dirpath) 197 c.Assert(err, gc.IsNil) 198 bunpath := filepath.Join(base, "bundle") 199 file, err := os.Create(bunpath) 200 c.Assert(err, gc.IsNil) 201 defer file.Close() 202 err = dir.BundleTo(file) 203 c.Assert(err, gc.IsNil) 204 bun, err := corecharm.ReadBundle(bunpath) 205 c.Assert(err, gc.IsNil) 206 return bun 207 } 208 209 func checkCleanup(c *gc.C, d *charm.Deployer) { 210 // Only one update dir should exist and be pointed to by the 'current' 211 // symlink since extra ones should have been cleaned up by 212 // cleanupOrphans. 213 updateDirs, err := filepath.Glob(filepath.Join(d.Path(), "update-*")) 214 c.Assert(err, gc.IsNil) 215 c.Assert(updateDirs, gc.HasLen, 1) 216 current, err := os.Readlink(d.Current().Path()) 217 c.Assert(err, gc.IsNil) 218 c.Assert(updateDirs[0], gc.Equals, current) 219 220 // No install dirs should be left behind since the one created is 221 // renamed to the target path. 222 installDirs, err := filepath.Glob(filepath.Join(d.Path(), "install-*")) 223 c.Assert(err, gc.IsNil) 224 c.Assert(installDirs, gc.HasLen, 0) 225 }