1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package org.apache.hadoop.fs; 20 21 import static org.junit.Assert.*; 22 import static org.junit.Assume.assumeTrue; 23 24 import java.io.File; 25 import java.io.IOException; 26 27 import org.apache.hadoop.conf.Configuration; 28 import org.junit.Before; 29 import org.junit.BeforeClass; 30 import org.junit.Test; 31 32 public class TestFsShellCopy { 33 static Configuration conf; 34 static FsShell shell; 35 static LocalFileSystem lfs; 36 static Path testRootDir, srcPath, dstPath; 37 38 @BeforeClass setup()39 public static void setup() throws Exception { 40 conf = new Configuration(); 41 shell = new FsShell(conf); 42 lfs = FileSystem.getLocal(conf); 43 testRootDir = lfs.makeQualified(new Path( 44 System.getProperty("test.build.data","test/build/data"), 45 "testShellCopy")); 46 47 lfs.mkdirs(testRootDir); 48 srcPath = new Path(testRootDir, "srcFile"); 49 dstPath = new Path(testRootDir, "dstFile"); 50 } 51 52 @Before prepFiles()53 public void prepFiles() throws Exception { 54 lfs.setVerifyChecksum(true); 55 lfs.setWriteChecksum(true); 56 57 lfs.delete(srcPath, true); 58 lfs.delete(dstPath, true); 59 FSDataOutputStream out = lfs.create(srcPath); 60 out.writeChars("hi"); 61 out.close(); 62 assertTrue(lfs.exists(lfs.getChecksumFile(srcPath))); 63 } 64 65 @Test testCopyNoCrc()66 public void testCopyNoCrc() throws Exception { 67 shellRun(0, "-get", srcPath.toString(), dstPath.toString()); 68 checkPath(dstPath, false); 69 } 70 71 @Test testCopyCrc()72 public void testCopyCrc() throws Exception { 73 shellRun(0, "-get", "-crc", srcPath.toString(), dstPath.toString()); 74 checkPath(dstPath, true); 75 } 76 77 78 @Test testCorruptedCopyCrc()79 public void testCorruptedCopyCrc() throws Exception { 80 FSDataOutputStream out = lfs.getRawFileSystem().create(srcPath); 81 out.writeChars("bang"); 82 out.close(); 83 shellRun(1, "-get", srcPath.toString(), dstPath.toString()); 84 } 85 86 @Test testCorruptedCopyIgnoreCrc()87 public void testCorruptedCopyIgnoreCrc() throws Exception { 88 shellRun(0, "-get", "-ignoreCrc", srcPath.toString(), dstPath.toString()); 89 checkPath(dstPath, false); 90 } 91 checkPath(Path p, boolean expectChecksum)92 private void checkPath(Path p, boolean expectChecksum) throws IOException { 93 assertTrue(lfs.exists(p)); 94 boolean hasChecksum = lfs.exists(lfs.getChecksumFile(p)); 95 assertEquals(expectChecksum, hasChecksum); 96 } 97 shellRun(int n, String ... args)98 private void shellRun(int n, String ... args) throws Exception { 99 assertEquals(n, shell.run(args)); 100 } 101 102 @Test testCopyFileFromLocal()103 public void testCopyFileFromLocal() throws Exception { 104 Path testRoot = new Path(testRootDir, "testPutFile"); 105 lfs.delete(testRoot, true); 106 lfs.mkdirs(testRoot); 107 108 Path targetDir = new Path(testRoot, "target"); 109 Path filePath = new Path(testRoot, new Path("srcFile")); 110 lfs.create(filePath).close(); 111 checkPut(filePath, targetDir, false); 112 } 113 114 @Test testCopyDirFromLocal()115 public void testCopyDirFromLocal() throws Exception { 116 Path testRoot = new Path(testRootDir, "testPutDir"); 117 lfs.delete(testRoot, true); 118 lfs.mkdirs(testRoot); 119 120 Path targetDir = new Path(testRoot, "target"); 121 Path dirPath = new Path(testRoot, new Path("srcDir")); 122 lfs.mkdirs(dirPath); 123 lfs.create(new Path(dirPath, "srcFile")).close(); 124 checkPut(dirPath, targetDir, false); 125 } 126 127 @Test testCopyFileFromWindowsLocalPath()128 public void testCopyFileFromWindowsLocalPath() throws Exception { 129 assumeTrue(Path.WINDOWS); 130 String windowsTestRootPath = (new File(testRootDir.toUri().getPath() 131 .toString())).getAbsolutePath(); 132 Path testRoot = new Path(windowsTestRootPath, "testPutFile"); 133 lfs.delete(testRoot, true); 134 lfs.mkdirs(testRoot); 135 136 Path targetDir = new Path(testRoot, "target"); 137 Path filePath = new Path(testRoot, new Path("srcFile")); 138 lfs.create(filePath).close(); 139 checkPut(filePath, targetDir, true); 140 } 141 142 @Test testCopyDirFromWindowsLocalPath()143 public void testCopyDirFromWindowsLocalPath() throws Exception { 144 assumeTrue(Path.WINDOWS); 145 String windowsTestRootPath = (new File(testRootDir.toUri().getPath() 146 .toString())).getAbsolutePath(); 147 Path testRoot = new Path(windowsTestRootPath, "testPutDir"); 148 lfs.delete(testRoot, true); 149 lfs.mkdirs(testRoot); 150 151 Path targetDir = new Path(testRoot, "target"); 152 Path dirPath = new Path(testRoot, new Path("srcDir")); 153 lfs.mkdirs(dirPath); 154 lfs.create(new Path(dirPath, "srcFile")).close(); 155 checkPut(dirPath, targetDir, true); 156 } 157 158 checkPut(Path srcPath, Path targetDir, boolean useWindowsPath)159 private void checkPut(Path srcPath, Path targetDir, boolean useWindowsPath) 160 throws Exception { 161 lfs.delete(targetDir, true); 162 lfs.mkdirs(targetDir); 163 lfs.setWorkingDirectory(targetDir); 164 165 final Path dstPath = new Path("path"); 166 final Path childPath = new Path(dstPath, "childPath"); 167 lfs.setWorkingDirectory(targetDir); 168 169 // copy to new file, then again 170 prepPut(dstPath, false, false); 171 checkPut(0, srcPath, dstPath, useWindowsPath); 172 if (lfs.isFile(srcPath)) { 173 checkPut(1, srcPath, dstPath, useWindowsPath); 174 } else { // directory works because it copies into the dir 175 // clear contents so the check won't think there are extra paths 176 prepPut(dstPath, true, true); 177 checkPut(0, srcPath, dstPath, useWindowsPath); 178 } 179 180 // copy to non-existent subdir 181 prepPut(childPath, false, false); 182 checkPut(1, srcPath, dstPath, useWindowsPath); 183 184 // copy into dir, then with another name 185 prepPut(dstPath, true, true); 186 checkPut(0, srcPath, dstPath, useWindowsPath); 187 prepPut(childPath, true, true); 188 checkPut(0, srcPath, childPath, useWindowsPath); 189 190 // try to put to pwd with existing dir 191 prepPut(targetDir, true, true); 192 checkPut(0, srcPath, null, useWindowsPath); 193 prepPut(targetDir, true, true); 194 checkPut(0, srcPath, new Path("."), useWindowsPath); 195 196 // try to put to pwd with non-existent cwd 197 prepPut(dstPath, false, true); 198 lfs.setWorkingDirectory(dstPath); 199 checkPut(1, srcPath, null, useWindowsPath); 200 prepPut(dstPath, false, true); 201 checkPut(1, srcPath, new Path("."), useWindowsPath); 202 } 203 prepPut(Path dst, boolean create, boolean isDir)204 private void prepPut(Path dst, boolean create, 205 boolean isDir) throws IOException { 206 lfs.delete(dst, true); 207 assertFalse(lfs.exists(dst)); 208 if (create) { 209 if (isDir) { 210 lfs.mkdirs(dst); 211 assertTrue(lfs.isDirectory(dst)); 212 } else { 213 lfs.mkdirs(new Path(dst.getName())); 214 lfs.create(dst).close(); 215 assertTrue(lfs.isFile(dst)); 216 } 217 } 218 } 219 checkPut(int exitCode, Path src, Path dest, boolean useWindowsPath)220 private void checkPut(int exitCode, Path src, Path dest, 221 boolean useWindowsPath) throws Exception { 222 String argv[] = null; 223 String srcPath = src.toString(); 224 if (useWindowsPath) { 225 srcPath = (new File(srcPath)).getAbsolutePath(); 226 } 227 if (dest != null) { 228 argv = new String[]{ "-put", srcPath, pathAsString(dest) }; 229 } else { 230 argv = new String[]{ "-put", srcPath }; 231 dest = new Path(Path.CUR_DIR); 232 } 233 234 Path target; 235 if (lfs.exists(dest)) { 236 if (lfs.isDirectory(dest)) { 237 target = new Path(pathAsString(dest), src.getName()); 238 } else { 239 target = dest; 240 } 241 } else { 242 target = new Path(lfs.getWorkingDirectory(), dest); 243 } 244 boolean targetExists = lfs.exists(target); 245 Path parent = lfs.makeQualified(target).getParent(); 246 247 System.out.println("COPY src["+src.getName()+"] -> ["+dest+"] as ["+target+"]"); 248 String lsArgv[] = new String[]{ "-ls", "-R", pathAsString(parent) }; 249 shell.run(lsArgv); 250 251 int gotExit = shell.run(argv); 252 253 System.out.println("copy exit:"+gotExit); 254 lsArgv = new String[]{ "-ls", "-R", pathAsString(parent) }; 255 shell.run(lsArgv); 256 257 if (exitCode == 0) { 258 assertTrue(lfs.exists(target)); 259 assertTrue(lfs.isFile(src) == lfs.isFile(target)); 260 assertEquals(1, lfs.listStatus(lfs.makeQualified(target).getParent()).length); 261 } else { 262 assertEquals(targetExists, lfs.exists(target)); 263 } 264 assertEquals(exitCode, gotExit); 265 } 266 267 @Test testRepresentsDir()268 public void testRepresentsDir() throws Exception { 269 Path subdirDstPath = new Path(dstPath, srcPath.getName()); 270 String argv[] = null; 271 lfs.delete(dstPath, true); 272 assertFalse(lfs.exists(dstPath)); 273 274 argv = new String[]{ "-put", srcPath.toString(), dstPath.toString() }; 275 assertEquals(0, shell.run(argv)); 276 assertTrue(lfs.exists(dstPath) && lfs.isFile(dstPath)); 277 278 lfs.delete(dstPath, true); 279 assertFalse(lfs.exists(dstPath)); 280 281 // since dst path looks like a dir, it should not copy the file and 282 // rename it to what looks like a directory 283 lfs.delete(dstPath, true); // make copy fail 284 for (String suffix : new String[]{ "/", "/." } ) { 285 argv = new String[]{ 286 "-put", srcPath.toString(), dstPath.toString()+suffix }; 287 assertEquals(1, shell.run(argv)); 288 assertFalse(lfs.exists(dstPath)); 289 assertFalse(lfs.exists(subdirDstPath)); 290 } 291 292 // since dst path looks like a dir, it should not copy the file and 293 // rename it to what looks like a directory 294 for (String suffix : new String[]{ "/", "/." } ) { 295 // empty out the directory and create to make copy succeed 296 lfs.delete(dstPath, true); 297 lfs.mkdirs(dstPath); 298 argv = new String[]{ 299 "-put", srcPath.toString(), dstPath.toString()+suffix }; 300 assertEquals(0, shell.run(argv)); 301 assertTrue(lfs.exists(subdirDstPath)); 302 assertTrue(lfs.isFile(subdirDstPath)); 303 } 304 305 // ensure .. is interpreted as a dir 306 String dotdotDst = dstPath+"/foo/.."; 307 lfs.delete(dstPath, true); 308 lfs.mkdirs(new Path(dstPath, "foo")); 309 argv = new String[]{ "-put", srcPath.toString(), dotdotDst }; 310 assertEquals(0, shell.run(argv)); 311 assertTrue(lfs.exists(subdirDstPath)); 312 assertTrue(lfs.isFile(subdirDstPath)); 313 } 314 315 @Test testCopyMerge()316 public void testCopyMerge() throws Exception { 317 Path root = new Path(testRootDir, "TestMerge"); 318 Path f1 = new Path(root, "f1"); 319 Path f2 = new Path(root, "f2"); 320 Path f3 = new Path(root, "f3"); 321 Path fnf = new Path(root, "fnf"); 322 Path d = new Path(root, "dir"); 323 Path df1 = new Path(d, "df1"); 324 Path df2 = new Path(d, "df2"); 325 Path df3 = new Path(d, "df3"); 326 327 createFile(f1, f2, f3, df1, df2, df3); 328 329 int exit; 330 // one file, kind of silly 331 exit = shell.run(new String[]{ 332 "-getmerge", 333 f1.toString(), 334 "out" }); 335 assertEquals(0, exit); 336 assertEquals("f1", readFile("out")); 337 338 exit = shell.run(new String[]{ 339 "-getmerge", 340 fnf.toString(), 341 "out" }); 342 assertEquals(1, exit); 343 assertFalse(lfs.exists(new Path("out"))); 344 345 // two files 346 exit = shell.run(new String[]{ 347 "-getmerge", 348 f1.toString(), f2.toString(), 349 "out" }); 350 assertEquals(0, exit); 351 assertEquals("f1f2", readFile("out")); 352 353 // two files, preserves order 354 exit = shell.run(new String[]{ 355 "-getmerge", 356 f2.toString(), f1.toString(), 357 "out" }); 358 assertEquals(0, exit); 359 assertEquals("f2f1", readFile("out")); 360 361 // two files 362 exit = shell.run(new String[]{ 363 "-getmerge", "-nl", 364 f1.toString(), f2.toString(), 365 "out" }); 366 assertEquals(0, exit); 367 assertEquals("f1\nf2\n", readFile("out")); 368 369 // glob three files 370 shell.run(new String[]{ 371 "-getmerge", "-nl", 372 new Path(root, "f*").toString(), 373 "out" }); 374 assertEquals(0, exit); 375 assertEquals("f1\nf2\nf3\n", readFile("out")); 376 377 // directory with 3 files, should skip subdir 378 shell.run(new String[]{ 379 "-getmerge", "-nl", 380 root.toString(), 381 "out" }); 382 assertEquals(0, exit); 383 assertEquals("f1\nf2\nf3\n", readFile("out")); 384 385 // subdir 386 shell.run(new String[]{ 387 "-getmerge", "-nl", 388 d.toString(), "out"}); 389 assertEquals(0, exit); 390 assertEquals("df1\ndf2\ndf3\n", readFile("out")); 391 392 // file, dir, file 393 shell.run(new String[]{ 394 "-getmerge", "-nl", 395 f1.toString(), d.toString(), f2.toString(), "out" }); 396 assertEquals(0, exit); 397 assertEquals("f1\ndf1\ndf2\ndf3\nf2\n", readFile("out")); 398 } 399 400 401 @Test testMoveFileFromLocal()402 public void testMoveFileFromLocal() throws Exception { 403 Path testRoot = new Path(testRootDir, "testPutFile"); 404 lfs.delete(testRoot, true); 405 lfs.mkdirs(testRoot); 406 407 Path target = new Path(testRoot, "target"); 408 Path srcFile = new Path(testRoot, new Path("srcFile")); 409 lfs.createNewFile(srcFile); 410 411 int exit = shell.run(new String[]{ 412 "-moveFromLocal", srcFile.toString(), target.toString() }); 413 assertEquals(0, exit); 414 assertFalse(lfs.exists(srcFile)); 415 assertTrue(lfs.exists(target)); 416 assertTrue(lfs.isFile(target)); 417 } 418 419 @Test testMoveDirFromLocal()420 public void testMoveDirFromLocal() throws Exception { 421 Path testRoot = new Path(testRootDir, "testPutDir"); 422 lfs.delete(testRoot, true); 423 lfs.mkdirs(testRoot); 424 425 Path srcDir = new Path(testRoot, "srcDir"); 426 lfs.mkdirs(srcDir); 427 Path targetDir = new Path(testRoot, "target"); 428 429 int exit = shell.run(new String[]{ 430 "-moveFromLocal", srcDir.toString(), targetDir.toString() }); 431 assertEquals(0, exit); 432 assertFalse(lfs.exists(srcDir)); 433 assertTrue(lfs.exists(targetDir)); 434 } 435 436 @Test testMoveDirFromLocalDestExists()437 public void testMoveDirFromLocalDestExists() throws Exception { 438 Path testRoot = new Path(testRootDir, "testPutDir"); 439 lfs.delete(testRoot, true); 440 lfs.mkdirs(testRoot); 441 442 Path srcDir = new Path(testRoot, "srcDir"); 443 lfs.mkdirs(srcDir); 444 Path targetDir = new Path(testRoot, "target"); 445 lfs.mkdirs(targetDir); 446 447 int exit = shell.run(new String[]{ 448 "-moveFromLocal", srcDir.toString(), targetDir.toString() }); 449 assertEquals(0, exit); 450 assertFalse(lfs.exists(srcDir)); 451 assertTrue(lfs.exists(new Path(targetDir, srcDir.getName()))); 452 453 lfs.mkdirs(srcDir); 454 exit = shell.run(new String[]{ 455 "-moveFromLocal", srcDir.toString(), targetDir.toString() }); 456 assertEquals(1, exit); 457 assertTrue(lfs.exists(srcDir)); 458 } 459 460 @Test testMoveFromWindowsLocalPath()461 public void testMoveFromWindowsLocalPath() throws Exception { 462 assumeTrue(Path.WINDOWS); 463 Path testRoot = new Path(testRootDir, "testPutFile"); 464 lfs.delete(testRoot, true); 465 lfs.mkdirs(testRoot); 466 467 Path target = new Path(testRoot, "target"); 468 Path srcFile = new Path(testRoot, new Path("srcFile")); 469 lfs.createNewFile(srcFile); 470 471 String winSrcFile = (new File(srcFile.toUri().getPath() 472 .toString())).getAbsolutePath(); 473 shellRun(0, "-moveFromLocal", winSrcFile, target.toString()); 474 assertFalse(lfs.exists(srcFile)); 475 assertTrue(lfs.exists(target)); 476 assertTrue(lfs.isFile(target)); 477 } 478 479 @Test testGetWindowsLocalPath()480 public void testGetWindowsLocalPath() throws Exception { 481 assumeTrue(Path.WINDOWS); 482 String winDstFile = (new File(dstPath.toUri().getPath() 483 .toString())).getAbsolutePath(); 484 shellRun(0, "-get", srcPath.toString(), winDstFile); 485 checkPath(dstPath, false); 486 } 487 createFile(Path .... paths)488 private void createFile(Path ... paths) throws IOException { 489 for (Path path : paths) { 490 FSDataOutputStream out = lfs.create(path); 491 out.write(path.getName().getBytes()); 492 out.close(); 493 } 494 } 495 readFile(String out)496 private String readFile(String out) throws IOException { 497 Path path = new Path(out); 498 FileStatus stat = lfs.getFileStatus(path); 499 FSDataInputStream in = lfs.open(path); 500 byte[] buffer = new byte[(int)stat.getLen()]; 501 in.readFully(buffer); 502 in.close(); 503 lfs.delete(path, false); 504 return new String(buffer); 505 } 506 507 // path handles "." rather oddly pathAsString(Path p)508 private String pathAsString(Path p) { 509 String s = (p == null) ? Path.CUR_DIR : p.toString(); 510 return s.isEmpty() ? Path.CUR_DIR : s; 511 } 512 } 513