View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.net.ftp;
18  
19  import java.io.IOException;
20  import java.time.Duration;
21  import java.time.Instant;
22  import java.util.Calendar;
23  import java.util.TreeSet;
24  
25  import junit.framework.TestCase;
26  
27  /**
28   * This test was contributed in a different form by W. McDonald Buck of Boulder, Colorado, to help fix some bugs with the FTPClientConfig in a real world
29   * setting. It is a perfect functional test for the Time Zone functionality of FTPClientConfig.
30   *
31   * A publicly accessible FTP server at the US National Oceanographic and Atmospheric Adminstration houses a directory which contains 300 files, named sn.0000 to
32   * sn.0300. Every ten minutes or so the next file in sequence is rewritten with new data. Thus, the directory contains observations for more than 24 hours of
33   * data. Since the server has its clock set to GMT this is an excellent functional test for any machine in a different time zone.
34   *
35   * Noteworthy is the fact that the FTP routines in some web browsers don't work as well as this. They can't, since they have no way of knowing the server's time
36   * zone. Depending on the local machine's position relative to GMT and the time of day, the browsers may decide that a timestamp would be in the future if given
37   * the current year, so they assume the year to be last year. This illustrates the value of FTPClientConfig's time zone functionality.
38   */
39  public class FTPClientConfigFunctionalTest extends TestCase {
40  
41      private final FTPClient ftpClient = new FTPClient();
42      private FTPClientConfig ftpClientConfig;
43  
44      /**
45       */
46      public FTPClientConfigFunctionalTest() {
47  
48      }
49  
50      public FTPClientConfigFunctionalTest(final String arg0) {
51          super(arg0);
52      }
53  
54      private TreeSet<FTPFile> getSortedSet(final FTPFile[] files) {
55          // create a TreeSet which will sort each element
56          // as it is added.
57          final TreeSet<FTPFile> sorted = new TreeSet<>((o1, o2) -> o1.getTimestamp().getTime().compareTo(o2.getTimestamp().getTime()));
58  
59          for (final FTPFile file : files) {
60              // The directory contains a few additional files at the beginning
61              // which aren't in the series we want. The series we want consists
62              // of files named sn.dddd. This adjusts the file list to get rid
63              // of the uninteresting ones.
64              if (file.getName().startsWith("sn")) {
65                  sorted.add(file);
66              }
67          }
68          return sorted;
69      }
70  
71      /**
72       * @throws Exception
73       */
74      @Override
75      protected void setUp() throws Exception {
76          super.setUp();
77          ftpClientConfig = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
78          ftpClientConfig.setServerTimeZoneId("GMT");
79          ftpClient.configure(ftpClientConfig);
80          try {
81              ftpClient.connect("tgftp.nws.noaa.gov");
82              ftpClient.login("anonymous", "testing@apache.org");
83              ftpClient.changeWorkingDirectory("SL.us008001/DF.an/DC.sflnd/DS.metar");
84              ftpClient.enterLocalPassiveMode();
85          } catch (final IOException e) {
86              e.printStackTrace();
87          }
88      }
89  
90      /**
91       * @throws Exception
92       */
93      @Override
94      protected void tearDown() throws Exception {
95          ftpClient.disconnect();
96          super.tearDown();
97      }
98  
99      public void testTimeZoneFunctionality() throws Exception {
100         final java.util.Date nowDate = new java.util.Date();
101         final Instant nowInstant = nowDate.toInstant();
102         final FTPFile[] files = ftpClient.listFiles();
103         final TreeSet<FTPFile> sortedSet = getSortedSet(files);
104         // SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm z" );
105         FTPFile lastFile = null;
106         FTPFile firstFile = null;
107         for (final FTPFile thisFile : sortedSet) {
108             if (firstFile == null) {
109                 firstFile = thisFile;
110             }
111             // System.out.println(sdf.format(thisFile.getTimestamp().getTime())
112             // + " " +thisFile.getName());
113             if (lastFile != null) {
114                 // verify that the list is sorted earliest to latest.
115                 assertTrue(lastFile.getTimestamp().before(thisFile.getTimestamp()));
116                 assertTrue(lastFile.getTimestampInstant().isBefore(thisFile.getTimestampInstant()));
117             }
118             lastFile = thisFile;
119         }
120 
121         if (firstFile == null || lastFile == null) {
122             fail("No files found");
123         } else {
124             // test that notwithstanding any time zone differences, the newest file
125             // is older than now.
126             assertTrue(lastFile.getTimestamp().getTime().before(nowDate));
127             assertTrue(lastFile.getTimestampInstant().isBefore(nowInstant));
128             final Calendar firstCal = firstFile.getTimestamp();
129             final Instant firstInstant = firstFile.getTimestampInstant().plus(Duration.ofDays(2));
130 
131             // test that the oldest is less than two days older than the newest
132             // and, in particular, that no files have been considered "future"
133             // by the parser and therefore been relegated to the same date a
134             // year ago.
135             firstCal.add(Calendar.DAY_OF_MONTH, 2);
136             assertTrue(lastFile.getTimestamp().getTime() + " before " + firstCal.getTime(), lastFile.getTimestamp().before(firstCal));
137             assertTrue(lastFile.getTimestampInstant() + " before " + firstInstant, lastFile.getTimestampInstant().isBefore(firstInstant));
138         }
139     }
140 }