gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/osutil/synctree_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 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 osutil_test 21 22 import ( 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 27 . "gopkg.in/check.v1" 28 29 "github.com/snapcore/snapd/osutil" 30 "github.com/snapcore/snapd/testutil" 31 ) 32 33 type EnsureTreeStateSuite struct { 34 dir string 35 globs []string 36 } 37 38 var _ = Suite(&EnsureTreeStateSuite{globs: []string{"*.snap"}}) 39 40 func (s *EnsureTreeStateSuite) SetUpTest(c *C) { 41 s.dir = c.MkDir() 42 } 43 44 func (s *EnsureTreeStateSuite) TestVerifiesExpectedFiles(c *C) { 45 c.Assert(os.MkdirAll(filepath.Join(s.dir, "foo", "bar"), 0755), IsNil) 46 name := filepath.Join(s.dir, "foo", "bar", "expected.snap") 47 c.Assert(ioutil.WriteFile(name, []byte("expected"), 0600), IsNil) 48 changed, removed, err := osutil.EnsureTreeState(s.dir, s.globs, map[string]map[string]osutil.FileState{ 49 "foo/bar": { 50 "expected.snap": &osutil.MemoryFileState{Content: []byte("expected"), Mode: 0600}, 51 }, 52 }) 53 c.Assert(err, IsNil) 54 c.Check(changed, HasLen, 0) 55 c.Check(removed, HasLen, 0) 56 57 // The content and permissions are correct 58 c.Check(name, testutil.FileEquals, "expected") 59 stat, err := os.Stat(name) 60 c.Assert(err, IsNil) 61 c.Check(stat.Mode().Perm(), Equals, os.FileMode(0600)) 62 } 63 64 func (s *EnsureTreeStateSuite) TestCreatesMissingFiles(c *C) { 65 c.Assert(os.MkdirAll(filepath.Join(s.dir, "foo"), 0755), IsNil) 66 67 changed, removed, err := osutil.EnsureTreeState(s.dir, s.globs, map[string]map[string]osutil.FileState{ 68 "foo": { 69 "missing1.snap": &osutil.MemoryFileState{Content: []byte(`content-1`), Mode: 0600}, 70 }, 71 "bar": { 72 "missing2.snap": &osutil.MemoryFileState{Content: []byte(`content-2`), Mode: 0600}, 73 }, 74 }) 75 c.Assert(err, IsNil) 76 c.Check(changed, DeepEquals, []string{"bar/missing2.snap", "foo/missing1.snap"}) 77 c.Check(removed, HasLen, 0) 78 } 79 80 func (s *EnsureTreeStateSuite) TestRemovesUnexpectedFiles(c *C) { 81 c.Assert(os.MkdirAll(filepath.Join(s.dir, "foo"), 0755), IsNil) 82 c.Assert(os.MkdirAll(filepath.Join(s.dir, "bar"), 0755), IsNil) 83 name1 := filepath.Join(s.dir, "foo", "evil1.snap") 84 name2 := filepath.Join(s.dir, "bar", "evil2.snap") 85 c.Assert(ioutil.WriteFile(name1, []byte(`evil-1`), 0600), IsNil) 86 c.Assert(ioutil.WriteFile(name2, []byte(`evil-2`), 0600), IsNil) 87 88 changed, removed, err := osutil.EnsureTreeState(s.dir, s.globs, map[string]map[string]osutil.FileState{ 89 "foo": {}, 90 }) 91 c.Assert(err, IsNil) 92 c.Check(changed, HasLen, 0) 93 c.Check(removed, DeepEquals, []string{"bar/evil2.snap", "foo/evil1.snap"}) 94 c.Check(name1, testutil.FileAbsent) 95 c.Check(name2, testutil.FileAbsent) 96 } 97 98 func (s *EnsureTreeStateSuite) TestRemovesEmptyDirectories(c *C) { 99 c.Assert(os.MkdirAll(filepath.Join(s.dir, "foo"), 0755), IsNil) 100 c.Assert(os.MkdirAll(filepath.Join(s.dir, "bar", "baz"), 0755), IsNil) 101 name1 := filepath.Join(s.dir, "foo", "file1.snap") 102 name2 := filepath.Join(s.dir, "foo", "unrelated") 103 name3 := filepath.Join(s.dir, "bar", "baz", "file2.snap") 104 c.Assert(ioutil.WriteFile(name1, []byte(`text`), 0600), IsNil) 105 c.Assert(ioutil.WriteFile(name2, []byte(`text`), 0600), IsNil) 106 c.Assert(ioutil.WriteFile(name3, []byte(`text`), 0600), IsNil) 107 108 _, _, err := osutil.EnsureTreeState(s.dir, s.globs, nil) 109 c.Assert(err, IsNil) 110 111 // The "foo" directory is still present, while the "bar" tree 112 // has been removed. 113 c.Check(filepath.Join(s.dir, "foo"), testutil.FilePresent) 114 c.Check(filepath.Join(s.dir, "bar"), testutil.FileAbsent) 115 } 116 117 func (s *EnsureTreeStateSuite) TestIgnoresUnrelatedFiles(c *C) { 118 c.Assert(os.MkdirAll(filepath.Join(s.dir, "foo"), 0755), IsNil) 119 name := filepath.Join(s.dir, "foo", "unrelated") 120 err := ioutil.WriteFile(name, []byte(`text`), 0600) 121 c.Assert(err, IsNil) 122 changed, removed, err := osutil.EnsureTreeState(s.dir, s.globs, map[string]map[string]osutil.FileState{}) 123 c.Assert(err, IsNil) 124 // Report says that nothing has changed 125 c.Check(changed, HasLen, 0) 126 c.Check(removed, HasLen, 0) 127 // The file is still there 128 c.Check(name, testutil.FilePresent) 129 } 130 131 func (s *EnsureTreeStateSuite) TestErrorsOnBadGlob(c *C) { 132 _, _, err := osutil.EnsureTreeState(s.dir, []string{"["}, nil) 133 c.Check(err, ErrorMatches, `internal error: EnsureTreeState got invalid pattern "\[": syntax error in pattern`) 134 } 135 136 func (s *EnsureTreeStateSuite) TestErrorsOnDirectoryPathsMatchingGlobs(c *C) { 137 _, _, err := osutil.EnsureTreeState(s.dir, s.globs, map[string]map[string]osutil.FileState{ 138 "foo/bar.snap/baz": nil, 139 }) 140 c.Check(err, ErrorMatches, `internal error: EnsureTreeState got path "foo/bar.snap/baz" that matches glob pattern "\*.snap"`) 141 } 142 143 func (s *EnsureTreeStateSuite) TestErrorsOnFilenamesWithSlashes(c *C) { 144 _, _, err := osutil.EnsureTreeState(s.dir, s.globs, map[string]map[string]osutil.FileState{ 145 "foo": { 146 "dir/file1.snap": &osutil.MemoryFileState{Content: []byte(`content-1`), Mode: 0600}, 147 }, 148 }) 149 c.Check(err, ErrorMatches, `internal error: EnsureTreeState got filename "dir/file1.snap" in "foo", which has a path component`) 150 } 151 152 func (s *EnsureTreeStateSuite) TestErrorsOnFilenamesNotMatchingGlobs(c *C) { 153 _, _, err := osutil.EnsureTreeState(s.dir, s.globs, map[string]map[string]osutil.FileState{ 154 "foo": { 155 "file1.not-snap": &osutil.MemoryFileState{Content: []byte(`content-1`), Mode: 0600}, 156 }, 157 }) 158 c.Check(err, ErrorMatches, `internal error: EnsureTreeState got filename "file1.not-snap" in "foo", which doesn't match any glob patterns \["\*.snap"\]`) 159 } 160 161 func (s *EnsureTreeStateSuite) TestRemovesFilesOnError(c *C) { 162 c.Assert(os.MkdirAll(filepath.Join(s.dir, "foo"), 0755), IsNil) 163 c.Assert(os.MkdirAll(filepath.Join(s.dir, "bar", "dir.snap"), 0755), IsNil) 164 name1 := filepath.Join(s.dir, "foo", "file1.snap") 165 name2 := filepath.Join(s.dir, "bar", "file2.snap") 166 name3 := filepath.Join(s.dir, "bar", "dir.snap", "sentinel") 167 c.Assert(ioutil.WriteFile(name1, []byte(`text`), 0600), IsNil) 168 c.Assert(ioutil.WriteFile(name2, []byte(`text`), 0600), IsNil) 169 c.Assert(ioutil.WriteFile(name3, []byte(`text`), 0600), IsNil) 170 171 changed, removed, err := osutil.EnsureTreeState(s.dir, s.globs, map[string]map[string]osutil.FileState{ 172 "foo": { 173 "file1.snap": &osutil.MemoryFileState{Content: []byte(`content-1`), Mode: 0600}, 174 }, 175 }) 176 c.Check(err, ErrorMatches, `remove .*/bar/dir.snap: directory not empty`) 177 c.Check(changed, HasLen, 0) 178 c.Check(removed, DeepEquals, []string{"bar/file2.snap", "foo/file1.snap"}) 179 180 // Matching files have been removed, along with the empty directory 181 c.Check(name1, testutil.FileAbsent) 182 c.Check(filepath.Dir(name1), testutil.FileAbsent) 183 c.Check(name2, testutil.FileAbsent) 184 185 // But the unmatched file in the bad directory remains 186 c.Check(name3, testutil.FilePresent) 187 }