File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\test\java\hudson\FilePathTest.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Alan Harder
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson;
25
26 import static org.mockito.Mockito.*;
27 import hudson.FilePath.TarCompression;
28 import hudson.model.TaskListener;
29 import hudson.remoting.LocalChannel;
30 import hudson.remoting.VirtualChannel;
31 import hudson.util.IOException2;
32 import hudson.util.NullStream;
33
34 import java.io.ByteArrayInputStream;
35 import java.io.ByteArrayOutputStream;
36 import java.io.File;
37 import java.io.FileOutputStream;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.io.OutputStream;
41 import java.net.HttpURLConnection;
42 import java.net.URL;
43 import java.net.URLConnection;
44 import java.net.URLStreamHandler;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.HashSet;
48 import java.util.List;
49 import java.util.Set;
50 import java.util.concurrent.Callable;
51 import java.util.concurrent.ExecutorService;
52 import java.util.concurrent.Executors;
53 import java.util.concurrent.Future;
54 import java.util.zip.ZipEntry;
55 import java.util.zip.ZipOutputStream;
56
57 import org.apache.commons.io.FileUtils;
58 import org.apache.commons.io.output.NullOutputStream;
59 import org.apache.tools.ant.Project;
60 import org.apache.tools.ant.taskdefs.Chmod;
61 import org.jvnet.hudson.test.Bug;
62
63 /**
64 * @author Kohsuke Kawaguchi
65 */
66 public class FilePathTest extends ChannelTestCase {
67
68 public void testCopyTo() throws Exception {
69 File tmp = File.createTempFile("testCopyTo","");
70 FilePath f = new FilePath(french,tmp.getPath());
71 f.copyTo(new NullStream());
72 assertTrue("target does not exist", tmp.exists());
73 assertTrue("could not delete target " + tmp.getPath(), tmp.delete());
74 }
75
76 /**
77 * An attempt to reproduce the file descriptor leak.
78 * If this operation leaks a file descriptor, 2500 should be enough, I think.
79 */
80 // TODO: this test is much too slow to be a traditional unit test. Should be extracted into some stress test
81 // which is no part of the default test harness?
82 public void testNoFileLeakInCopyTo() throws Exception {
83 for (int j=0; j<2500; j++) {
84 File tmp = File.createTempFile("testCopyFrom","");
85 FilePath f = new FilePath(tmp);
86 File tmp2 = File.createTempFile("testCopyTo","");
87 FilePath f2 = new FilePath(british,tmp2.getPath());
88
89 f.copyTo(f2);
90
91 f.delete();
92 f2.delete();
93 }
94 }
95
96 /**
97 * As we moved the I/O handling to another thread, there's a race condition in
98 * {@link FilePath#copyTo(OutputStream)} &mdash; this method can return before
99 * all the writes are delivered to {@link OutputStream}.
100 *
101 * <p>
102 * To reproduce that problem, we use a large number of threads, so that we can
103 * maximize the chance of out-of-order execution, and make sure we are
104 * seeing the right byte count at the end.
105 *
106 * Also see JENKINS-7897
107 */
108 @Bug(7871)
109 public void testNoRaceConditionInCopyTo() throws Exception {
110 final File tmp = File.createTempFile("testNoRaceConditionInCopyTo","");
111
112 try {
113 int fileSize = 90000;
114
115 givenSomeContentInFile(tmp, fileSize);
116
117 List<Future<Integer>> results = whenFileIsCopied100TimesConcurrently(tmp);
118
119 // THEN copied count was always equal the expected size
120 for (Future<Integer> f : results)
121 assertEquals(fileSize,f.get().intValue());
122 } finally {
123 tmp.delete();
124 }
125 }
126
127 private void givenSomeContentInFile(File file, int size) throws IOException {
128 FileOutputStream os = new FileOutputStream(file);
129 byte[] buf = new byte[size];
130 for (int i=0; i<buf.length; i++)
131 buf[i] = (byte)(i%256);
132 os.write(buf);
133 os.close();
134 }
135
136 private List<Future<Integer>> whenFileIsCopied100TimesConcurrently(final File file) throws InterruptedException {
137 List<Callable<Integer>> r = new ArrayList<Callable<Integer>>();
138 for (int i=0; i<100; i++) {
139 r.add(new Callable<Integer>() {
140 public Integer call() throws Exception {
141 class Sink extends OutputStream {
142 private Exception closed;
143 private volatile int count;
144
145 private void checkNotClosed() throws IOException2 {
146 if (closed != null)
147 throw new IOException2(closed);
148 }
149
150 @Override
151 public void write(int b) throws IOException {
152 count++;
153 checkNotClosed();
154 }
155
156 @Override
157 public void write(byte[] b) throws IOException {
158 count+=b.length;
159 checkNotClosed();
160 }
161
162 @Override
163 public void write(byte[] b, int off, int len) throws IOException {
164 count+=len;
165 checkNotClosed();
166 }
167
168 @Override
169 public void close() throws IOException {
170 closed = new Exception();
171 //if (size!=count)
172 // fail();
173 }
174 }
175
176 FilePath f = new FilePath(french, file.getPath());
177 Sink sink = new Sink();
178 f.copyTo(sink);
179 return sink.count;
180 }
181 });
182 }
183
184 ExecutorService es = Executors.newFixedThreadPool(100);
185 try {
186 return es.invokeAll(r);
187 } finally {
188 es.shutdown();
189 }
190 }
191
192 public void testRepeatCopyRecursiveTo() throws Exception {
193 // local->local copy used to return 0 if all files were "up to date"
194 // should return number of files processed, whether or not they were copied or already current
195 File tmp = Util.createTempDir(), src = new File(tmp, "src"), dst = new File(tmp, "dst");
196 try {
197 assertTrue(src.mkdir());
198 assertTrue(dst.mkdir());
199 File.createTempFile("foo", ".tmp", src);
200 FilePath fp = new FilePath(src);
201 assertEquals(1, fp.copyRecursiveTo(new FilePath(dst)));
202 // copy again should still report 1
203 assertEquals(1, fp.copyRecursiveTo(new FilePath(dst)));
204 } finally {
205 Util.deleteRecursive(tmp);
206 }
207 }
208
209 public void testArchiveBug4039() throws Exception {
210 File tmp = Util.createTempDir();
211 try {
212 FilePath d = new FilePath(french,tmp.getPath());
213 d.child("test").touch(0);
214 d.zip(new NullOutputStream());
215 d.zip(new NullOutputStream(),"**/*");
216 } finally {
217 Util.deleteRecursive(tmp);
218 }
219 }
220
221 public void testNormalization() throws Exception {
222 compare("abc/def\\ghi","abc/def\\ghi"); // allow mixed separators
223
224 {// basic '.' trimming
225 compare("./abc/def","abc/def");
226 compare("abc/./def","abc/def");
227 compare("abc/def/.","abc/def");
228
229 compare(".\\abc\\def","abc\\def");
230 compare("abc\\.\\def","abc\\def");
231 compare("abc\\def\\.","abc\\def");
232 }
233
234 compare("abc/../def","def");
235 compare("abc/def/../../ghi","ghi");
236 compare("abc/./def/../././../ghi","ghi"); // interleaving . and ..
237
238 compare("../abc/def","../abc/def"); // uncollapsible ..
239 compare("abc/def/..","abc");
240
241 compare("c:\\abc\\..","c:\\"); // we want c:\\, not c:
242 compare("c:\\abc\\def\\..","c:\\abc");
243
244 compare("/abc/../","/");
245 compare("abc/..",".");
246 compare(".",".");
247
248 // @Bug(5951)
249 compare("C:\\Hudson\\jobs\\foo\\workspace/../../otherjob/workspace/build.xml",
250 "C:\\Hudson\\jobs/otherjob/workspace/build.xml");
251 // Other cases that failed before
252 compare("../../abc/def","../../abc/def");
253 compare("..\\..\\abc\\def","..\\..\\abc\\def");
254 compare("/abc//../def","/def");
255 compare("c:\\abc\\\\..\\def","c:\\def");
256 compare("/../abc/def","/abc/def");
257 compare("c:\\..\\abc\\def","c:\\abc\\def");
258 compare("abc/def/","abc/def");
259 compare("abc\\def\\","abc\\def");
260 // The new code can collapse extra separator chars
261 compare("abc//def/\\//\\ghi","abc/def/ghi");
262 compare("\\\\host\\\\abc\\\\\\def","\\\\host\\abc\\def"); // don't collapse for \\ prefix
263 compare("\\\\\\foo","\\\\foo");
264 compare("//foo","/foo");
265 // Other edge cases
266 compare("abc/def/../../../ghi","../ghi");
267 compare("\\abc\\def\\..\\..\\..\\ghi\\","\\ghi");
268 }
269
270 private void compare(String original, String answer) {
271 assertEquals(answer,new FilePath((VirtualChannel)null,original).getRemote());
272 }
273
274 // @Bug(6494)
275 public void testGetParent() throws Exception {
276 FilePath fp = new FilePath((VirtualChannel)null, "/abc/def");
277 assertEquals("/abc", (fp = fp.getParent()).getRemote());
278 assertEquals("/", (fp = fp.getParent()).getRemote());
279 assertNull(fp.getParent());
280
281 fp = new FilePath((VirtualChannel)null, "abc/def\\ghi");
282 assertEquals("abc/def", (fp = fp.getParent()).getRemote());
283 assertEquals("abc", (fp = fp.getParent()).getRemote());
284 assertNull(fp.getParent());
285
286 fp = new FilePath((VirtualChannel)null, "C:\\abc\\def");
287 assertEquals("C:\\abc", (fp = fp.getParent()).getRemote());
288 assertEquals("C:\\", (fp = fp.getParent()).getRemote());
289 assertNull(fp.getParent());
290 }
291
292 private FilePath createFilePath(final File base, final String... path) throws IOException {
293 File building = base;
294 for (final String component : path) {
295 building = new File(building, component);
296 }
297 FileUtils.touch(building);
298 return new FilePath(building);
299 }
300
301 public void testList() throws Exception {
302 File baseDir = Util.createTempDir();
303 try {
304 final Set<FilePath> expected = new HashSet<FilePath>();
305 expected.add(createFilePath(baseDir, "top", "sub", "app.log"));
306 expected.add(createFilePath(baseDir, "top", "sub", "trace.log"));
307 expected.add(createFilePath(baseDir, "top", "db", "db.log"));
308 expected.add(createFilePath(baseDir, "top", "db", "trace.log"));
309 final FilePath[] result = new FilePath(baseDir).list("**");
310 assertEquals(expected, new HashSet<FilePath>(Arrays.asList(result)));
311 } finally {
312 Util.deleteRecursive(baseDir);
313 }
314 }
315
316 public void testListWithExcludes() throws Exception {
317 File baseDir = Util.createTempDir();
318 try {
319 final Set<FilePath> expected = new HashSet<FilePath>();
320 expected.add(createFilePath(baseDir, "top", "sub", "app.log"));
321 createFilePath(baseDir, "top", "sub", "trace.log");
322 expected.add(createFilePath(baseDir, "top", "db", "db.log"));
323 createFilePath(baseDir, "top", "db", "trace.log");
324 final FilePath[] result = new FilePath(baseDir).list("**", "**/trace.log");
325 assertEquals(expected, new HashSet<FilePath>(Arrays.asList(result)));
326 } finally {
327 Util.deleteRecursive(baseDir);
328 }
329 }
330
331 public void testListWithDefaultExcludes() throws Exception {
332 File baseDir = Util.createTempDir();
333 try {
334 final Set<FilePath> expected = new HashSet<FilePath>();
335 expected.add(createFilePath(baseDir, "top", "sub", "backup~"));
336 expected.add(createFilePath(baseDir, "top", "CVS", "somefile,v"));
337 expected.add(createFilePath(baseDir, "top", ".git", "config"));
338 // none of the files are included by default (default includes true)
339 assertEquals(0, new FilePath(baseDir).list("**", "").length);
340 final FilePath[] result = new FilePath(baseDir).list("**", "", false);
341 assertEquals(expected, new HashSet<FilePath>(Arrays.asList(result)));
342 } finally {
343 Util.deleteRecursive(baseDir);
344 }
345 }
346
347 @Bug(11073)
348 public void testIsUnix() {
349 FilePath winPath = new FilePath(new LocalChannel(null),
350 " c:\\app\\hudson\\workspace\\3.8-jelly-db\\jdk/jdk1.6.0_21/label/sqlserver/profile/sqlserver\\acceptance-tests\\distribution.zip");
351 assertFalse(winPath.isUnix());
352
353 FilePath base = new FilePath(new LocalChannel(null),
354 "c:\\app\\hudson\\workspace\\3.8-jelly-db");
355 FilePath middle = new FilePath(base, "jdk/jdk1.6.0_21/label/sqlserver/profile/sqlserver");
356 FilePath full = new FilePath(middle, "acceptance-tests\\distribution.zip");
357 assertFalse(full.isUnix());
358
359
360 FilePath unixPath = new FilePath(new LocalChannel(null),
361 "/home/test");
362 assertTrue(unixPath.isUnix());
363 }
364
365 /**
366 * Tests that permissions are kept when using {@link FilePath#copyToWithPermission(FilePath)}.
367 * Also tries to check that a problem with setting the last-modified date on Windows doesn't fail the whole copy
368 * - well at least when running this test on a Windows OS. See JENKINS-11073
369 */
370 public void testCopyToWithPermission() throws IOException, InterruptedException {
371 File tmp = Util.createTempDir();
372 try {
373 File child = new File(tmp,"child");
374 FilePath childP = new FilePath(child);
375 childP.touch(4711);
376
377 Chmod chmodTask = new Chmod();
378 chmodTask.setProject(new Project());
379 chmodTask.setFile(child);
380 chmodTask.setPerm("0400");
381 chmodTask.execute();
382
383 FilePath copy = new FilePath(british,tmp.getPath()).child("copy");
384 childP.copyToWithPermission(copy);
385
386 assertEquals(childP.mode(),copy.mode());
387 if (!Functions.isWindows()) {
388 assertEquals(childP.lastModified(),copy.lastModified());
389 }
390
391 // JENKINS-11073:
392 // Windows seems to have random failures when setting the timestamp on newly generated
393 // files. So test that:
394 for (int i=0; i<100; i++) {
395 copy = new FilePath(british,tmp.getPath()).child("copy"+i);
396 childP.copyToWithPermission(copy);
397 }
398 } finally {
399 Util.deleteRecursive(tmp);
400 }
401 }
402
403 public void testSymlinkInTar() throws Exception {
404 if (Functions.isWindows()) return; // can't test on Windows
405
406 FilePath tmp = new FilePath(Util.createTempDir());
407 try {
408 FilePath in = tmp.child("in");
409 in.mkdirs();
410 in.child("c").touch(0);
411 in.child("b").symlinkTo("c", TaskListener.NULL);
412
413 FilePath tar = tmp.child("test.tar");
414 in.tar(tar.write(), "**/*");
415
416 FilePath dst = in.child("dst");
417 tar.untar(dst, TarCompression.NONE);
418
419 assertEquals("c",dst.child("b").readLink());
420 } finally {
421 tmp.deleteRecursive();
422 }
423 }
424
425 @Bug(13649)
426 public void testMultiSegmentRelativePaths() throws Exception {
427 FilePath winPath = new FilePath(new LocalChannel(null), "c:\\app\\jenkins\\workspace");
428 FilePath nixPath = new FilePath(new LocalChannel(null), "/opt/jenkins/workspace");
429
430 assertEquals("c:\\app\\jenkins\\workspace\\foo\\bar\\manchu", new FilePath(winPath, "foo/bar/manchu").getRemote());
431 assertEquals("c:\\app\\jenkins\\workspace\\foo\\bar\\manchu", new FilePath(winPath, "foo\\bar/manchu").getRemote());
432 assertEquals("c:\\app\\jenkins\\workspace\\foo\\bar\\manchu", new FilePath(winPath, "foo\\bar\\manchu").getRemote());
433 assertEquals("/opt/jenkins/workspace/foo/bar/manchu", new FilePath(nixPath, "foo\\bar\\manchu").getRemote());
434 assertEquals("/opt/jenkins/workspace/foo/bar/manchu", new FilePath(nixPath, "foo/bar\\manchu").getRemote());
435 assertEquals("/opt/jenkins/workspace/foo/bar/manchu", new FilePath(nixPath, "foo/bar/manchu").getRemote());
436 }
437
438 public void testValidateAntFileMask() throws Exception {
439 File tmp = Util.createTempDir();
440 try {
441 FilePath d = new FilePath(french, tmp.getPath());
442 d.child("d1/d2/d3").mkdirs();
443 d.child("d1/d2/d3/f.txt").touch(0);
444 d.child("d1/d2/d3/f.html").touch(0);
445 d.child("d1/d2/f.txt").touch(0);
446 assertValidateAntFileMask(null, d, "**/*.txt");
447 assertValidateAntFileMask(null, d, "d1/d2/d3/f.txt");
448 assertValidateAntFileMask(null, d, "**/*.html");
449 assertValidateAntFileMask(Messages.FilePath_validateAntFileMask_portionMatchButPreviousNotMatchAndSuggest("**/*.js", "**", "**/*.js"), d, "**/*.js");
450 assertValidateAntFileMask(Messages.FilePath_validateAntFileMask_doesntMatchAnything("index.htm"), d, "index.htm");
451 assertValidateAntFileMask(Messages.FilePath_validateAntFileMask_doesntMatchAndSuggest("f.html", "d1/d2/d3/f.html"), d, "f.html");
452 // XXX lots more to test, e.g. multiple patterns separated by commas; ought to have full code coverage for this method
453 } finally {
454 Util.deleteRecursive(tmp);
455 }
456 }
457
458 private static void assertValidateAntFileMask(String expected, FilePath d, String fileMasks) throws Exception {
459 assertEquals(expected, d.validateAntFileMask(fileMasks));
460 }
461
462 @Bug(7214)
463 public void testValidateAntFileMaskBounded() throws Exception {
464 File tmp = Util.createTempDir();
465 try {
466 FilePath d = new FilePath(french, tmp.getPath());
467 FilePath d2 = d.child("d1/d2");
468 d2.mkdirs();
469 for (int i = 0; i < 100; i++) {
470 FilePath d3 = d2.child("d" + i);
471 d3.mkdirs();
472 d3.child("f.txt").touch(0);
473 }
474 assertEquals(null, d.validateAntFileMask("d1/d2/**/f.txt"));
475 assertEquals(null, d.validateAntFileMask("d1/d2/**/f.txt", 10));
476 assertEquals(Messages.FilePath_validateAntFileMask_portionMatchButPreviousNotMatchAndSuggest("**/*.js", "**", "**/*.js"), d.validateAntFileMask("**/*.js", 1000));
477 try {
478 d.validateAntFileMask("**/*.js", 10);
479 fail();
480 } catch (InterruptedException x) {
481 // good
482 }
483 } finally {
484 Util.deleteRecursive(tmp);
485 }
486 }
487
488 @Bug(15418)
489 public void testDeleteLongPathOnWindows() throws Exception {
490 File tmp = Util.createTempDir();
491 try {
492 FilePath d = new FilePath(french, tmp.getPath());
493
494 // construct a very long path
495 StringBuilder sb = new StringBuilder();
496 while(sb.length() + tmp.getPath().length() < 260 - "very/".length()) {
497 sb.append("very/");
498 }
499 sb.append("pivot/very/very/long/path");
500
501 FilePath longPath = d.child(sb.toString());
502 longPath.mkdirs();
503 FilePath childInLongPath = longPath.child("file.txt");
504 childInLongPath.touch(0);
505
506 File firstDirectory = new File(tmp.getAbsolutePath() + "/very");
507 Util.deleteRecursive(firstDirectory);
508
509 assertFalse("Could not delete directory!", firstDirectory.exists());
510
511 } finally {
512 Util.deleteRecursive(tmp);
513 }
514 }
515
516 @Bug(16215)
517 public void testInstallIfNecessaryAvoidsExcessiveDownloadsByUsingIfModifiedSince() throws Exception {
518 final File tmp = Util.createTempDir();
519 try {
520 final FilePath d = new FilePath(tmp);
521
522 d.child(".timestamp").touch(123000);
523
524 final HttpURLConnection con = mock(HttpURLConnection.class);
525 final URL url = someUrlToZipFile(con);
526
527 when(con.getResponseCode())
528 .thenReturn(HttpURLConnection.HTTP_NOT_MODIFIED);
529
530 assertFalse(d.installIfNecessaryFrom(url, null, null));
531
532 verify(con).setIfModifiedSince(123000);
533 } finally {
534 Util.deleteRecursive(tmp);
535 }
536 }
537
538 @Bug(16215)
539 public void testInstallIfNecessaryPerformsInstallation() throws Exception {
540 final File tmp = Util.createTempDir();
541 try {
542 final FilePath d = new FilePath(tmp);
543
544 final HttpURLConnection con = mock(HttpURLConnection.class);
545 final URL url = someUrlToZipFile(con);
546
547 when(con.getResponseCode())
548 .thenReturn(HttpURLConnection.HTTP_OK);
549
550 when(con.getInputStream())
551 .thenReturn(someZippedContent());
552
553 assertTrue(d.installIfNecessaryFrom(url, null, null));
554 } finally {
555 Util.deleteRecursive(tmp);
556 }
557 }
558
559 private URL someUrlToZipFile(final URLConnection con) throws IOException {
560
561 final URLStreamHandler urlHandler = new URLStreamHandler() {
562 @Override protected URLConnection openConnection(URL u) throws IOException {
563 return con;
564 }
565 };
566
567 return new URL("http", "some-host", 0, "/some-path.zip", urlHandler);
568 }
569
570 private InputStream someZippedContent() throws IOException {
571 final ByteArrayOutputStream buf = new ByteArrayOutputStream();
572 final ZipOutputStream zip = new ZipOutputStream(buf);
573
574 zip.putNextEntry(new ZipEntry("abc"));
575 zip.write("abc".getBytes());
576 zip.close();
577
578 return new ByteArrayInputStream(buf.toByteArray());
579 }
580 }
581