OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package cipd | |
6 | |
7 import ( | |
8 "io/ioutil" | |
9 "os" | |
10 "path/filepath" | |
11 "testing" | |
12 | |
13 . "github.com/smartystreets/goconvey/convey" | |
14 ) | |
15 | |
16 func TestScanFileSystem(t *testing.T) { | |
17 Convey("Given a temp directory", t, func() { | |
18 tempDir, err := ioutil.TempDir("", "cipd_test") | |
19 So(err, ShouldBeNil) | |
20 Reset(func() { os.RemoveAll(tempDir) }) | |
21 | |
22 Convey("Scan empty dir works", func() { | |
23 files, err := ScanFileSystem(tempDir, tempDir, nil) | |
24 So(files, ShouldBeEmpty) | |
25 So(err, ShouldBeNil) | |
26 }) | |
27 | |
28 Convey("Discovering single file works", func() { | |
29 writeFile(tempDir, "single_file", "12345", 0666) | |
30 files, err := ScanFileSystem(tempDir, tempDir, nil) | |
31 So(len(files), ShouldEqual, 1) | |
32 So(err, ShouldBeNil) | |
33 | |
34 file := files[0] | |
35 So(file.Name(), ShouldEqual, "single_file") | |
36 So(file.Size(), ShouldEqual, uint64(5)) | |
37 So(file.Executable(), ShouldBeFalse) | |
38 | |
39 r, err := file.Open() | |
40 if r != nil { | |
41 defer r.Close() | |
42 } | |
43 So(err, ShouldBeNil) | |
44 buf, err := ioutil.ReadAll(r) | |
45 So(buf, ShouldResemble, []byte("12345")) | |
46 So(err, ShouldBeNil) | |
47 }) | |
48 | |
49 Convey("Discovering single executable file works", func() { | |
50 writeFile(tempDir, "single_file", "12345", 0766) | |
51 files, err := ScanFileSystem(tempDir, tempDir, nil) | |
52 So(len(files), ShouldEqual, 1) | |
53 So(err, ShouldBeNil) | |
54 file := files[0] | |
55 So(file.Executable(), ShouldBeTrue) | |
56 }) | |
57 | |
58 Convey("Relative symlink to outside of package cause error", fun
c() { | |
59 writeSymlink(tempDir, "a/b1/rel_symlink", filepath.FromS
lash("../../..")) | |
60 _, err := ScanFileSystem(tempDir, tempDir, nil) | |
61 So(err, ShouldNotBeNil) | |
62 }) | |
63 | |
64 Convey("Enumerating subdirectories", func() { | |
65 writeFile(tempDir, "a", "", 0666) | |
66 writeFile(tempDir, "b", "", 0666) | |
67 writeFile(tempDir, "1/a", "", 0666) | |
68 writeFile(tempDir, "1/b", "", 0666) | |
69 writeFile(tempDir, "1/2/a", "", 0666) | |
70 files, err := ScanFileSystem(tempDir, tempDir, nil) | |
71 So(err, ShouldBeNil) | |
72 names := []string{} | |
73 for _, f := range files { | |
74 names = append(names, f.Name()) | |
75 } | |
76 // Order matters. Slashes matters. | |
77 So(names, ShouldResemble, []string{ | |
78 "1/2/a", | |
79 "1/a", | |
80 "1/b", | |
81 "a", | |
82 "b", | |
83 }) | |
84 }) | |
85 | |
86 Convey("Empty subdirectories are skipped", func() { | |
87 mkDir(tempDir, "a") | |
88 mkDir(tempDir, "1/2/3") | |
89 mkDir(tempDir, "1/c") | |
90 writeFile(tempDir, "1/d/file", "1234", 0666) | |
91 files, err := ScanFileSystem(tempDir, tempDir, nil) | |
92 So(len(files), ShouldEqual, 1) | |
93 So(err, ShouldBeNil) | |
94 So(files[0].Name(), ShouldEqual, "1/d/file") | |
95 }) | |
96 | |
97 Convey("Non root start path works", func() { | |
98 writeFile(tempDir, "a", "", 0666) | |
99 writeFile(tempDir, "b", "", 0666) | |
100 writeFile(tempDir, "1/a", "", 0666) | |
101 writeFile(tempDir, "1/b", "", 0666) | |
102 writeFile(tempDir, "1/2/a", "", 0666) | |
103 files, err := ScanFileSystem(filepath.Join(tempDir, "1")
, tempDir, nil) | |
104 So(err, ShouldBeNil) | |
105 names := []string{} | |
106 for _, f := range files { | |
107 names = append(names, f.Name()) | |
108 } | |
109 // Order matters. Slashes matters. | |
110 So(names, ShouldResemble, []string{ | |
111 "1/2/a", | |
112 "1/a", | |
113 "1/b", | |
114 }) | |
115 }) | |
116 | |
117 Convey("Start path must be under root", func() { | |
118 _, err := ScanFileSystem(filepath.Dir(tempDir), tempDir,
nil) | |
119 So(err, ShouldNotBeNil) | |
120 }) | |
121 | |
122 Convey("Exclude filter works", func() { | |
123 writeFile(tempDir, "a", "", 0666) | |
124 writeFile(tempDir, "b", "", 0666) | |
125 writeFile(tempDir, "1/a", "", 0666) | |
126 writeFile(tempDir, "1/b", "", 0666) | |
127 writeFile(tempDir, "1/2/a", "", 0666) | |
128 | |
129 // Exclude "a" and entire "1/" directory. | |
130 excluderCalls := []string{} | |
131 excluder := func(abs string) bool { | |
132 excluderCalls = append(excluderCalls, abs) | |
133 if abs == filepath.Join(tempDir, "a") { | |
134 return true | |
135 } | |
136 if abs == filepath.Join(tempDir, "1") { | |
137 return true | |
138 } | |
139 return false | |
140 } | |
141 | |
142 files, err := ScanFileSystem(tempDir, tempDir, excluder) | |
143 So(err, ShouldBeNil) | |
144 So(len(files), ShouldEqual, 1) | |
145 So(files[0].Name(), ShouldEqual, "b") | |
146 | |
147 // "1/*" subdir should have been skipped completely. | |
148 So(excluderCalls, ShouldResemble, []string{ | |
149 filepath.Join(tempDir, "1"), | |
150 filepath.Join(tempDir, "a"), | |
151 filepath.Join(tempDir, "b"), | |
152 }) | |
153 }) | |
154 }) | |
155 } | |
156 | |
157 func TestWrapFile(t *testing.T) { | |
158 Convey("Given a temp directory", t, func() { | |
159 tempDir, err := ioutil.TempDir("", "cipd_test") | |
160 So(err, ShouldBeNil) | |
161 Reset(func() { os.RemoveAll(tempDir) }) | |
162 | |
163 Convey("WrapFile simple file works", func() { | |
164 writeFile(tempDir, "dir/a/b", "12345", 0666) | |
165 out, err := WrapFile(filepath.Join(tempDir, "dir", "a",
"b"), tempDir, nil) | |
166 So(err, ShouldBeNil) | |
167 So(out.Name(), ShouldEqual, "dir/a/b") | |
168 }) | |
169 | |
170 Convey("WrapFile executable file works", func() { | |
171 writeFile(tempDir, "single_file", "12345", 0766) | |
172 out, err := WrapFile(filepath.Join(tempDir, "single_file
"), tempDir, nil) | |
173 So(err, ShouldBeNil) | |
174 So(out.Executable(), ShouldBeTrue) | |
175 }) | |
176 | |
177 Convey("WrapFile directory fails", func() { | |
178 mkDir(tempDir, "dir") | |
179 _, err := WrapFile(filepath.Join(tempDir, "dir"), tempDi
r, nil) | |
180 So(err, ShouldNotBeNil) | |
181 }) | |
182 | |
183 Convey("WrapFile outside of root fails", func() { | |
184 mkDir(tempDir, "a") | |
185 writeFile(tempDir, "b", "body", 0666) | |
186 _, err := WrapFile(filepath.Join(tempDir, "b"), filepath
.Join(tempDir, "a"), nil) | |
187 So(err, ShouldNotBeNil) | |
188 }) | |
189 | |
190 Convey("WrapFile outside of root fails (tricky path)", func() { | |
191 mkDir(tempDir, "a") | |
192 // "abc" starts with "a", it tricks naive string.HasPref
ix subpath check. | |
193 writeFile(tempDir, "abc", "body", 0666) | |
194 _, err := WrapFile(filepath.Join(tempDir, "abc"), filepa
th.Join(tempDir, "a"), nil) | |
195 So(err, ShouldNotBeNil) | |
196 }) | |
197 | |
198 Convey("WrapFile rel symlink in root", func() { | |
199 writeSymlink(tempDir, "a/b/c", filepath.FromSlash("../..
/d")) | |
200 mkDir(tempDir, "d") | |
201 out, err := WrapFile(filepath.Join(tempDir, "a", "b", "c
"), tempDir, nil) | |
202 So(err, ShouldBeNil) | |
203 ensureSymlinkTarget(out, "../../d") | |
204 }) | |
205 | |
206 Convey("WrapFile rel symlink outside root", func() { | |
207 writeSymlink(tempDir, "a/b/c", filepath.FromSlash("../..
/../d")) | |
208 _, err := WrapFile(filepath.Join(tempDir, "a", "b", "c")
, tempDir, nil) | |
209 So(err, ShouldNotBeNil) | |
210 }) | |
211 | |
212 Convey("WrapFile abs symlink in root", func() { | |
213 writeSymlink(tempDir, "a/b/c", filepath.Join(tempDir, "a
", "d")) | |
214 out, err := WrapFile(filepath.Join(tempDir, "a", "b", "c
"), tempDir, nil) | |
215 So(err, ShouldBeNil) | |
216 ensureSymlinkTarget(out, "../d") | |
217 }) | |
218 | |
219 Convey("WrapFile abs symlink outside root", func() { | |
220 writeSymlink(tempDir, "a/b/c", filepath.Dir(tempDir)) | |
221 out, err := WrapFile(filepath.Join(tempDir, "a", "b", "c
"), tempDir, nil) | |
222 So(err, ShouldBeNil) | |
223 ensureSymlinkTarget(out, filepath.ToSlash(filepath.Dir(t
empDir))) | |
224 }) | |
225 }) | |
226 } | |
227 | |
228 func mkDir(root string, path string) { | |
229 abs := filepath.Join(root, filepath.FromSlash(path)) | |
230 err := os.MkdirAll(abs, 0777) | |
231 if err != nil { | |
232 panic("Failed to create a directory under temp directory") | |
233 } | |
234 } | |
235 | |
236 func writeFile(root string, path string, data string, mode os.FileMode) { | |
237 abs := filepath.Join(root, filepath.FromSlash(path)) | |
238 os.MkdirAll(filepath.Dir(abs), 0777) | |
239 err := ioutil.WriteFile(abs, []byte(data), mode) | |
240 if err != nil { | |
241 panic("Failed to write a temp file") | |
242 } | |
243 } | |
244 | |
245 func writeSymlink(root string, path string, target string) { | |
246 abs := filepath.Join(root, filepath.FromSlash(path)) | |
247 os.MkdirAll(filepath.Dir(abs), 0777) | |
248 err := os.Symlink(target, abs) | |
249 if err != nil { | |
250 panic("Failed to create symlink") | |
251 } | |
252 } | |
253 | |
254 func ensureSymlinkTarget(file File, target string) { | |
255 So(file.Symlink(), ShouldBeTrue) | |
256 discoveredTarget, err := file.SymlinkTarget() | |
257 So(err, ShouldBeNil) | |
258 So(discoveredTarget, ShouldEqual, target) | |
259 } | |
260 | |
261 func TestFileSystemDestination(t *testing.T) { | |
262 Convey("Given a temp directory", t, func() { | |
263 tempDir, err := ioutil.TempDir("", "cipd_test") | |
264 destDir := filepath.Join(tempDir, "dest") | |
265 So(err, ShouldBeNil) | |
266 dest := NewFileSystemDestination(destDir) | |
267 Reset(func() { os.RemoveAll(tempDir) }) | |
268 | |
269 writeFileToDest := func(name string, executable bool, data strin
g) { | |
270 writer, err := dest.CreateFile(name, executable) | |
271 if writer != nil { | |
272 defer writer.Close() | |
273 } | |
274 So(err, ShouldBeNil) | |
275 _, err = writer.Write([]byte(data)) | |
276 So(err, ShouldBeNil) | |
277 } | |
278 | |
279 writeSymlinkToDest := func(name string, target string) { | |
280 err := dest.CreateSymlink(name, target) | |
281 So(err, ShouldBeNil) | |
282 } | |
283 | |
284 Convey("Empty success write works", func() { | |
285 So(dest.Begin(), ShouldBeNil) | |
286 So(dest.End(true), ShouldBeNil) | |
287 | |
288 // Should create a new directory. | |
289 stat, err := os.Stat(destDir) | |
290 So(err, ShouldBeNil) | |
291 So(stat.IsDir(), ShouldBeTrue) | |
292 | |
293 // And it should be empty. | |
294 files, err := ScanFileSystem(destDir, destDir, nil) | |
295 So(err, ShouldBeNil) | |
296 So(len(files), ShouldEqual, 0) | |
297 }) | |
298 | |
299 Convey("Empty failed write works", func() { | |
300 So(dest.Begin(), ShouldBeNil) | |
301 So(dest.End(false), ShouldBeNil) | |
302 | |
303 // Doesn't create a directory. | |
304 _, err := os.Stat(destDir) | |
305 So(os.IsNotExist(err), ShouldBeTrue) | |
306 }) | |
307 | |
308 Convey("Double begin or double end fails", func() { | |
309 So(dest.Begin(), ShouldBeNil) | |
310 So(dest.Begin(), ShouldNotBeNil) | |
311 So(dest.End(true), ShouldBeNil) | |
312 So(dest.End(true), ShouldNotBeNil) | |
313 }) | |
314 | |
315 Convey("CreateFile works only when destination is open", func()
{ | |
316 wr, err := dest.CreateFile("testing", true) | |
317 So(wr, ShouldBeNil) | |
318 So(err, ShouldNotBeNil) | |
319 }) | |
320 | |
321 Convey("CreateFile rejects invalid relative paths", func() { | |
322 So(dest.Begin(), ShouldBeNil) | |
323 defer dest.End(true) | |
324 | |
325 // Rel path that is still inside the package is ok. | |
326 wr, err := dest.CreateFile("a/b/c/../../../d", false) | |
327 So(err, ShouldBeNil) | |
328 wr.Close() | |
329 | |
330 // Rel path pointing outside is forbidden. | |
331 _, err = dest.CreateFile("a/b/c/../../../../d", false) | |
332 So(err, ShouldNotBeNil) | |
333 }) | |
334 | |
335 Convey("CreateSymlink rejects invalid relative paths", func() { | |
336 So(dest.Begin(), ShouldBeNil) | |
337 defer dest.End(true) | |
338 | |
339 // Rel symlink to a file inside the destination is OK. | |
340 So(dest.CreateSymlink("a/b/c", "../.."), ShouldBeNil) | |
341 // Rel symlink to a file outside -> error. | |
342 So(dest.CreateSymlink("a/b/c", "../../.."), ShouldNotBeN
il) | |
343 }) | |
344 | |
345 Convey("Committing bunch of files works", func() { | |
346 So(dest.Begin(), ShouldBeNil) | |
347 writeFileToDest("a", false, "a data") | |
348 writeFileToDest("exe", true, "exe data") | |
349 writeFileToDest("dir/c", false, "dir/c data") | |
350 writeFileToDest("dir/dir/d", false, "dir/dir/c data") | |
351 writeSymlinkToDest("abs_symlink", filepath.FromSlash(tem
pDir)) | |
352 writeSymlinkToDest("dir/dir/rel_symlink", "../../a") | |
353 So(dest.End(true), ShouldBeNil) | |
354 | |
355 // Ensure everything is there. | |
356 files, err := ScanFileSystem(destDir, destDir, nil) | |
357 So(err, ShouldBeNil) | |
358 names := []string{} | |
359 for _, f := range files { | |
360 names = append(names, f.Name()) | |
361 } | |
362 So(names, ShouldResemble, []string{ | |
363 "a", | |
364 "abs_symlink", | |
365 "dir/c", | |
366 "dir/dir/d", | |
367 "dir/dir/rel_symlink", | |
368 "exe", | |
369 }) | |
370 | |
371 // Ensure data is valid (check first file only). | |
372 r, err := files[0].Open() | |
373 if r != nil { | |
374 defer r.Close() | |
375 } | |
376 So(err, ShouldBeNil) | |
377 data, err := ioutil.ReadAll(r) | |
378 So(err, ShouldBeNil) | |
379 So(data, ShouldResemble, []byte("a data")) | |
380 | |
381 // Ensure file mode is valid. | |
382 So(files[5].Name(), ShouldEqual, "exe") | |
383 So(files[5].Executable(), ShouldBeTrue) | |
384 | |
385 // Ensure absolute symlink if valid. | |
386 So(files[1].Name(), ShouldEqual, "abs_symlink") | |
387 ensureSymlinkTarget(files[1], filepath.FromSlash(tempDir
)) | |
388 | |
389 // Ensure relative symlink is valid. | |
390 So(files[4].Name(), ShouldEqual, "dir/dir/rel_symlink") | |
391 ensureSymlinkTarget(files[4], "../../a") | |
392 | |
393 // Ensure no temp files left. | |
394 allFiles, err := ScanFileSystem(tempDir, tempDir, nil) | |
395 So(len(allFiles), ShouldEqual, len(files)) | |
396 }) | |
397 | |
398 Convey("Rolling back bunch of files works", func() { | |
399 So(dest.Begin(), ShouldBeNil) | |
400 writeFileToDest("a", false, "a data") | |
401 writeFileToDest("dir/c", false, "dir/c data") | |
402 writeSymlinkToDest("dir/d", "c") | |
403 So(dest.End(false), ShouldBeNil) | |
404 | |
405 // No dest directory. | |
406 _, err := os.Stat(destDir) | |
407 So(os.IsNotExist(err), ShouldBeTrue) | |
408 | |
409 // Ensure no temp files left. | |
410 allFiles, err := ScanFileSystem(tempDir, tempDir, nil) | |
411 So(len(allFiles), ShouldEqual, 0) | |
412 }) | |
413 | |
414 Convey("Overwriting a directory works", func() { | |
415 // Create dest directory manually with some stuff. | |
416 err := os.Mkdir(destDir, 0777) | |
417 So(err, ShouldBeNil) | |
418 err = ioutil.WriteFile(filepath.Join(destDir, "data"), [
]byte("data"), 0666) | |
419 So(err, ShouldBeNil) | |
420 | |
421 // Now deploy something to it. | |
422 So(dest.Begin(), ShouldBeNil) | |
423 writeFileToDest("a", false, "a data") | |
424 writeSymlinkToDest("b", "a") | |
425 So(dest.End(true), ShouldBeNil) | |
426 | |
427 // Overwritten. | |
428 files, err := ScanFileSystem(destDir, destDir, nil) | |
429 So(err, ShouldBeNil) | |
430 So(len(files), ShouldEqual, 2) | |
431 So(files[0].Name(), ShouldEqual, "a") | |
432 So(files[1].Name(), ShouldEqual, "b") | |
433 }) | |
434 | |
435 Convey("Not overwriting a directory works", func() { | |
436 // Create dest directory manually with some stuff. | |
437 err := os.Mkdir(destDir, 0777) | |
438 So(err, ShouldBeNil) | |
439 err = ioutil.WriteFile(filepath.Join(destDir, "data"), [
]byte("data"), 0666) | |
440 So(err, ShouldBeNil) | |
441 | |
442 // Now attempt deploy something to it, but roll back. | |
443 So(dest.Begin(), ShouldBeNil) | |
444 writeFileToDest("a", false, "a data") | |
445 writeSymlinkToDest("b", "a") | |
446 So(dest.End(false), ShouldBeNil) | |
447 | |
448 // Kept as is. | |
449 files, err := ScanFileSystem(destDir, destDir, nil) | |
450 So(err, ShouldBeNil) | |
451 So(len(files), ShouldEqual, 1) | |
452 So(files[0].Name(), ShouldEqual, "data") | |
453 }) | |
454 | |
455 Convey("Opening file twice fails", func() { | |
456 So(dest.Begin(), ShouldBeNil) | |
457 writeFileToDest("a", false, "a data") | |
458 w, err := dest.CreateFile("a", false) | |
459 So(w, ShouldBeNil) | |
460 So(err, ShouldNotBeNil) | |
461 So(dest.End(true), ShouldBeNil) | |
462 }) | |
463 | |
464 Convey("End with opened files fail", func() { | |
465 So(dest.Begin(), ShouldBeNil) | |
466 w, err := dest.CreateFile("a", false) | |
467 So(w, ShouldNotBeNil) | |
468 So(err, ShouldBeNil) | |
469 So(dest.End(true), ShouldNotBeNil) | |
470 w.Close() | |
471 So(dest.End(true), ShouldBeNil) | |
472 }) | |
473 }) | |
474 } | |
OLD | NEW |