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    *      https://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 static org.junit.jupiter.api.Assertions.assertTrue;
20  import static org.junit.jupiter.api.Assertions.fail;
21  
22  import java.io.IOException;
23  import java.time.Duration;
24  import java.time.Instant;
25  import java.util.Calendar;
26  import java.util.TreeSet;
27  
28  import org.junit.jupiter.api.AfterEach;
29  import org.junit.jupiter.api.BeforeEach;
30  import org.junit.jupiter.api.Test;
31  
32  /**
33   * 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
34   * setting. It is a perfect functional test for the Time Zone functionality of FTPClientConfig.
35   *
36   * A publicly accessible FTP server at the US National Oceanographic and Atmospheric Adminstration houses a directory which contains 300 files, named sn.0000 to
37   * 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
38   * data. Since the server has its clock set to GMT this is an excellent functional test for any machine in a different time zone.
39   *
40   * 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
41   * 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
42   * the current year, so they assume the year to be last year. This illustrates the value of FTPClientConfig's time zone functionality.
43   */
44  class FTPClientConfigFunctionalTest {
45  
46      private final FTPClient ftpClient = new FTPClient();
47      private FTPClientConfig ftpClientConfig;
48  
49      private TreeSet<FTPFile> getSortedSet(final FTPFile[] files) {
50          // create a TreeSet which will sort each element
51          // as it is added.
52          final TreeSet<FTPFile> sorted = new TreeSet<>((o1, o2) -> o1.getTimestamp().getTime().compareTo(o2.getTimestamp().getTime()));
53  
54          for (final FTPFile file : files) {
55              // The directory contains a few additional files at the beginning
56              // which aren't in the series we want. The series we want consists
57              // of files named sn.dddd. This adjusts the file list to get rid
58              // of the uninteresting ones.
59              if (file.getName().startsWith("sn")) {
60                  sorted.add(file);
61              }
62          }
63          return sorted;
64      }
65  
66      /**
67       * @throws Exception
68       */
69      @BeforeEach
70      protected void setUp() throws Exception {
71          ftpClientConfig = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
72          ftpClientConfig.setServerTimeZoneId("GMT");
73          ftpClient.configure(ftpClientConfig);
74          try {
75              ftpClient.connect("tgftp.nws.noaa.gov");
76              ftpClient.login("anonymous", "testing@apache.org");
77              ftpClient.changeWorkingDirectory("SL.us008001/DF.an/DC.sflnd/DS.metar");
78              ftpClient.enterLocalPassiveMode();
79          } catch (final IOException e) {
80              e.printStackTrace();
81          }
82      }
83  
84      /**
85       * @throws Exception
86       */
87      @AfterEach
88      protected void tearDown() throws Exception {
89          ftpClient.disconnect();
90      }
91  
92      @Test
93      void testTimeZoneFunctionality() throws Exception {
94          final java.util.Date nowDate = new java.util.Date();
95          final Instant nowInstant = nowDate.toInstant();
96          final FTPFile[] files = ftpClient.listFiles();
97          final TreeSet<FTPFile> sortedSet = getSortedSet(files);
98          // SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm z" );
99          FTPFile lastFile = null;
100         FTPFile firstFile = null;
101         for (final FTPFile thisFile : sortedSet) {
102             if (firstFile == null) {
103                 firstFile = thisFile;
104             }
105             // System.out.println(sdf.format(thisFile.getTimestamp().getTime())
106             // + " " +thisFile.getName());
107             if (lastFile != null) {
108                 // verify that the list is sorted earliest to latest.
109                 assertTrue(lastFile.getTimestamp().before(thisFile.getTimestamp()));
110                 assertTrue(lastFile.getTimestampInstant().isBefore(thisFile.getTimestampInstant()));
111             }
112             lastFile = thisFile;
113         }
114 
115         if (firstFile == null || lastFile == null) {
116             fail("No files found");
117         } else {
118             // test that notwithstanding any time zone differences, the newest file
119             // is older than now.
120             assertTrue(lastFile.getTimestamp().getTime().before(nowDate));
121             assertTrue(lastFile.getTimestampInstant().isBefore(nowInstant));
122             final Calendar firstCal = firstFile.getTimestamp();
123             final Instant firstInstant = firstFile.getTimestampInstant().plus(Duration.ofDays(2));
124 
125             // test that the oldest is less than two days older than the newest
126             // and, in particular, that no files have been considered "future"
127             // by the parser and therefore been relegated to the same date a
128             // year ago.
129             firstCal.add(Calendar.DAY_OF_MONTH, 2);
130             assertTrue(lastFile.getTimestamp().before(firstCal), lastFile.getTimestamp().getTime() + " before " + firstCal.getTime());
131             assertTrue(lastFile.getTimestampInstant().isBefore(firstInstant), lastFile.getTimestampInstant() + " before " + firstInstant);
132         }
133     }
134 }