github.com/rigado/snapd@v2.42.5-go-mod+incompatible/snap/pack/pack_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2014-2016 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package pack_test
    21  
    22  import (
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"os/exec"
    27  	"path/filepath"
    28  	"regexp"
    29  	"strings"
    30  	"testing"
    31  
    32  	. "gopkg.in/check.v1"
    33  
    34  	"github.com/snapcore/snapd/dirs"
    35  	"github.com/snapcore/snapd/snap"
    36  	"github.com/snapcore/snapd/snap/pack"
    37  	"github.com/snapcore/snapd/snap/squashfs"
    38  	"github.com/snapcore/snapd/testutil"
    39  )
    40  
    41  func Test(t *testing.T) { TestingT(t) }
    42  
    43  type packSuite struct {
    44  	testutil.BaseTest
    45  }
    46  
    47  var _ = Suite(&packSuite{})
    48  
    49  func (s *packSuite) SetUpTest(c *C) {
    50  	s.BaseTest.SetUpTest(c)
    51  	s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {}))
    52  
    53  	// chdir into a tempdir
    54  	pwd, err := os.Getwd()
    55  	c.Assert(err, IsNil)
    56  	s.AddCleanup(func() { os.Chdir(pwd) })
    57  	err = os.Chdir(c.MkDir())
    58  	c.Assert(err, IsNil)
    59  
    60  	// use fake root
    61  	dirs.SetRootDir(c.MkDir())
    62  }
    63  
    64  func (s *packSuite) TearDownTest(c *C) {
    65  	s.BaseTest.TearDownTest(c)
    66  }
    67  
    68  func makeExampleSnapSourceDir(c *C, snapYamlContent string) string {
    69  	tempdir := c.MkDir()
    70  	c.Assert(os.Chmod(tempdir, 0755), IsNil)
    71  
    72  	// use meta/snap.yaml
    73  	metaDir := filepath.Join(tempdir, "meta")
    74  	err := os.Mkdir(metaDir, 0755)
    75  	c.Assert(err, IsNil)
    76  	err = ioutil.WriteFile(filepath.Join(metaDir, "snap.yaml"), []byte(snapYamlContent), 0644)
    77  	c.Assert(err, IsNil)
    78  
    79  	const helloBinContent = `#!/bin/sh
    80  printf "hello world"
    81  `
    82  
    83  	// an example binary
    84  	binDir := filepath.Join(tempdir, "bin")
    85  	err = os.Mkdir(binDir, 0755)
    86  	c.Assert(err, IsNil)
    87  	err = ioutil.WriteFile(filepath.Join(binDir, "hello-world"), []byte(helloBinContent), 0755)
    88  	c.Assert(err, IsNil)
    89  
    90  	// unusual permissions for dir
    91  	tmpDir := filepath.Join(tempdir, "tmp")
    92  	err = os.Mkdir(tmpDir, 0755)
    93  	c.Assert(err, IsNil)
    94  	// avoid umask
    95  	err = os.Chmod(tmpDir, 01777)
    96  	c.Assert(err, IsNil)
    97  
    98  	// and file
    99  	someFile := filepath.Join(tempdir, "file-with-perm")
   100  	err = ioutil.WriteFile(someFile, []byte(""), 0666)
   101  	c.Assert(err, IsNil)
   102  	err = os.Chmod(someFile, 0666)
   103  	c.Assert(err, IsNil)
   104  
   105  	// an example symlink
   106  	err = os.Symlink("bin/hello-world", filepath.Join(tempdir, "symlink"))
   107  	c.Assert(err, IsNil)
   108  
   109  	return tempdir
   110  }
   111  
   112  func (s *packSuite) TestPackNoManifestFails(c *C) {
   113  	sourceDir := makeExampleSnapSourceDir(c, "{name: hello, version: 0}")
   114  	c.Assert(os.Remove(filepath.Join(sourceDir, "meta", "snap.yaml")), IsNil)
   115  	_, err := pack.Snap(sourceDir, "", "")
   116  	c.Assert(err, ErrorMatches, `.*/meta/snap\.yaml: no such file or directory`)
   117  }
   118  
   119  func (s *packSuite) TestPackMissingAppFails(c *C) {
   120  	sourceDir := makeExampleSnapSourceDir(c, `name: hello
   121  version: 0
   122  apps:
   123   foo:
   124    command: bin/hello-world
   125  `)
   126  	c.Assert(os.Remove(filepath.Join(sourceDir, "bin", "hello-world")), IsNil)
   127  	_, err := pack.Snap(sourceDir, "", "")
   128  	c.Assert(err, Equals, snap.ErrMissingPaths)
   129  }
   130  
   131  func (s *packSuite) TestValidateMissingAppFailsWithErrMissingPaths(c *C) {
   132  	sourceDir := makeExampleSnapSourceDir(c, `name: hello
   133  version: 0
   134  apps:
   135   foo:
   136    command: bin/hello-world
   137  `)
   138  	c.Assert(os.Remove(filepath.Join(sourceDir, "bin", "hello-world")), IsNil)
   139  	err := pack.CheckSkeleton(sourceDir)
   140  	c.Assert(err, Equals, snap.ErrMissingPaths)
   141  }
   142  
   143  func (s *packSuite) TestPackExcludesBackups(c *C) {
   144  	sourceDir := makeExampleSnapSourceDir(c, "{name: hello, version: 0}")
   145  	target := c.MkDir()
   146  	// add a backup file
   147  	c.Assert(ioutil.WriteFile(filepath.Join(sourceDir, "foo~"), []byte("hi"), 0755), IsNil)
   148  	snapfile, err := pack.Snap(sourceDir, c.MkDir(), "")
   149  	c.Assert(err, IsNil)
   150  	c.Assert(squashfs.New(snapfile).Unpack("*", target), IsNil)
   151  
   152  	cmd := exec.Command("diff", "-qr", sourceDir, target)
   153  	cmd.Env = append(cmd.Env, "LANG=C")
   154  	out, err := cmd.Output()
   155  	c.Check(err, NotNil)
   156  	c.Check(string(out), Matches, `(?m)Only in \S+: foo~`)
   157  }
   158  
   159  func (s *packSuite) TestPackExcludesTopLevelDEBIAN(c *C) {
   160  	sourceDir := makeExampleSnapSourceDir(c, "{name: hello, version: 0}")
   161  	target := c.MkDir()
   162  	// add a toplevel DEBIAN
   163  	c.Assert(os.MkdirAll(filepath.Join(sourceDir, "DEBIAN", "foo"), 0755), IsNil)
   164  	// and a non-toplevel DEBIAN
   165  	c.Assert(os.MkdirAll(filepath.Join(sourceDir, "bar", "DEBIAN", "baz"), 0755), IsNil)
   166  	snapfile, err := pack.Snap(sourceDir, c.MkDir(), "")
   167  	c.Assert(err, IsNil)
   168  	c.Assert(squashfs.New(snapfile).Unpack("*", target), IsNil)
   169  	cmd := exec.Command("diff", "-qr", sourceDir, target)
   170  	cmd.Env = append(cmd.Env, "LANG=C")
   171  	out, err := cmd.Output()
   172  	c.Check(err, NotNil)
   173  	c.Check(string(out), Matches, `(?m)Only in \S+: DEBIAN`)
   174  	// but *only one* DEBIAN is skipped
   175  	c.Check(strings.Count(string(out), "Only in"), Equals, 1)
   176  }
   177  
   178  func (s *packSuite) TestPackExcludesWholeDirs(c *C) {
   179  	sourceDir := makeExampleSnapSourceDir(c, "{name: hello, version: 0}")
   180  	target := c.MkDir()
   181  	// add a file inside a skipped dir
   182  	c.Assert(os.Mkdir(filepath.Join(sourceDir, ".bzr"), 0755), IsNil)
   183  	c.Assert(ioutil.WriteFile(filepath.Join(sourceDir, ".bzr", "foo"), []byte("hi"), 0755), IsNil)
   184  	snapfile, err := pack.Snap(sourceDir, c.MkDir(), "")
   185  	c.Assert(err, IsNil)
   186  	c.Assert(squashfs.New(snapfile).Unpack("*", target), IsNil)
   187  	out, _ := exec.Command("find", sourceDir).Output()
   188  	c.Check(string(out), Not(Equals), "")
   189  	cmd := exec.Command("diff", "-qr", sourceDir, target)
   190  	cmd.Env = append(cmd.Env, "LANG=C")
   191  	out, err = cmd.Output()
   192  	c.Check(err, NotNil)
   193  	c.Check(string(out), Matches, `(?m)Only in \S+: \.bzr`)
   194  }
   195  
   196  func (s *packSuite) TestDebArchitecture(c *C) {
   197  	c.Check(pack.DebArchitecture(&snap.Info{Architectures: []string{"foo"}}), Equals, "foo")
   198  	c.Check(pack.DebArchitecture(&snap.Info{Architectures: []string{"foo", "bar"}}), Equals, "multi")
   199  	c.Check(pack.DebArchitecture(&snap.Info{Architectures: nil}), Equals, "all")
   200  }
   201  
   202  func (s *packSuite) TestPackSimple(c *C) {
   203  	sourceDir := makeExampleSnapSourceDir(c, `name: hello
   204  version: 1.0.1
   205  architectures: ["i386", "amd64"]
   206  integration:
   207   app:
   208    apparmor-profile: meta/hello.apparmor
   209  `)
   210  
   211  	outputDir := filepath.Join(c.MkDir(), "output")
   212  	absSnapFile := filepath.Join(c.MkDir(), "foo.snap")
   213  
   214  	type T struct {
   215  		outputDir, filename, expected string
   216  	}
   217  
   218  	table := []T{
   219  		// no output dir, no filename -> default in .
   220  		{"", "", "hello_1.0.1_multi.snap"},
   221  		// no output dir, relative filename -> filename in .
   222  		{"", "foo.snap", "foo.snap"},
   223  		// no putput dir, absolute filename -> absolute filename
   224  		{"", absSnapFile, absSnapFile},
   225  		// output dir, no filename -> default in outputdir
   226  		{outputDir, "", filepath.Join(outputDir, "hello_1.0.1_multi.snap")},
   227  		// output dir, relative filename -> filename in outputDir
   228  		{filepath.Join(outputDir, "inner"), "../foo.snap", filepath.Join(outputDir, "foo.snap")},
   229  		// output dir, absolute filename -> absolute filename
   230  		{outputDir, absSnapFile, absSnapFile},
   231  	}
   232  
   233  	for i, t := range table {
   234  		comm := Commentf("%d", i)
   235  		resultSnap, err := pack.Snap(sourceDir, t.outputDir, t.filename)
   236  		c.Assert(err, IsNil, comm)
   237  
   238  		// check that there is result
   239  		_, err = os.Stat(resultSnap)
   240  		c.Assert(err, IsNil, comm)
   241  		c.Assert(resultSnap, Equals, t.expected, comm)
   242  
   243  		// check that the content looks sane
   244  		output, err := exec.Command("unsquashfs", "-ll", resultSnap).CombinedOutput()
   245  		c.Assert(err, IsNil, comm)
   246  		for _, needle := range []string{
   247  			"meta/snap.yaml",
   248  			"bin/hello-world",
   249  			"symlink -> bin/hello-world",
   250  		} {
   251  			expr := fmt.Sprintf(`(?ms).*%s.*`, regexp.QuoteMeta(needle))
   252  			c.Assert(string(output), Matches, expr, comm)
   253  		}
   254  	}
   255  
   256  }