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.tftp;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  import static org.junit.jupiter.api.Assertions.fail;
25  
26  import java.io.BufferedOutputStream;
27  import java.io.File;
28  import java.io.FileInputStream;
29  import java.io.FileOutputStream;
30  import java.io.IOException;
31  import java.io.OutputStream;
32  import java.net.InetAddress;
33  
34  import org.apache.commons.io.FileUtils;
35  import org.apache.commons.net.tftp.TFTPServer.ServerMode;
36  import org.junit.jupiter.api.AfterEach;
37  import org.junit.jupiter.api.Test;
38  
39  /**
40   * Test the TFTP Server and TFTP Client by creating some FILES in the system temp folder and then uploading and downloading them.
41   */
42  class TFTPTest {
43      private static final int SERVER_PORT = 6902;
44      private static TFTPServer tftpS; //NOPMD test code
45      private static final File SERVER_DIR = FileUtils.getTempDirectory();
46      private static final String FILE_PREFIX = "tftp-";
47      private static final File[] FILES = new File[8];
48  
49      static int testsLeftToRun = 10; // TODO Nasty hack.
50  
51      // only want to do this once...
52      static {
53          try {
54              FILES[0] = createFile(new File(SERVER_DIR, FILE_PREFIX + "empty.txt"), 0);
55              FILES[1] = createFile(new File(SERVER_DIR, FILE_PREFIX + "small.txt"), 1);
56              FILES[2] = createFile(new File(SERVER_DIR, FILE_PREFIX + "511.txt"), 511);
57              FILES[3] = createFile(new File(SERVER_DIR, FILE_PREFIX + "512.txt"), 512);
58              FILES[4] = createFile(new File(SERVER_DIR, FILE_PREFIX + "513.txt"), 513);
59              FILES[5] = createFile(new File(SERVER_DIR, FILE_PREFIX + "med.txt"), 1000 * 1024);
60              FILES[6] = createFile(new File(SERVER_DIR, FILE_PREFIX + "big.txt"), 5000 * 1024);
61              FILES[7] = createFile(new File(SERVER_DIR, FILE_PREFIX + "huge.txt"), 37000 * 1024);
62  
63              // Start the server
64              tftpS = new TFTPServer(SERVER_DIR, SERVER_DIR, SERVER_PORT, ServerMode.GET_AND_PUT, null, null);
65              tftpS.setSocketTimeout(2000);
66          } catch (final IOException e) {
67              e.printStackTrace();
68          }
69  
70      }
71  
72      /*
73       * Create a file, size specified in bytes
74       */
75      private static File createFile(final File file, final int size) throws IOException {
76          try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
77              final byte[] temp = "0".getBytes();
78              for (int i = 0; i < size; i++) {
79                  os.write(temp);
80              }
81          }
82          return file;
83      }
84  
85      private boolean contentEquals(final File a, final File b) throws IOException {
86          return FileUtils.contentEquals(a, b);
87      }
88  
89      @AfterEach
90      protected void tearDown() throws Exception {
91          testsLeftToRun--;
92          if (testsLeftToRun <= 0) {
93              if (tftpS != null) {
94                  tftpS.close();
95              }
96              for (final File file : FILES) {
97                  file.delete();
98              }
99          }
100     }
101 
102     @Test
103     void testASCIIDownloads() {
104         // test with the smaller FILES
105         for (int i = 0; i < 6; i++) {
106             try {
107                 testDownload(TFTP.ASCII_MODE, FILES[i]);
108             } catch (final IOException e) {
109                 fail("Entry " + i + " Error " + e.toString());
110             }
111 
112         }
113     }
114 
115     @Test
116     void testASCIIUploads() throws Exception {
117         // test with the smaller FILES
118         for (int i = 0; i < 6; i++) {
119             testUpload(TFTP.ASCII_MODE, FILES[i]);
120         }
121     }
122 
123     @Test
124     void testDiscardPackets() throws IOException {
125         try (TFTP tftp = new TFTP()) {
126             assertThrows(NullPointerException.class, tftp::discardPackets);
127             tftp.open();
128             tftp.discardPackets();
129         }
130     }
131 
132     private void testDownload(final int mode, final File file) throws IOException {
133         // Create our TFTP instance to handle the file transfer.
134         try (TFTPClient tftp = new TFTPClient()) {
135             tftp.open();
136             tftp.setSoTimeout(2000);
137 
138             final File out = new File(SERVER_DIR, FILE_PREFIX + "download");
139 
140             // cleanup old failed runs
141             out.delete();
142             assertFalse(out.exists(), "Couldn't clear output location");
143 
144             try (FileOutputStream output = new FileOutputStream(out)) {
145                 tftp.receiveFile(file.getName(), mode, output, "localhost", SERVER_PORT);
146             }
147 
148             assertTrue(out.exists(), "file not created");
149             assertTrue(contentEquals(out, file), "FILES not identical on file " + file);
150 
151             // delete the downloaded file
152             out.delete();
153         }
154     }
155 
156     @Test
157     void testGetModeName() {
158         assertNotNull(TFTP.getModeName(0));
159         assertNotNull(TFTP.getModeName(1));
160     }
161 
162     @Test
163     void testHugeDownloads() throws Exception {
164         // test with the smaller FILES
165         for (int i = 5; i < FILES.length; i++) {
166             testDownload(TFTP.BINARY_MODE, FILES[i]);
167         }
168     }
169 
170     @Test
171     void testHugeUploads() throws Exception {
172         for (int i = 5; i < FILES.length; i++) {
173             testUpload(TFTP.BINARY_MODE, FILES[i]);
174         }
175     }
176 
177     @Test
178     void testResizeBuffer() {
179         try (TFTPClient tftp = new TFTPClient()) {
180             final int bufferSize = 1024;
181             tftp.resetBuffersToSize(bufferSize);
182             assertEquals(bufferSize + 4, tftp.getPacketSize(), "Packet size should be 1028");
183         }
184     }
185 
186     @Test
187     void testSend() throws IOException {
188         try (TFTP tftp = new TFTP()) {
189             tftp.open();
190             tftp.send(new TFTPDataPacket(InetAddress.getLocalHost(), tftp.getLocalPort(), 0, new byte[10]));
191         }
192     }
193 
194     @Test
195     void testTFTPBinaryDownloads() throws Exception {
196         // test with the smaller FILES
197         for (int i = 0; i < 6; i++) {
198             testDownload(TFTP.BINARY_MODE, FILES[i]);
199         }
200     }
201 
202     @Test
203     void testTFTPBinaryUploads() throws Exception {
204         // test with the smaller FILES
205         for (int i = 0; i < 6; i++) {
206             testUpload(TFTP.BINARY_MODE, FILES[i]);
207         }
208     }
209 
210     private void testUpload(final int mode, final File file) throws Exception {
211         // Create our TFTP instance to handle the file transfer.
212         try (TFTPClient tftp = new TFTPClient()) {
213             tftp.open();
214             tftp.setSoTimeout(2000);
215 
216             final File in = new File(SERVER_DIR, FILE_PREFIX + "upload");
217             // cleanup old failed runs
218             in.delete();
219             assertFalse(in.exists(), "Couldn't clear output location");
220 
221             try (FileInputStream fis = new FileInputStream(file)) {
222                 tftp.sendFile(in.getName(), mode, fis, "localhost", SERVER_PORT);
223             }
224 
225             // need to give the server a bit of time to receive our last packet, and
226             // close out its file buffers, etc.
227             Thread.sleep(100);
228             assertTrue(in.exists(), "file not created");
229             assertTrue(contentEquals(file, in), "FILES not identical on file " + file);
230 
231             in.delete();
232         }
233     }
234 }