1
// Copyright 2013 Canonical Ltd.
2
// Licensed under the LGPLv3, see LICENCE file for details.
13
"github.com/juju/testing"
14
jc "github.com/juju/testing/checkers"
15
gc "gopkg.in/check.v1"
17
"github.com/juju/utils"
20
type fileSuite struct {
21
testing.IsolationSuite
24
var _ = gc.Suite(&fileSuite{})
26
func (*fileSuite) TestNormalizePath(c *gc.C) {
27
home := filepath.FromSlash(c.MkDir())
28
err := utils.SetHome(home)
29
c.Assert(err, gc.IsNil)
30
// TODO (frankban) bug 1324841: improve the isolation of this suite.
31
currentUser, err := user.Current()
32
c.Assert(err, gc.IsNil)
33
for i, test := range []struct {
38
path: filepath.FromSlash("/var/lib/juju"),
39
expected: filepath.FromSlash("/var/lib/juju"),
42
expected: filepath.Join(home, "foo"),
44
path: "~/foo//../bar",
45
expected: filepath.Join(home, "bar"),
50
path: "~" + currentUser.Username,
51
expected: currentUser.HomeDir,
53
path: "~" + currentUser.Username + "/foo",
54
expected: filepath.Join(currentUser.HomeDir, "foo"),
56
path: "~" + currentUser.Username + "/foo//../bar",
57
expected: filepath.Join(currentUser.HomeDir, "bar"),
59
path: filepath.FromSlash("foo~bar/baz"),
60
expected: filepath.FromSlash("foo~bar/baz"),
63
err: ".*" + utils.NoSuchUserErrRegexp,
65
c.Logf("test %d: %s", i, test.path)
66
actual, err := utils.NormalizePath(test.path)
68
c.Check(err, gc.ErrorMatches, test.err)
70
c.Check(err, gc.IsNil)
71
c.Check(actual, gc.Equals, test.expected)
76
func (*fileSuite) TestCopyFile(c *gc.C) {
78
f, err := ioutil.TempFile(dir, "source")
79
c.Assert(err, gc.IsNil)
81
_, err = f.Write([]byte("hello world"))
82
c.Assert(err, gc.IsNil)
83
dest := filepath.Join(dir, "dest")
85
err = utils.CopyFile(dest, f.Name())
86
c.Assert(err, gc.IsNil)
87
data, err := ioutil.ReadFile(dest)
88
c.Assert(err, gc.IsNil)
89
c.Assert(string(data), gc.Equals, "hello world")
92
var atomicWriteFileTests = []struct {
94
change func(filename string, contents []byte) error
95
check func(c *gc.C, fileInfo os.FileInfo)
98
summary: "atomic file write and chmod 0644",
99
change: func(filename string, contents []byte) error {
100
return utils.AtomicWriteFile(filename, contents, 0765)
102
check: func(c *gc.C, fi os.FileInfo) {
103
c.Assert(fi.Mode(), gc.Equals, 0765)
106
summary: "atomic file write and change",
107
change: func(filename string, contents []byte) error {
108
chmodChange := func(f *os.File) error {
109
// FileMod.Chmod() is not implemented on Windows, however, os.Chmod() is
110
return os.Chmod(f.Name(), 0700)
112
return utils.AtomicWriteFileAndChange(filename, contents, chmodChange)
114
check: func(c *gc.C, fi os.FileInfo) {
115
c.Assert(fi.Mode(), gc.Equals, 0700)
118
summary: "atomic file write empty contents",
119
change: func(filename string, contents []byte) error {
120
nopChange := func(*os.File) error {
123
return utils.AtomicWriteFileAndChange(filename, contents, nopChange)
126
summary: "atomic file write and failing change func",
127
change: func(filename string, contents []byte) error {
128
errChange := func(*os.File) error {
129
return fmt.Errorf("pow!")
131
return utils.AtomicWriteFileAndChange(filename, contents, errChange)
136
func (*fileSuite) TestAtomicWriteFile(c *gc.C) {
139
path := filepath.Join(dir, name)
140
assertDirContents := func(names ...string) {
141
fis, err := ioutil.ReadDir(dir)
142
c.Assert(err, gc.IsNil)
143
c.Assert(fis, gc.HasLen, len(names))
144
for i, name := range names {
145
c.Assert(fis[i].Name(), gc.Equals, name)
148
assertNotExist := func(path string) {
149
_, err := os.Lstat(path)
150
c.Assert(err, jc.Satisfies, os.IsNotExist)
153
for i, test := range atomicWriteFileTests {
154
c.Logf("test %d: %s", i, test.summary)
155
// First - test with file not already there.
158
contents := []byte("some\ncontents")
160
err := test.change(path, contents)
161
if test.expectErr == "" {
162
c.Assert(err, gc.IsNil)
163
data, err := ioutil.ReadFile(path)
164
c.Assert(err, gc.IsNil)
165
c.Assert(data, jc.DeepEquals, contents)
166
assertDirContents(name)
168
c.Assert(err, gc.ErrorMatches, test.expectErr)
173
// Second - test with a file already there.
174
contents = []byte("new\ncontents")
175
err = test.change(path, contents)
176
c.Assert(err, gc.IsNil)
177
data, err := ioutil.ReadFile(path)
178
c.Assert(err, gc.IsNil)
179
c.Assert(data, jc.DeepEquals, contents)
180
assertDirContents(name)
182
// Remove the file to reset scenario.
183
c.Assert(os.Remove(path), gc.IsNil)
187
func (*fileSuite) TestMoveFile(c *gc.C) {
189
dest := filepath.Join(d, "foo")
190
f1Name := filepath.Join(d, ".foo1")
191
f2Name := filepath.Join(d, ".foo2")
192
err := ioutil.WriteFile(f1Name, []byte("macaroni"), 0644)
193
c.Assert(err, gc.IsNil)
194
err = ioutil.WriteFile(f2Name, []byte("cheese"), 0644)
195
c.Assert(err, gc.IsNil)
197
ok, err := utils.MoveFile(f1Name, dest)
198
c.Assert(ok, gc.Equals, true)
199
c.Assert(err, gc.IsNil)
201
ok, err = utils.MoveFile(f2Name, dest)
202
c.Assert(ok, gc.Equals, false)
203
c.Assert(err, gc.NotNil)
205
contents, err := ioutil.ReadFile(dest)
206
c.Assert(err, gc.IsNil)
207
c.Assert(contents, gc.DeepEquals, []byte("macaroni"))