github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/utils/zip/zip_test.go (about) 1 // Copyright 2011-2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package zip_test 5 6 import ( 7 "bytes" 8 "io/ioutil" 9 "os/exec" 10 "path/filepath" 11 "sort" 12 13 gc "launchpad.net/gocheck" 14 15 jc "launchpad.net/juju-core/testing/checkers" 16 "launchpad.net/juju-core/utils/zip" 17 ) 18 19 type ZipSuite struct { 20 BaseSuite 21 } 22 23 var _ = gc.Suite(&ZipSuite{}) 24 25 func (s *ZipSuite) TestFind(c *gc.C) { 26 reader := s.makeZip(c, 27 file{"some-file", "", 0644}, 28 file{"another-file", "", 0644}, 29 symlink{"some-symlink", "some-file"}, 30 dir{"some-dir", 0755}, 31 dir{"some-dir/another-dir", 0755}, 32 file{"some-dir/another-file", "", 0644}, 33 ) 34 35 for i, test := range []struct { 36 pattern string 37 expect []string 38 }{{ 39 "", nil, 40 }, { 41 "no-matches", nil, 42 }, { 43 "some-file", []string{ 44 "some-file"}, 45 }, { 46 "another-file", []string{ 47 "another-file", 48 "some-dir/another-file"}, 49 }, { 50 "some-*", []string{ 51 "some-file", 52 "some-symlink", 53 "some-dir"}, 54 }, { 55 "another-*", []string{ 56 "another-file", 57 "some-dir/another-dir", 58 "some-dir/another-file"}, 59 }, { 60 "*", []string{ 61 "some-file", 62 "another-file", 63 "some-symlink", 64 "some-dir", 65 "some-dir/another-dir", 66 "some-dir/another-file"}, 67 }} { 68 c.Logf("test %d: %q", i, test.pattern) 69 actual, err := zip.Find(reader, test.pattern) 70 c.Assert(err, gc.IsNil) 71 sort.Strings(test.expect) 72 sort.Strings(actual) 73 c.Check(actual, jc.DeepEquals, test.expect) 74 } 75 76 c.Logf("test $spanish-inquisition: FindAll") 77 expect, err := zip.Find(reader, "*") 78 c.Assert(err, gc.IsNil) 79 actual, err := zip.FindAll(reader) 80 c.Assert(err, gc.IsNil) 81 sort.Strings(expect) 82 sort.Strings(actual) 83 c.Check(actual, jc.DeepEquals, expect) 84 } 85 86 func (s *ZipSuite) TestFindError(c *gc.C) { 87 reader := s.makeZip(c, file{"some-file", "", 0644}) 88 _, err := zip.Find(reader, "[]") 89 c.Assert(err, gc.ErrorMatches, "syntax error in pattern") 90 } 91 92 func (s *ZipSuite) TestExtractAll(c *gc.C) { 93 creators := []creator{ 94 file{"some-file", "content 1", 0644}, 95 file{"another-file", "content 2", 0640}, 96 symlink{"some-symlink", "some-file"}, 97 dir{"some-dir", 0750}, 98 file{"some-dir/another-file", "content 3", 0644}, 99 dir{"some-dir/another-dir", 0755}, 100 symlink{"some-dir/another-dir/another-symlink", "../../another-file"}, 101 } 102 reader := s.makeZip(c, creators...) 103 targetPath := c.MkDir() 104 err := zip.ExtractAll(reader, targetPath) 105 c.Assert(err, gc.IsNil) 106 for i, creator := range creators { 107 c.Logf("test %d: %#v", i, creator) 108 creator.check(c, targetPath) 109 } 110 } 111 112 func (s *ZipSuite) TestExtractAllOverwriteFiles(c *gc.C) { 113 name := "some-file" 114 for i, test := range []creator{ 115 file{name, "content", 0644}, 116 dir{name, 0751}, 117 symlink{name, "wherever"}, 118 } { 119 c.Logf("test %d: %#v", i, test) 120 targetPath := c.MkDir() 121 file{name, "original", 0}.create(c, targetPath) 122 reader := s.makeZip(c, test) 123 err := zip.ExtractAll(reader, targetPath) 124 c.Check(err, gc.IsNil) 125 test.check(c, targetPath) 126 } 127 } 128 129 func (s *ZipSuite) TestExtractAllOverwriteSymlinks(c *gc.C) { 130 name := "some-symlink" 131 for i, test := range []creator{ 132 file{name, "content", 0644}, 133 dir{name, 0751}, 134 symlink{name, "wherever"}, 135 } { 136 c.Logf("test %d: %#v", i, test) 137 targetPath := c.MkDir() 138 original := file{"original", "content", 0644} 139 original.create(c, targetPath) 140 symlink{name, "original"}.create(c, targetPath) 141 reader := s.makeZip(c, test) 142 err := zip.ExtractAll(reader, targetPath) 143 c.Check(err, gc.IsNil) 144 test.check(c, targetPath) 145 original.check(c, targetPath) 146 } 147 } 148 149 func (s *ZipSuite) TestExtractAllOverwriteDirs(c *gc.C) { 150 name := "some-dir" 151 for i, test := range []creator{ 152 file{name, "content", 0644}, 153 dir{name, 0751}, 154 symlink{name, "wherever"}, 155 } { 156 c.Logf("test %d: %#v", i, test) 157 targetPath := c.MkDir() 158 dir{name, 0}.create(c, targetPath) 159 reader := s.makeZip(c, test) 160 err := zip.ExtractAll(reader, targetPath) 161 c.Check(err, gc.IsNil) 162 test.check(c, targetPath) 163 } 164 } 165 166 func (s *ZipSuite) TestExtractAllMergeDirs(c *gc.C) { 167 targetPath := c.MkDir() 168 dir{"dir", 0755}.create(c, targetPath) 169 originals := []creator{ 170 dir{"dir/original-dir", 0751}, 171 file{"dir/original-file", "content 1", 0600}, 172 symlink{"dir/original-symlink", "original-file"}, 173 } 174 for _, creator := range originals { 175 creator.create(c, targetPath) 176 } 177 merges := []creator{ 178 dir{"dir", 0751}, 179 dir{"dir/merge-dir", 0750}, 180 file{"dir/merge-file", "content 2", 0640}, 181 symlink{"dir/merge-symlink", "merge-file"}, 182 } 183 reader := s.makeZip(c, merges...) 184 err := zip.ExtractAll(reader, targetPath) 185 c.Assert(err, gc.IsNil) 186 187 for i, test := range append(originals, merges...) { 188 c.Logf("test %d: %#v", i, test) 189 test.check(c, targetPath) 190 } 191 } 192 193 func (s *ZipSuite) TestExtractAllSymlinkErrors(c *gc.C) { 194 for i, test := range []struct { 195 content []creator 196 error string 197 }{{ 198 content: []creator{ 199 symlink{"symlink", "/blah"}, 200 }, 201 error: `cannot extract "symlink": symlink "/blah" is absolute`, 202 }, { 203 content: []creator{ 204 symlink{"symlink", "../blah"}, 205 }, 206 error: `cannot extract "symlink": symlink "../blah" leads out of scope`, 207 }, { 208 content: []creator{ 209 dir{"dir", 0755}, 210 symlink{"dir/symlink", "../../blah"}, 211 }, 212 error: `cannot extract "dir/symlink": symlink "../../blah" leads out of scope`, 213 }} { 214 c.Logf("test %d: %s", i, test.error) 215 targetPath := c.MkDir() 216 reader := s.makeZip(c, test.content...) 217 err := zip.ExtractAll(reader, targetPath) 218 c.Check(err, gc.ErrorMatches, test.error) 219 } 220 } 221 222 func (s *ZipSuite) TestExtractDir(c *gc.C) { 223 reader := s.makeZip(c, 224 file{"bad-file", "xxx", 0644}, 225 dir{"bad-dir", 0755}, 226 symlink{"bad-symlink", "bad-file"}, 227 dir{"some-dir", 0751}, 228 file{"some-dir-bad-lol", "xxx", 0644}, 229 file{"some-dir/some-file", "content 1", 0644}, 230 file{"some-dir/another-file", "content 2", 0600}, 231 dir{"some-dir/another-dir", 0750}, 232 symlink{"some-dir/another-dir/some-symlink", "../some-file"}, 233 ) 234 targetParent := c.MkDir() 235 targetPath := filepath.Join(targetParent, "random-dir") 236 err := zip.Extract(reader, targetPath, "some-dir") 237 c.Assert(err, gc.IsNil) 238 239 for i, test := range []creator{ 240 dir{"random-dir", 0751}, 241 file{"random-dir/some-file", "content 1", 0644}, 242 file{"random-dir/another-file", "content 2", 0600}, 243 dir{"random-dir/another-dir", 0750}, 244 symlink{"random-dir/another-dir/some-symlink", "../some-file"}, 245 } { 246 c.Logf("test %d: %#v", i, test) 247 test.check(c, targetParent) 248 } 249 250 fileInfos, err := ioutil.ReadDir(targetParent) 251 c.Check(err, gc.IsNil) 252 c.Check(fileInfos, gc.HasLen, 1) 253 254 fileInfos, err = ioutil.ReadDir(targetPath) 255 c.Check(err, gc.IsNil) 256 c.Check(fileInfos, gc.HasLen, 3) 257 } 258 259 func (s *ZipSuite) TestExtractSingleFile(c *gc.C) { 260 reader := s.makeZip(c, 261 dir{"dir", 0755}, 262 dir{"dir/dir", 0755}, 263 file{"dir/dir/some-file", "content 1", 0644}, 264 file{"dir/dir/some-file-wtf", "content 2", 0644}, 265 ) 266 targetParent := c.MkDir() 267 targetPath := filepath.Join(targetParent, "just-the-one-file") 268 err := zip.Extract(reader, targetPath, "dir/dir/some-file") 269 c.Assert(err, gc.IsNil) 270 fileInfos, err := ioutil.ReadDir(targetParent) 271 c.Check(err, gc.IsNil) 272 c.Check(fileInfos, gc.HasLen, 1) 273 file{"just-the-one-file", "content 1", 0644}.check(c, targetParent) 274 } 275 276 func (s *ZipSuite) TestClosesFile(c *gc.C) { 277 reader := s.makeZip(c, file{"f", "echo hullo!", 0755}) 278 targetPath := c.MkDir() 279 err := zip.ExtractAll(reader, targetPath) 280 c.Assert(err, gc.IsNil) 281 cmd := exec.Command("/bin/sh", "-c", filepath.Join(targetPath, "f")) 282 var buffer bytes.Buffer 283 cmd.Stdout = &buffer 284 err = cmd.Run() 285 c.Assert(err, gc.IsNil) 286 c.Assert(buffer.String(), gc.Equals, "hullo!\n") 287 } 288 289 func (s *ZipSuite) TestExtractSymlinkErrors(c *gc.C) { 290 for i, test := range []struct { 291 content []creator 292 source string 293 error string 294 }{{ 295 content: []creator{ 296 dir{"dir", 0755}, 297 symlink{"dir/symlink", "/blah"}, 298 }, 299 source: "dir", 300 error: `cannot extract "dir/symlink": symlink "/blah" is absolute`, 301 }, { 302 content: []creator{ 303 dir{"dir", 0755}, 304 symlink{"dir/symlink", "../blah"}, 305 }, 306 source: "dir", 307 error: `cannot extract "dir/symlink": symlink "../blah" leads out of scope`, 308 }, { 309 content: []creator{ 310 symlink{"symlink", "blah"}, 311 }, 312 source: "symlink", 313 error: `cannot extract "symlink": symlink "blah" leads out of scope`, 314 }} { 315 c.Logf("test %d: %s", i, test.error) 316 targetPath := c.MkDir() 317 reader := s.makeZip(c, test.content...) 318 err := zip.Extract(reader, targetPath, test.source) 319 c.Check(err, gc.ErrorMatches, test.error) 320 } 321 } 322 323 func (s *ZipSuite) TestExtractSourceError(c *gc.C) { 324 reader := s.makeZip(c, dir{"dir", 0755}) 325 err := zip.Extract(reader, c.MkDir(), "../lol") 326 c.Assert(err, gc.ErrorMatches, `cannot extract files rooted at "../lol"`) 327 }