001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.taskdefs.optional.net;
019:
020: import java.io.File;
021: import java.io.IOException;
022: import java.util.Arrays;
023: import java.util.HashMap;
024: import java.util.Map;
025: import java.util.Random;
026: import java.util.Vector;
027:
028: import org.apache.commons.net.ftp.FTPClient;
029: import org.apache.tools.ant.BuildEvent;
030: import org.apache.tools.ant.BuildException;
031: import org.apache.tools.ant.BuildFileTest;
032: import org.apache.tools.ant.DefaultLogger;
033: import org.apache.tools.ant.DirectoryScanner;
034: import org.apache.tools.ant.taskdefs.condition.Os;
035: import org.apache.tools.ant.types.FileSet;
036: import org.apache.tools.ant.util.RetryHandler;
037: import org.apache.tools.ant.util.Retryable;
038: import org.apache.tools.ant.util.regexp.RegexpMatcher;
039: import org.apache.tools.ant.util.regexp.RegexpMatcherFactory;
040:
041: public class FTPTest extends BuildFileTest {
042: // keep track of what operating systems are supported here.
043: private boolean supportsSymlinks = Os.isFamily("unix");
044:
045: private FTPClient ftp;
046: private boolean connectionSucceeded = true;
047: private boolean loginSuceeded = true;
048: private String tmpDir = null;
049: private String remoteTmpDir = null;
050: private String ftpFileSep = null;
051: private myFTP myFTPTask = new myFTP();
052:
053: public FTPTest(String name) {
054: super (name);
055: }
056:
057: public void setUp() {
058: configureProject("src/etc/testcases/taskdefs/optional/net/ftp.xml");
059: getProject().executeTarget("setup");
060: tmpDir = getProject().getProperty("tmp.dir");
061: ftp = new FTPClient();
062: ftpFileSep = getProject().getProperty("ftp.filesep");
063: myFTPTask.setSeparator(ftpFileSep);
064: myFTPTask.setProject(getProject());
065: remoteTmpDir = myFTPTask.resolveFile(tmpDir);
066: String remoteHost = getProject().getProperty("ftp.host");
067: int port = Integer.parseInt(getProject()
068: .getProperty("ftp.port"));
069: String remoteUser = getProject().getProperty("ftp.user");
070: String password = getProject().getProperty("ftp.password");
071: try {
072: ftp.connect(remoteHost, port);
073: } catch (Exception ex) {
074: connectionSucceeded = false;
075: loginSuceeded = false;
076: System.out.println("could not connect to host "
077: + remoteHost + " on port " + port);
078: }
079: if (connectionSucceeded) {
080: try {
081: ftp.login(remoteUser, password);
082: } catch (IOException ioe) {
083: loginSuceeded = false;
084: System.out.println("could not log on to " + remoteHost
085: + " as user " + remoteUser);
086: }
087: }
088: }
089:
090: public void tearDown() {
091: try {
092: ftp.disconnect();
093: } catch (IOException ioe) {
094: // do nothing
095: }
096: getProject().executeTarget("cleanup");
097: }
098:
099: private boolean changeRemoteDir(String remoteDir) {
100: boolean result = true;
101: try {
102: ftp.cwd(remoteDir);
103: } catch (Exception ex) {
104: System.out.println("could not change directory to "
105: + remoteTmpDir);
106: result = false;
107: }
108: return result;
109: }
110:
111: public void test1() {
112: if (loginSuceeded) {
113: if (changeRemoteDir(remoteTmpDir)) {
114: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
115: ds
116: .setBasedir(new File(getProject().getBaseDir(),
117: "tmp"));
118: ds.setIncludes(new String[] { "alpha" });
119: ds.scan();
120: compareFiles(ds, new String[] {},
121: new String[] { "alpha" });
122: }
123: }
124: }
125:
126: public void test2() {
127: if (loginSuceeded) {
128: if (changeRemoteDir(remoteTmpDir)) {
129: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
130: ds
131: .setBasedir(new File(getProject().getBaseDir(),
132: "tmp"));
133: ds.setIncludes(new String[] { "alpha/" });
134: ds.scan();
135: compareFiles(ds, new String[] { "alpha/beta/beta.xml",
136: "alpha/beta/gamma/gamma.xml" }, new String[] {
137: "alpha", "alpha/beta", "alpha/beta/gamma" });
138: }
139: }
140: }
141:
142: public void test3() {
143: if (loginSuceeded) {
144: if (changeRemoteDir(remoteTmpDir)) {
145: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
146: ds
147: .setBasedir(new File(getProject().getBaseDir(),
148: "tmp"));
149: ds.scan();
150: compareFiles(ds, new String[] { "alpha/beta/beta.xml",
151: "alpha/beta/gamma/gamma.xml" }, new String[] {
152: "alpha", "alpha/beta", "alpha/beta/gamma" });
153: }
154: }
155: }
156:
157: public void testFullPathMatchesCaseSensitive() {
158: if (loginSuceeded) {
159: if (changeRemoteDir(remoteTmpDir)) {
160: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
161: ds
162: .setBasedir(new File(getProject().getBaseDir(),
163: "tmp"));
164: ds
165: .setIncludes(new String[] { "alpha/beta/gamma/GAMMA.XML" });
166: ds.scan();
167: compareFiles(ds, new String[] {}, new String[] {});
168: }
169: }
170: }
171:
172: public void testFullPathMatchesCaseInsensitive() {
173: if (loginSuceeded) {
174: if (changeRemoteDir(remoteTmpDir)) {
175: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
176: ds.setCaseSensitive(false);
177: ds
178: .setBasedir(new File(getProject().getBaseDir(),
179: "tmp"));
180: ds
181: .setIncludes(new String[] { "alpha/beta/gamma/GAMMA.XML" });
182: ds.scan();
183: compareFiles(ds,
184: new String[] { "alpha/beta/gamma/gamma.xml" },
185: new String[] {});
186: }
187: }
188: }
189:
190: public void test2ButCaseInsensitive() {
191: if (loginSuceeded) {
192: if (changeRemoteDir(remoteTmpDir)) {
193: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
194: ds
195: .setBasedir(new File(getProject().getBaseDir(),
196: "tmp"));
197: ds.setIncludes(new String[] { "ALPHA/" });
198: ds.setCaseSensitive(false);
199: ds.scan();
200: compareFiles(ds, new String[] { "alpha/beta/beta.xml",
201: "alpha/beta/gamma/gamma.xml" }, new String[] {
202: "alpha", "alpha/beta", "alpha/beta/gamma" });
203: }
204: }
205: }
206:
207: public void test2bisButCaseInsensitive() {
208: if (loginSuceeded) {
209: if (changeRemoteDir(remoteTmpDir)) {
210: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
211: ds
212: .setBasedir(new File(getProject().getBaseDir(),
213: "tmp"));
214: ds.setIncludes(new String[] { "alpha/BETA/gamma/" });
215: ds.setCaseSensitive(false);
216: ds.scan();
217: compareFiles(ds,
218: new String[] { "alpha/beta/gamma/gamma.xml" },
219: new String[] { "alpha/beta/gamma" });
220: }
221: }
222: }
223:
224: public void testGetWithSelector() {
225: expectLogContaining("ftp-get-with-selector",
226: "selectors are not supported in remote filesets");
227: FileSet fsDestination = (FileSet) getProject().getReference(
228: "fileset-destination-without-selector");
229: DirectoryScanner dsDestination = fsDestination
230: .getDirectoryScanner(getProject());
231: dsDestination.scan();
232: String[] sortedDestinationDirectories = dsDestination
233: .getIncludedDirectories();
234: String[] sortedDestinationFiles = dsDestination
235: .getIncludedFiles();
236: for (int counter = 0; counter < sortedDestinationDirectories.length; counter++) {
237: sortedDestinationDirectories[counter] = sortedDestinationDirectories[counter]
238: .replace(File.separatorChar, '/');
239: }
240: for (int counter = 0; counter < sortedDestinationFiles.length; counter++) {
241: sortedDestinationFiles[counter] = sortedDestinationFiles[counter]
242: .replace(File.separatorChar, '/');
243: }
244: FileSet fsSource = (FileSet) getProject().getReference(
245: "fileset-source-without-selector");
246: DirectoryScanner dsSource = fsSource
247: .getDirectoryScanner(getProject());
248: dsSource.scan();
249: compareFiles(dsSource, sortedDestinationFiles,
250: sortedDestinationDirectories);
251: }
252:
253: public void testGetFollowSymlinksTrue() {
254: if (!supportsSymlinks) {
255: return;
256: }
257: if (!loginSuceeded) {
258: return;
259: }
260: if (!changeRemoteDir(remoteTmpDir)) {
261: return;
262: }
263: getProject().executeTarget("ftp-get-directory-symbolic-link");
264: FileSet fsDestination = (FileSet) getProject().getReference(
265: "fileset-destination-without-selector");
266: DirectoryScanner dsDestination = fsDestination
267: .getDirectoryScanner(getProject());
268: dsDestination.scan();
269: compareFiles(dsDestination,
270: new String[] { "alpha/beta/gamma/gamma.xml" },
271: new String[] { "alpha", "alpha/beta",
272: "alpha/beta/gamma" });
273: }
274:
275: public void testGetFollowSymlinksFalse() {
276: if (!supportsSymlinks) {
277: return;
278: }
279: if (!loginSuceeded) {
280: return;
281: }
282: if (!changeRemoteDir(remoteTmpDir)) {
283: return;
284: }
285: getProject()
286: .executeTarget("ftp-get-directory-no-symbolic-link");
287: FileSet fsDestination = (FileSet) getProject().getReference(
288: "fileset-destination-without-selector");
289: DirectoryScanner dsDestination = fsDestination
290: .getDirectoryScanner(getProject());
291: dsDestination.scan();
292: compareFiles(dsDestination, new String[] {}, new String[] {});
293: }
294:
295: public void testAllowSymlinks() {
296: if (!supportsSymlinks) {
297: return;
298: }
299: if (!loginSuceeded) {
300: return;
301: }
302: if (!changeRemoteDir(remoteTmpDir)) {
303: return;
304: }
305: getProject().executeTarget("symlink-setup");
306: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
307: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
308: ds.setIncludes(new String[] { "alpha/beta/gamma/" });
309: ds.setFollowSymlinks(true);
310: ds.scan();
311: compareFiles(ds, new String[] { "alpha/beta/gamma/gamma.xml" },
312: new String[] { "alpha/beta/gamma" });
313: }
314:
315: public void testProhibitSymlinks() {
316: if (!supportsSymlinks) {
317: return;
318: }
319: if (!loginSuceeded) {
320: return;
321: }
322: if (!changeRemoteDir(remoteTmpDir)) {
323: return;
324: }
325: getProject().executeTarget("symlink-setup");
326: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
327: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
328: ds.setIncludes(new String[] { "alpha/beta/gamma/" });
329: ds.setFollowSymlinks(false);
330: ds.scan();
331: compareFiles(ds, new String[] {}, new String[] {});
332: }
333:
334: public void testFileSymlink() {
335: if (!supportsSymlinks) {
336: return;
337: }
338: if (!loginSuceeded) {
339: return;
340: }
341: if (!changeRemoteDir(remoteTmpDir)) {
342: return;
343: }
344: getProject().executeTarget("symlink-file-setup");
345: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
346: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
347: ds.setIncludes(new String[] { "alpha/beta/gamma/" });
348: ds.setFollowSymlinks(true);
349: ds.scan();
350: compareFiles(ds, new String[] { "alpha/beta/gamma/gamma.xml" },
351: new String[] { "alpha/beta/gamma" });
352: }
353:
354: // father and child pattern test
355: public void testOrderOfIncludePatternsIrrelevant() {
356: if (!loginSuceeded) {
357: return;
358: }
359: if (!changeRemoteDir(remoteTmpDir)) {
360: return;
361: }
362: String[] expectedFiles = { "alpha/beta/beta.xml",
363: "alpha/beta/gamma/gamma.xml" };
364: String[] expectedDirectories = { "alpha/beta",
365: "alpha/beta/gamma" };
366: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
367: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
368: ds.setIncludes(new String[] { "alpha/be?a/**",
369: "alpha/beta/gamma/" });
370: ds.scan();
371: compareFiles(ds, expectedFiles, expectedDirectories);
372: // redo the test, but the 2 include patterns are inverted
373: ds = myFTPTask.newScanner(ftp);
374: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
375: ds.setIncludes(new String[] { "alpha/beta/gamma/",
376: "alpha/be?a/**" });
377: ds.scan();
378: compareFiles(ds, expectedFiles, expectedDirectories);
379: }
380:
381: public void testPatternsDifferInCaseScanningSensitive() {
382: if (!loginSuceeded) {
383: return;
384: }
385: if (!changeRemoteDir(remoteTmpDir)) {
386: return;
387: }
388: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
389: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
390: ds.setIncludes(new String[] { "alpha/", "ALPHA/" });
391: ds.scan();
392: compareFiles(ds, new String[] { "alpha/beta/beta.xml",
393: "alpha/beta/gamma/gamma.xml" }, new String[] { "alpha",
394: "alpha/beta", "alpha/beta/gamma" });
395: }
396:
397: public void testPatternsDifferInCaseScanningInsensitive() {
398: if (!loginSuceeded) {
399: return;
400: }
401: if (!changeRemoteDir(remoteTmpDir)) {
402: return;
403: }
404: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
405: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
406: ds.setIncludes(new String[] { "alpha/", "ALPHA/" });
407: ds.setCaseSensitive(false);
408: ds.scan();
409: compareFiles(ds, new String[] { "alpha/beta/beta.xml",
410: "alpha/beta/gamma/gamma.xml" }, new String[] { "alpha",
411: "alpha/beta", "alpha/beta/gamma" });
412: }
413:
414: public void testFullpathDiffersInCaseScanningSensitive() {
415: if (!loginSuceeded) {
416: return;
417: }
418: if (!changeRemoteDir(remoteTmpDir)) {
419: return;
420: }
421: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
422: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
423: ds.setIncludes(new String[] { "alpha/beta/gamma/gamma.xml",
424: "alpha/beta/gamma/GAMMA.XML" });
425: ds.scan();
426: compareFiles(ds, new String[] { "alpha/beta/gamma/gamma.xml" },
427: new String[] {});
428: }
429:
430: public void testFullpathDiffersInCaseScanningInsensitive() {
431: if (!loginSuceeded) {
432: return;
433: }
434: if (!changeRemoteDir(remoteTmpDir)) {
435: return;
436: }
437: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
438: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
439: ds.setIncludes(new String[] { "alpha/beta/gamma/gamma.xml",
440: "alpha/beta/gamma/GAMMA.XML" });
441: ds.setCaseSensitive(false);
442: ds.scan();
443: compareFiles(ds, new String[] { "alpha/beta/gamma/gamma.xml" },
444: new String[] {});
445: }
446:
447: public void testParentDiffersInCaseScanningSensitive() {
448: if (!loginSuceeded) {
449: return;
450: }
451: if (!changeRemoteDir(remoteTmpDir)) {
452: return;
453: }
454: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
455: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
456: ds.setIncludes(new String[] { "alpha/", "ALPHA/beta/" });
457: ds.scan();
458: compareFiles(ds, new String[] { "alpha/beta/beta.xml",
459: "alpha/beta/gamma/gamma.xml" }, new String[] { "alpha",
460: "alpha/beta", "alpha/beta/gamma" });
461: }
462:
463: public void testParentDiffersInCaseScanningInsensitive() {
464: if (!loginSuceeded) {
465: return;
466: }
467: if (!changeRemoteDir(remoteTmpDir)) {
468: return;
469: }
470: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
471: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
472: ds.setIncludes(new String[] { "alpha/", "ALPHA/beta/" });
473: ds.setCaseSensitive(false);
474: ds.scan();
475: compareFiles(ds, new String[] { "alpha/beta/beta.xml",
476: "alpha/beta/gamma/gamma.xml" }, new String[] { "alpha",
477: "alpha/beta", "alpha/beta/gamma" });
478: }
479:
480: public void testExcludeOneFile() {
481: if (!loginSuceeded) {
482: return;
483: }
484: if (!changeRemoteDir(remoteTmpDir)) {
485: return;
486: }
487: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
488: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
489: ds.setIncludes(new String[] { "**/*.xml" });
490: ds.setExcludes(new String[] { "alpha/beta/b*xml" });
491: ds.scan();
492: compareFiles(ds, new String[] { "alpha/beta/gamma/gamma.xml" },
493: new String[] {});
494: }
495:
496: public void testExcludeHasPrecedence() {
497: if (!loginSuceeded) {
498: return;
499: }
500: if (!changeRemoteDir(remoteTmpDir)) {
501: return;
502: }
503: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
504: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
505: ds.setIncludes(new String[] { "alpha/**" });
506: ds.setExcludes(new String[] { "alpha/**" });
507: ds.scan();
508: compareFiles(ds, new String[] {}, new String[] {});
509:
510: }
511:
512: public void testAlternateIncludeExclude() {
513: if (!loginSuceeded) {
514: return;
515: }
516: if (!changeRemoteDir(remoteTmpDir)) {
517: return;
518: }
519: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
520: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
521: ds
522: .setIncludes(new String[] { "alpha/**",
523: "alpha/beta/gamma/**" });
524: ds.setExcludes(new String[] { "alpha/beta/**" });
525: ds.scan();
526: compareFiles(ds, new String[] {}, new String[] { "alpha" });
527:
528: }
529:
530: public void testAlternateExcludeInclude() {
531: if (!loginSuceeded) {
532: return;
533: }
534: if (!changeRemoteDir(remoteTmpDir)) {
535: return;
536: }
537: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
538: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
539: ds
540: .setExcludes(new String[] { "alpha/**",
541: "alpha/beta/gamma/**" });
542: ds.setIncludes(new String[] { "alpha/beta/**" });
543: ds.scan();
544: compareFiles(ds, new String[] {}, new String[] {});
545:
546: }
547:
548: /**
549: * Test inspired by Bug#1415.
550: */
551: public void testChildrenOfExcludedDirectory() {
552: if (!loginSuceeded) {
553: return;
554: }
555: if (!changeRemoteDir(remoteTmpDir)) {
556: return;
557: }
558: getProject().executeTarget("children-of-excluded-dir-setup");
559: FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
560: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
561: ds.setExcludes(new String[] { "alpha/**" });
562: ds.scan();
563: compareFiles(ds, new String[] { "delta/delta.xml" },
564: new String[] { "delta" });
565:
566: ds = myFTPTask.newScanner(ftp);
567: if (!changeRemoteDir(remoteTmpDir)) {
568: return;
569: }
570: ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
571: ds.setExcludes(new String[] { "alpha" });
572: ds.scan();
573: compareFiles(ds, new String[] { "alpha/beta/beta.xml",
574: "alpha/beta/gamma/gamma.xml", "delta/delta.xml" },
575: new String[] { "alpha/beta", "alpha/beta/gamma",
576: "delta" });
577:
578: }
579:
580: /**
581: * This class enables the use of the log messages as a way of testing
582: * the number of files actually transferred.
583: * It uses the ant regular expression mechanism to get a regex parser
584: * to parse the log output.
585: */
586: private class CountLogListener extends DefaultLogger {
587: private Vector lastMatchGroups = null;
588: private RegexpMatcher matcher = new RegexpMatcherFactory()
589: .newRegexpMatcher();
590:
591: /**
592: * The only constructor for a CountLogListener
593: * @param pattern a regular expression pattern. It should have
594: * one parenthesized group and that group should contain the
595: * number desired.
596: */
597: public CountLogListener(String pattern) {
598: super ();
599: this .matcher.setPattern(pattern);
600: }
601:
602: /*
603: * @param event the build event that is being logged.
604: */
605: public void messageLogged(BuildEvent event) {
606: String message = event.getMessage();
607: if (this .matcher.matches(message)) {
608: lastMatchGroups = this .matcher.getGroups(message);
609: }
610: super .messageLogged(event);
611: }
612:
613: /**
614: * returns the desired number that results from parsing the log
615: * message
616: * @return the number of files indicated in the desired message or -1
617: * if a matching log message was never found.
618: */
619: public int getCount() {
620: if (this .lastMatchGroups == null) {
621: return -1;
622: }
623: return Integer.parseInt((String) this .lastMatchGroups
624: .get(1));
625: }
626: }
627:
628: /**
629: * This class enables the use of the log to count the number
630: * of times a message has been emitted.
631: */
632: private class LogCounter extends DefaultLogger {
633: private Map searchMap = new HashMap();
634: private int matchCount;
635:
636: public void addLogMessageToSearch(String message) {
637: searchMap.put(message, new Integer(0));
638: }
639:
640: /*
641: * @param event the build event that is being logged.
642: */
643: public void messageLogged(BuildEvent event) {
644: String message = event.getMessage();
645: Integer mcnt = (Integer) searchMap.get(message);
646: if (null != mcnt) {
647: searchMap
648: .put(message, new Integer(mcnt.intValue() + 1));
649: }
650: super .messageLogged(event);
651: }
652:
653: /**
654: * @return the number of times that the looked for message was sent
655: * to the log
656: */
657: public int getMatchCount(String message) {
658: Integer mcnt = (Integer) searchMap.get(message);
659: if (null != mcnt) {
660: return mcnt.intValue();
661: }
662: return 0;
663: }
664: }
665:
666: /**
667: * Tests the combination of the newer parameter and the
668: * serverTimezoneConfig parameter in the PUT action. The default
669: * configuration is an ftp server on localhost which formats
670: * timestamps as GMT.
671: */
672: public void testTimezonePut() {
673: CountLogListener log = new CountLogListener(
674: "(\\d+) files? sent");
675: getProject().executeTarget("timed.test.setup");
676: getProject().addBuildListener(log);
677: getProject().executeTarget("timed.test.put.older");
678: assertEquals(1, log.getCount());
679: }
680:
681: /**
682: * Tests the combination of the newer parameter and the
683: * serverTimezoneConfig parameter in the GET action. The default
684: * configuration is an ftp server on localhost which formats
685: * timestamps as GMT.
686: */
687: public void testTimezoneGet() {
688: CountLogListener log = new CountLogListener(
689: "(\\d+) files? retrieved");
690: getProject().executeTarget("timed.test.setup");
691: getProject().addBuildListener(log);
692: getProject().executeTarget("timed.test.get.older");
693: assertEquals(3, log.getCount());
694: }
695:
696: /**
697: * Tests that the presence of one of the server config params forces
698: * the system type to Unix if not specified.
699: */
700: public void testConfiguration1() {
701: int[] expectedCounts = { 1, 1, 0, 1, 0, 0, 0 };
702: performConfigTest("configuration.1", expectedCounts);
703:
704: }
705:
706: /**
707: * Tests the systemTypeKey attribute.
708: */
709: public void testConfiguration2() {
710: int[] expectedCounts = { 1, 0, 0, 1, 1, 0, 0 };
711: performConfigTest("configuration.2", expectedCounts);
712:
713: }
714:
715: /**
716: * Tests the systemTypeKey attribute with UNIX specified.
717: */
718: public void testConfiguration3() {
719: int[] expectedCounts = { 1, 0, 1, 0, 0, 1, 0 };
720: performConfigTest("configuration.3", expectedCounts);
721:
722: }
723:
724: public void testConfigurationLang() {
725: int[] expectedCounts = { 1, 1, 0, 0, 0, 0, 1 };
726: performConfigTest("configuration.lang.good", expectedCounts);
727:
728: try {
729: performConfigTest("configuration.lang.bad", expectedCounts);
730: fail("BuildException Expected");
731: } catch (Exception bx) {
732: assertTrue(bx instanceof BuildException);
733: }
734: }
735:
736: /**
737: * Tests the systemTypeKey attribute.
738: */
739: public void testConfigurationNone() {
740: int[] expectedCounts = { 0, 0, 0, 0, 0, 0, 0 };
741: performConfigTest("configuration.none", expectedCounts);
742:
743: }
744:
745: private void performConfigTest(String target, int[] expectedCounts) {
746: String[] messages = new String[] {
747: "custom configuration",
748: "custom config: system key = default (UNIX)",
749: "custom config: system key = UNIX",
750: "custom config: server time zone ID = "
751: + getProject().getProperty(
752: "ftp.server.timezone"),
753: "custom config: system key = WINDOWS",
754: "custom config: default date format = yyyy/MM/dd HH:mm",
755: "custom config: server language code = de"
756:
757: };
758: LogCounter counter = new LogCounter();
759: for (int i = 0; i < messages.length; i++) {
760: counter.addLogMessageToSearch(messages[i]);
761: }
762:
763: getProject().addBuildListener(counter);
764: getProject().executeTarget(target);
765: for (int i = 0; i < messages.length; i++) {
766: assertEquals("target " + target + ":message " + i,
767: expectedCounts[i], counter
768: .getMatchCount(messages[i]));
769: }
770:
771: }
772:
773: /**
774: * this test is inspired by a user reporting that deletions of directories with the ftp task do not work
775: */
776: public void testFTPDelete() {
777: getProject().executeTarget("ftp-delete");
778: }
779:
780: private void compareFiles(DirectoryScanner ds,
781: String[] expectedFiles, String[] expectedDirectories) {
782: String includedFiles[] = ds.getIncludedFiles();
783: String includedDirectories[] = ds.getIncludedDirectories();
784: assertEquals("file present: ", expectedFiles.length,
785: includedFiles.length);
786: assertEquals("directories present: ",
787: expectedDirectories.length, includedDirectories.length);
788:
789: for (int counter = 0; counter < includedFiles.length; counter++) {
790: includedFiles[counter] = includedFiles[counter].replace(
791: File.separatorChar, '/');
792: }
793: Arrays.sort(includedFiles);
794: for (int counter = 0; counter < includedDirectories.length; counter++) {
795: includedDirectories[counter] = includedDirectories[counter]
796: .replace(File.separatorChar, '/');
797: }
798: Arrays.sort(includedDirectories);
799: for (int counter = 0; counter < includedFiles.length; counter++) {
800: assertEquals(expectedFiles[counter], includedFiles[counter]);
801: }
802: for (int counter = 0; counter < includedDirectories.length; counter++) {
803: assertEquals(expectedDirectories[counter],
804: includedDirectories[counter]);
805: counter++;
806: }
807: }
808:
809: private static class myFTP extends FTP {
810: public FTP.FTPDirectoryScanner newScanner(FTPClient client) {
811: return new FTP.FTPDirectoryScanner(client);
812: }
813:
814: // provide public visibility
815: public String resolveFile(String file) {
816: return super .resolveFile(file);
817: }
818: }
819:
820: public abstract static class myRetryableFTP extends FTP {
821: private final int numberOfFailuresToSimulate;
822: private int simulatedFailuresLeft;
823:
824: protected myRetryableFTP(int numberOfFailuresToSimulate) {
825: this .numberOfFailuresToSimulate = numberOfFailuresToSimulate;
826: this .simulatedFailuresLeft = numberOfFailuresToSimulate;
827: }
828:
829: protected void getFile(FTPClient ftp, String dir,
830: String filename) throws IOException, BuildException {
831: if (this .simulatedFailuresLeft > 0) {
832: this .simulatedFailuresLeft--;
833: throw new IOException("Simulated failure for testing");
834: }
835: super .getFile(ftp, dir, filename);
836: }
837:
838: protected void executeRetryable(RetryHandler h, Retryable r,
839: String filename) throws IOException {
840: this .simulatedFailuresLeft = this .numberOfFailuresToSimulate;
841: super .executeRetryable(h, r, filename);
842: }
843: }
844:
845: public static class oneFailureFTP extends myRetryableFTP {
846: public oneFailureFTP() {
847: super (1);
848: }
849: }
850:
851: public static class twoFailureFTP extends myRetryableFTP {
852: public twoFailureFTP() {
853: super (2);
854: }
855: }
856:
857: public static class threeFailureFTP extends myRetryableFTP {
858: public threeFailureFTP() {
859: super (3);
860: }
861: }
862:
863: public static class randomFailureFTP extends myRetryableFTP {
864: public randomFailureFTP() {
865: super (new Random().nextInt(Short.MAX_VALUE));
866: }
867: }
868:
869: public void testGetWithSelectorRetryable1() {
870: getProject().addTaskDefinition("ftp", oneFailureFTP.class);
871: try {
872: getProject().executeTarget(
873: "ftp-get-with-selector-retryable");
874: } catch (BuildException bx) {
875: fail("Two retries expected, failed after one.");
876: }
877: }
878:
879: public void testGetWithSelectorRetryable2() {
880: getProject().addTaskDefinition("ftp", twoFailureFTP.class);
881: try {
882: getProject().executeTarget(
883: "ftp-get-with-selector-retryable");
884: } catch (BuildException bx) {
885: fail("Two retries expected, failed after two.");
886: }
887: }
888:
889: public void testGetWithSelectorRetryable3() {
890: getProject().addTaskDefinition("ftp", threeFailureFTP.class);
891: try {
892: getProject().executeTarget(
893: "ftp-get-with-selector-retryable");
894: fail("Two retries expected, continued after two.");
895: } catch (BuildException bx) {
896: }
897: }
898:
899: public void testGetWithSelectorRetryableRandom() {
900: getProject().addTaskDefinition("ftp", randomFailureFTP.class);
901: try {
902: getProject().setProperty("ftp.retries", "forever");
903: getProject().executeTarget(
904: "ftp-get-with-selector-retryable");
905: } catch (BuildException bx) {
906: fail("Retry forever specified, but failed.");
907: }
908: }
909:
910: public void testInitialCommand() {
911: performCommandTest("test-initial-command", new int[] { 1, 0 });
912: }
913:
914: public void testSiteAction() {
915: performCommandTest("test-site-action", new int[] { 1, 0 });
916: }
917:
918: private void performCommandTest(String target, int[] expectedCounts) {
919: String[] messages = new String[] {
920: "Doing Site Command: umask 222",
921: "Failed to issue Site Command: umask 222",
922:
923: };
924: LogCounter counter = new LogCounter();
925: for (int i = 0; i < messages.length; i++) {
926: counter.addLogMessageToSearch(messages[i]);
927: }
928:
929: getProject().addBuildListener(counter);
930: getProject().executeTarget(target);
931: for (int i = 0; i < messages.length; i++) {
932: assertEquals("target " + target + ":message " + i,
933: expectedCounts[i], counter
934: .getMatchCount(messages[i]));
935: }
936:
937: }
938:
939: }
|