8
. "launchpad.net/gocheck"
10
"launchpad.net/juju-core/charm"
11
"launchpad.net/juju-core/testing"
19
type BundleSuite struct {
24
var _ = Suite(&BundleSuite{})
26
func (s *BundleSuite) SetUpSuite(c *C) {
27
s.bundlePath = testing.Charms.BundlePath(c.MkDir(), "dummy")
30
func (s *BundleSuite) TestReadBundle(c *C) {
31
bundle, err := charm.ReadBundle(s.bundlePath)
33
checkDummy(c, bundle, s.bundlePath)
36
func (s *BundleSuite) TestReadBundleWithoutConfig(c *C) {
37
path := testing.Charms.BundlePath(c.MkDir(), "varnish")
38
bundle, err := charm.ReadBundle(path)
41
// A lacking config.yaml file still causes a proper
42
// Config value to be returned.
43
c.Assert(bundle.Config().Options, HasLen, 0)
46
func (s *BundleSuite) TestReadBundleBytes(c *C) {
47
data, err := ioutil.ReadFile(s.bundlePath)
50
bundle, err := charm.ReadBundleBytes(data)
52
checkDummy(c, bundle, "")
55
func (s *BundleSuite) TestExpandTo(c *C) {
56
bundle, err := charm.ReadBundle(s.bundlePath)
59
path := filepath.Join(c.MkDir(), "charm")
60
err = bundle.ExpandTo(path)
63
dir, err := charm.ReadDir(path)
65
checkDummy(c, dir, path)
68
func (s *BundleSuite) prepareBundle(c *C, charmDir *charm.Dir, bundlePath string) {
69
file, err := os.Create(bundlePath)
72
zipw := zip.NewWriter(file)
75
h := &zip.FileHeader{Name: "revision"}
76
h.SetMode(syscall.S_IFREG | 0644)
77
w, err := zipw.CreateHeader(h)
79
_, err = w.Write([]byte(strconv.Itoa(charmDir.Revision())))
81
h = &zip.FileHeader{Name: "metadata.yaml", Method: zip.Deflate}
83
w, err = zipw.CreateHeader(h)
85
data, err := goyaml.Marshal(charmDir.Meta())
87
_, err = w.Write(data)
90
for name := range charmDir.Meta().Hooks() {
91
hookName := filepath.Join("hooks", name)
96
// Force it non-executable
98
w, err := zipw.CreateHeader(h)
100
_, err = w.Write([]byte("not important"))
105
func (s *BundleSuite) TestExpandToSetsHooksExecutable(c *C) {
106
charmDir := testing.Charms.ClonedDir(c.MkDir(), "all-hooks")
107
// Bundle manually, so we can check ExpandTo(), unaffected
108
// by BundleTo()'s behavior
109
bundlePath := filepath.Join(c.MkDir(), "bundle.charm")
110
s.prepareBundle(c, charmDir, bundlePath)
111
bundle, err := charm.ReadBundle(bundlePath)
114
path := filepath.Join(c.MkDir(), "charm")
115
err = bundle.ExpandTo(path)
118
_, err = charm.ReadDir(path)
121
for name := range bundle.Meta().Hooks() {
122
hookName := string(name)
123
info, err := os.Stat(filepath.Join(path, "hooks", hookName))
125
perm := info.Mode() & 0777
126
c.Assert(perm&0100 != 0, Equals, true, Commentf("hook %q is not executable", hookName))
130
func (s *BundleSuite) TestBundleFileModes(c *C) {
131
// Apply subtler mode differences than can be expressed in Bazaar.
132
srcPath := testing.Charms.ClonedDirPath(c.MkDir(), "dummy")
137
{"hooks/install", 0751},
139
{"src/hello.c", 0614},
141
for _, m := range modes {
142
err := os.Chmod(filepath.Join(srcPath, m.path), m.mode)
145
var haveSymlinks = true
146
if err := os.Symlink("../target", filepath.Join(srcPath, "hooks/symlink")); err != nil {
150
// Bundle and extract the charm to a new directory.
151
dir, err := charm.ReadDir(srcPath)
153
buf := new(bytes.Buffer)
154
err = dir.BundleTo(buf)
156
bundle, err := charm.ReadBundleBytes(buf.Bytes())
159
err = bundle.ExpandTo(path)
162
// Check sensible file modes once round-tripped.
163
info, err := os.Stat(filepath.Join(path, "src", "hello.c"))
165
c.Assert(info.Mode()&0777, Equals, os.FileMode(0644))
166
c.Assert(info.Mode()&os.ModeType, Equals, os.FileMode(0))
168
info, err = os.Stat(filepath.Join(path, "hooks", "install"))
170
c.Assert(info.Mode()&0777, Equals, os.FileMode(0755))
171
c.Assert(info.Mode()&os.ModeType, Equals, os.FileMode(0))
173
info, err = os.Stat(filepath.Join(path, "empty"))
175
c.Assert(info.Mode()&0777, Equals, os.FileMode(0755))
178
target, err := os.Readlink(filepath.Join(path, "hooks", "symlink"))
180
c.Assert(target, Equals, "../target")
184
func (s *BundleSuite) TestBundleRevisionFile(c *C) {
185
charmDir := testing.Charms.ClonedDirPath(c.MkDir(), "dummy")
186
revPath := filepath.Join(charmDir, "revision")
188
// Missing revision file
189
err := os.Remove(revPath)
192
bundle, err := charm.ReadBundle(extBundleDir(c, charmDir))
194
c.Assert(bundle.Revision(), Equals, 0)
196
// Missing revision file with old revision in metadata
197
file, err := os.OpenFile(filepath.Join(charmDir, "metadata.yaml"), os.O_WRONLY|os.O_APPEND, 0)
199
_, err = file.Write([]byte("\nrevision: 1234\n"))
202
bundle, err = charm.ReadBundle(extBundleDir(c, charmDir))
204
c.Assert(bundle.Revision(), Equals, 1234)
206
// Revision file with bad content
207
err = ioutil.WriteFile(revPath, []byte("garbage"), 0666)
210
bundle, err = charm.ReadBundle(extBundleDir(c, charmDir))
211
c.Assert(err, ErrorMatches, "invalid revision file")
212
c.Assert(bundle, IsNil)
215
func (s *BundleSuite) TestBundleSetRevision(c *C) {
216
bundle, err := charm.ReadBundle(s.bundlePath)
219
c.Assert(bundle.Revision(), Equals, 1)
220
bundle.SetRevision(42)
221
c.Assert(bundle.Revision(), Equals, 42)
223
path := filepath.Join(c.MkDir(), "charm")
224
err = bundle.ExpandTo(path)
227
dir, err := charm.ReadDir(path)
229
c.Assert(dir.Revision(), Equals, 42)
232
func (s *BundleSuite) TestExpandToWithBadLink(c *C) {
233
charmDir := testing.Charms.ClonedDirPath(c.MkDir(), "dummy")
234
badLink := filepath.Join(charmDir, "hooks", "badlink")
236
// Symlink targeting a path outside of the charm.
237
err := os.Symlink("../../target", badLink)
240
bundle, err := charm.ReadBundle(extBundleDir(c, charmDir))
243
path := filepath.Join(c.MkDir(), "charm")
244
err = bundle.ExpandTo(path)
245
c.Assert(err, ErrorMatches, `symlink "hooks/badlink" links out of charm: "../../target"`)
247
// Symlink targeting an absolute path.
249
err = os.Symlink("/target", badLink)
252
bundle, err = charm.ReadBundle(extBundleDir(c, charmDir))
255
path = filepath.Join(c.MkDir(), "charm")
256
err = bundle.ExpandTo(path)
257
c.Assert(err, ErrorMatches, `symlink "hooks/badlink" is absolute: "/target"`)
260
func extBundleDir(c *C, dirpath string) (path string) {
261
path = filepath.Join(c.MkDir(), "bundle.charm")
262
cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf("cd %s; zip --fifo --symlinks -r %s .", dirpath, path))
263
output, err := cmd.CombinedOutput()
264
c.Assert(err, IsNil, Commentf("Command output: %s", output))