1
// Copyright 2013, 2014 Canonical Ltd.
2
// Licensed under the LGPLv3, see LICENCE file for details.
11
jc "github.com/juju/testing/checkers"
12
gc "launchpad.net/gocheck"
14
"launchpad.net/juju-core/utils"
17
// Entry represents a filesystem entity that can be created; and whose
18
// correctness can be verified.
19
type Entry interface {
21
// GetPath returns the slash-separated relative path that this
25
// Create causes the entry to be created, relative to basePath. It returns
26
// a copy of the receiver.
27
Create(c *gc.C, basePath string) Entry
29
// Check checks that the entry exists, relative to basePath, and matches
30
// the entry that would be created by Create. It returns a copy of the
32
Check(c *gc.C, basePath string) Entry
42
// Entries supplies convenience methods on Entry slices.
45
// Paths returns the slash-separated path of every entry.
46
func (e Entries) Paths() []string {
47
result := make([]string, len(e))
48
for i, entry := range e {
49
result[i] = entry.GetPath()
54
// Create creates every entry relative to basePath and returns a copy of itself.
55
func (e Entries) Create(c *gc.C, basePath string) Entries {
56
result := make([]Entry, len(e))
57
for i, entry := range e {
58
result[i] = entry.Create(c, basePath)
63
// Check checks every entry relative to basePath and returns a copy of itself.
64
func (e Entries) Check(c *gc.C, basePath string) Entries {
65
result := make([]Entry, len(e))
66
for i, entry := range e {
67
result[i] = entry.Check(c, basePath)
72
// AsRemoveds returns a slice of Removed entries whose paths correspond to
74
func (e Entries) AsRemoveds() Entries {
75
result := make([]Entry, len(e))
76
for i, entry := range e {
77
result[i] = Removed{entry.GetPath()}
82
// join joins a slash-separated path to a filesystem basePath.
83
func join(basePath, path string) string {
84
return filepath.Join(basePath, filepath.FromSlash(path))
87
// Dir is an Entry that allows directories to be created and verified. The
88
// Path field should use "/" as the path separator.
94
func (d Dir) GetPath() string {
98
func (d Dir) Create(c *gc.C, basePath string) Entry {
99
path := join(basePath, d.Path)
100
err := os.MkdirAll(path, d.Perm)
101
c.Assert(err, gc.IsNil)
102
err = os.Chmod(path, d.Perm)
103
c.Assert(err, gc.IsNil)
107
func (d Dir) Check(c *gc.C, basePath string) Entry {
108
fileInfo, err := os.Lstat(join(basePath, d.Path))
109
if !c.Check(err, gc.IsNil) {
112
c.Check(fileInfo.Mode()&os.ModePerm, gc.Equals, d.Perm)
113
c.Check(fileInfo.Mode()&os.ModeType, gc.Equals, os.ModeDir)
117
// File is an Entry that allows plain files to be created and verified. The
118
// Path field should use "/" as the path separator.
125
func (f File) GetPath() string {
129
func (f File) Create(c *gc.C, basePath string) Entry {
130
err := ioutil.WriteFile(join(basePath, f.Path), []byte(f.Data), f.Perm)
131
c.Assert(err, gc.IsNil)
135
func (f File) Check(c *gc.C, basePath string) Entry {
136
path := join(basePath, f.Path)
137
fileInfo, err := os.Lstat(path)
138
if !c.Check(err, gc.IsNil) {
141
mode := fileInfo.Mode()
142
c.Check(mode&os.ModeType, gc.Equals, os.FileMode(0))
143
c.Check(mode&os.ModePerm, gc.Equals, f.Perm)
144
data, err := ioutil.ReadFile(path)
145
c.Check(err, gc.IsNil)
146
c.Check(string(data), gc.Equals, f.Data)
150
// Symlink is an Entry that allows symlinks to be created and verified. The
151
// Path field should use "/" as the path separator.
152
type Symlink struct {
157
func (s Symlink) GetPath() string {
161
func (s Symlink) Create(c *gc.C, basePath string) Entry {
162
err := os.Symlink(s.Link, join(basePath, s.Path))
163
c.Assert(err, gc.IsNil)
167
func (s Symlink) Check(c *gc.C, basePath string) Entry {
168
link, err := os.Readlink(join(basePath, s.Path))
169
c.Check(err, gc.IsNil)
170
c.Check(link, gc.Equals, s.Link)
174
// Removed is an Entry that indicates the absence of any entry. The Path
175
// field should use "/" as the path separator.
176
type Removed struct {
180
func (r Removed) GetPath() string {
184
func (r Removed) Create(c *gc.C, basePath string) Entry {
185
err := os.RemoveAll(join(basePath, r.Path))
186
c.Assert(err, gc.IsNil)
190
func (r Removed) Check(c *gc.C, basePath string) Entry {
191
_, err := os.Lstat(join(basePath, r.Path))
192
// utils.IsNotExist allows us to handle the following case:
193
// File{"foo", ...}.Create(...)
194
// Removed{"foo/bar"}.Check(...)
195
// ...where os.IsNotExist would not work.
196
c.Assert(err, jc.Satisfies, utils.IsNotExist)