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  }