You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by cm...@apache.org on 2013/08/08 23:05:11 UTC

svn commit: r1512028 - in /hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common: ./ src/test/java/org/apache/hadoop/fs/

Author: cmccabe
Date: Thu Aug  8 21:05:10 2013
New Revision: 1512028

URL: http://svn.apache.org/r1512028
Log:
HADOOP-9355.  Abstract symlink tests to use either FileContext or FileSystem. (all files) (Andrew Wang via Colin Patrick McCabe)

Added:
    hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestSymlinkLocalFS.java
    hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestSymlinkLocalFSFileContext.java
Modified:
    hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/CHANGES.txt
    hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/FileContextSymlinkBaseTest.java
    hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestLocalFSFileContextSymlink.java

Modified: hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/CHANGES.txt?rev=1512028&r1=1512027&r2=1512028&view=diff
==============================================================================
--- hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/CHANGES.txt (original)
+++ hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/CHANGES.txt Thu Aug  8 21:05:10 2013
@@ -14,6 +14,9 @@ Release 2.1.1-beta - UNRELEASED
     HADOOP-9435.  Support building the JNI code against the IBM JVM.
     (Tian Hong Wang via Colin Patrick McCabe)
 
+    HADOOP-9355.  Abstract symlink tests to use either FileContext or
+    FileSystem.  (Andrew Wang via Colin Patrick McCabe)
+
   OPTIMIZATIONS
 
   BUG FIXES
@@ -201,9 +204,6 @@ Release 2.1.0-beta - 2013-08-06
     HADOOP-9370.  Write FSWrapper class to wrap FileSystem and FileContext for
     better test coverage.  (Andrew Wang via Colin Patrick McCabe)
 
-    HADOOP-9355.  Abstract symlink tests to use either FileContext or
-    FileSystem.  (Andrew Wang via Colin Patrick McCabe)
-
     HADOOP-9673.  NetworkTopology: when a node can't be added, print out its
     location for diagnostic purposes.  (Colin Patrick McCabe)
 

Modified: hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/FileContextSymlinkBaseTest.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/FileContextSymlinkBaseTest.java?rev=1512028&r1=1512027&r2=1512028&view=diff
==============================================================================
--- hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/FileContextSymlinkBaseTest.java (original)
+++ hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/FileContextSymlinkBaseTest.java Thu Aug  8 21:05:10 2013
@@ -1,1357 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.hadoop.fs;
-
-import java.io.*;
-import java.net.URI;
-import java.util.EnumSet;
-import org.apache.hadoop.fs.FileContext;
-import org.apache.hadoop.fs.Options.CreateOpts;
-import org.apache.hadoop.fs.Options.Rename;
-import org.apache.hadoop.fs.permission.FsPermission;
-import org.apache.hadoop.fs.CreateFlag;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.fs.FSDataOutputStream;
-import static org.apache.hadoop.fs.FileContextTestHelper.*;
-
-import static org.junit.Assert.*;
-import static org.junit.Assume.assumeTrue;
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.After;
-
-/**
- * Test symbolic links using FileContext.
- */
-public abstract class FileContextSymlinkBaseTest {
-  static final long seed = 0xDEADBEEFL;
-  static final int  blockSize =  8192;
-  static final int  fileSize  = 16384;
- 
-  protected final FileContextTestHelper fileContextTestHelper = new FileContextTestHelper();
-  protected static FileContext fc;
-
-  abstract protected String getScheme();
-  abstract protected String testBaseDir1() throws IOException;
-  abstract protected String testBaseDir2() throws IOException;
-  abstract protected URI testURI();
-
-  protected IOException unwrapException(IOException e) {
-    return e;
-  }
-
-  protected static void createAndWriteFile(FileContext fc, Path p) 
-      throws IOException {
-    createFile(fc, p, fileSize / blockSize,
-        CreateOpts.createParent(),
-        CreateOpts.repFac((short) 1),
-        CreateOpts.blockSize(blockSize));
-  }
-
-  protected static void createAndWriteFile(Path p) throws IOException {
-    createAndWriteFile(fc, p);
-  }
-
-  protected static void readFile(Path p) throws IOException {
-    FileContextTestHelper.readFile(fc, p, fileSize);
-  }
-
-  protected static void readFile(FileContext fc, Path p) throws IOException {
-    FileContextTestHelper.readFile(fc, p, fileSize);
-  }
-
-  protected static void appendToFile(Path p) throws IOException {
-    FileContextTestHelper.appendToFile(fc, p, fileSize / blockSize, 
-        CreateOpts.blockSize(blockSize));
-  }
-
-  @Before
-  public void setUp() throws Exception {
-    fc.mkdir(new Path(testBaseDir1()), FileContext.DEFAULT_PERM, true);
-    fc.mkdir(new Path(testBaseDir2()), FileContext.DEFAULT_PERM, true);
-  }
-
-  @After
-  public void tearDown() throws Exception { 
-    fc.delete(new Path(testBaseDir1()), true);
-    fc.delete(new Path(testBaseDir2()), true);
-  } 
-
-  @Test
-  /** The root is not a symlink */
-  public void testStatRoot() throws IOException {
-    assertFalse(fc.getFileLinkStatus(new Path("/")).isSymlink());    
-  }
-
-  @Test
-  /** Test setWorkingDirectory not resolves symlinks */
-  public void testSetWDNotResolvesLinks() throws IOException {
-    Path dir       = new Path(testBaseDir1());
-    Path linkToDir = new Path(testBaseDir1()+"/link");
-    fc.createSymlink(dir, linkToDir, false);
-    fc.setWorkingDirectory(linkToDir);
-    assertEquals(linkToDir.getName(), fc.getWorkingDirectory().getName());
-  }
-
-  @Test
-  /** Test create a dangling link */
-  public void testCreateDanglingLink() throws IOException {
-    Path file = new Path("/noSuchFile");
-    Path link = new Path(testBaseDir1()+"/link");    
-    fc.createSymlink(file, link, false);
-    try {
-      fc.getFileStatus(link);
-      fail("Got file status of non-existant file");
-    } catch (FileNotFoundException f) {
-      // Expected
-    }
-    fc.delete(link, false);
-  } 
-
-  @Test
-  /** Test create a link to null and empty path */
-  public void testCreateLinkToNullEmpty() throws IOException {
-    Path link = new Path(testBaseDir1()+"/link");
-    try {
-      fc.createSymlink(null, link, false);
-      fail("Can't create symlink to null");
-    } catch (java.lang.NullPointerException e) {
-      // Expected, create* with null yields NPEs
-    }
-    try {
-      fc.createSymlink(new Path(""), link, false);
-      fail("Can't create symlink to empty string");
-    } catch (java.lang.IllegalArgumentException e) {
-      // Expected, Path("") is invalid
-    }
-  } 
-    
-  @Test
-  /** Create a link with createParent set */
-  public void testCreateLinkCanCreateParent() throws IOException {
-    Path file = new Path(testBaseDir1()+"/file");
-    Path link = new Path(testBaseDir2()+"/linkToFile");
-    createAndWriteFile(file);
-    fc.delete(new Path(testBaseDir2()), true);
-    try {
-      fc.createSymlink(file, link, false);
-      fail("Created link without first creating parent dir");
-    } catch (IOException x) {
-      // Expected. Need to create testBaseDir2() first.
-    }
-    assertFalse(exists(fc, new Path(testBaseDir2())));
-    fc.createSymlink(file, link, true);
-    readFile(link);
-  }
-
-  @Test
-  /** Try to create a directory given a path that refers to a symlink */
-  public void testMkdirExistingLink() throws IOException {
-    Path dir  = new Path(testBaseDir1()+"/link");
-    fc.createSymlink(new Path("/doesNotExist"), dir, false);
-    try {
-      fc.mkdir(dir, FileContext.DEFAULT_PERM, false);
-      fail("Created a dir where a symlink exists");
-    } catch (FileAlreadyExistsException e) {
-      // Expected. The symlink already exists.
-    } catch (IOException e) {
-      // LocalFs just throws an IOException
-      assertEquals("file", getScheme());
-    }
-  }
-
-  @Test
-  /** Try to create a file with parent that is a dangling link */
-  public void testCreateFileViaDanglingLinkParent() throws IOException {
-    Path dir  = new Path(testBaseDir1()+"/dangling");
-    Path file = new Path(testBaseDir1()+"/dangling/file");
-    fc.createSymlink(new Path("/doesNotExist"), dir, false);
-    FSDataOutputStream out;
-    try {
-      out = fc.create(file, EnumSet.of(CreateFlag.CREATE), 
-                      CreateOpts.repFac((short) 1),
-                      CreateOpts.blockSize(blockSize));
-      out.close();
-      fail("Created a link with dangling link parent");
-    } catch (FileNotFoundException e) {
-      // Expected. The parent is dangling.
-    }
-  }
-
-  @Test
-  /** Delete a link */
-  public void testDeleteLink() throws IOException {
-    Path file = new Path(testBaseDir1()+"/file");
-    Path link = new Path(testBaseDir1()+"/linkToFile");    
-    createAndWriteFile(file);  
-    fc.createSymlink(file, link, false);
-    readFile(link);
-    fc.delete(link, false);
-    try {
-      readFile(link);
-      fail("Symlink should have been deleted");
-    } catch (IOException x) {
-      // Expected
-    }
-    // If we deleted the link we can put it back
-    fc.createSymlink(file, link, false);    
-  }
-  
-  @Test
-  /** Ensure open resolves symlinks */
-  public void testOpenResolvesLinks() throws IOException {
-    Path file = new Path(testBaseDir1()+"/noSuchFile");
-    Path link = new Path(testBaseDir1()+"/link");
-    fc.createSymlink(file, link, false);
-    try {
-      fc.open(link);
-      fail("link target does not exist");
-    } catch (FileNotFoundException x) {
-      // Expected
-    }
-    fc.delete(link, false);
-  }
-
-  @Test
-  /** Stat a link to a file */
-  public void testStatLinkToFile() throws IOException {
-    Path file = new Path(testBaseDir1()+"/file");
-    Path linkToFile = new Path(testBaseDir1()+"/linkToFile");    
-    createAndWriteFile(file);
-    fc.createSymlink(file, linkToFile, false);
-    assertFalse(fc.getFileLinkStatus(linkToFile).isDirectory());
-    assertTrue(isSymlink(fc, linkToFile));
-    assertTrue(isFile(fc, linkToFile));
-    assertFalse(isDir(fc, linkToFile));
-    assertEquals(file.toUri().getPath(), 
-                 fc.getLinkTarget(linkToFile).toString());
-    // The local file system does not fully resolve the link
-    // when obtaining the file status
-    if (!"file".equals(getScheme())) {
-      assertEquals(fc.getFileStatus(file), fc.getFileStatus(linkToFile));
-      assertEquals(fc.makeQualified(file),
-                   fc.getFileStatus(linkToFile).getPath());
-      assertEquals(fc.makeQualified(linkToFile),
-                   fc.getFileLinkStatus(linkToFile).getPath());
-    }
-  }
-
-  @Test
-  /** Stat a relative link to a file */
-  public void testStatRelLinkToFile() throws IOException {
-    assumeTrue(!"file".equals(getScheme()));
-    Path baseDir    = new Path(testBaseDir1());
-    Path file       = new Path(testBaseDir1(), "file");
-    Path linkToFile = new Path(testBaseDir1(), "linkToFile");
-    createAndWriteFile(file);
-    fc.createSymlink(new Path("file"), linkToFile, false);
-    assertEquals(fc.getFileStatus(file), fc.getFileStatus(linkToFile));
-    assertEquals(fc.makeQualified(file),
-                 fc.getFileStatus(linkToFile).getPath());
-    assertEquals(fc.makeQualified(linkToFile),
-                 fc.getFileLinkStatus(linkToFile).getPath());
-  }
-
-  @Test
-  /** Stat a link to a directory */
-  public void testStatLinkToDir() throws IOException {
-    Path dir  = new Path(testBaseDir1());
-    Path linkToDir = new Path(testBaseDir1()+"/linkToDir");
-    fc.createSymlink(dir, linkToDir, false);
-
-    assertFalse(fc.getFileStatus(linkToDir).isSymlink());
-    assertTrue(isDir(fc, linkToDir));
-    assertFalse(fc.getFileLinkStatus(linkToDir).isDirectory());
-    assertTrue(fc.getFileLinkStatus(linkToDir).isSymlink());
-
-    assertFalse(isFile(fc, linkToDir));
-    assertTrue(isDir(fc, linkToDir));
-
-    assertEquals(dir.toUri().getPath(), 
-                 fc.getLinkTarget(linkToDir).toString());
-  }
-
-  @Test
-  /** Stat a dangling link */
-  public void testStatDanglingLink() throws IOException {
-    Path file = new Path("/noSuchFile");
-    Path link = new Path(testBaseDir1()+"/link");    
-    fc.createSymlink(file, link, false);
-    assertFalse(fc.getFileLinkStatus(link).isDirectory());
-    assertTrue(fc.getFileLinkStatus(link).isSymlink());
-  }
-  
-  @Test
-  /** Stat a non-existant file */
-  public void testStatNonExistantFiles() throws IOException {
-    Path fileAbs = new Path("/doesNotExist");
-    try {
-      fc.getFileLinkStatus(fileAbs);
-      fail("Got FileStatus for non-existant file");
-    } catch (FileNotFoundException f) {
-      // Expected
-    }
-    try {
-      fc.getLinkTarget(fileAbs);
-      fail("Got link target for non-existant file");
-    } catch (FileNotFoundException f) {
-      // Expected
-    }
-  }
-
-  @Test
-  /** Test stat'ing a regular file and directory */
-  public void testStatNonLinks() throws IOException {
-    Path dir   = new Path(testBaseDir1());
-    Path file  = new Path(testBaseDir1()+"/file");
-    createAndWriteFile(file);
-    try {
-      fc.getLinkTarget(dir);
-      fail("Lstat'd a non-symlink");
-    } catch (IOException e) {
-      // Expected.
-    }
-    try {
-      fc.getLinkTarget(file);
-      fail("Lstat'd a non-symlink");
-    } catch (IOException e) {
-      // Expected.
-    }
-  }
-  
-  @Test
-  /** Test links that link to each other */
-  public void testRecursiveLinks() throws IOException {
-    Path link1 = new Path(testBaseDir1()+"/link1");
-    Path link2 = new Path(testBaseDir1()+"/link2");
-    fc.createSymlink(link1, link2, false);
-    fc.createSymlink(link2, link1, false);
-    try {
-      readFile(link1);
-      fail("Read recursive link");
-    } catch (FileNotFoundException f) {
-      // LocalFs throws sub class of IOException, since File.exists 
-      // returns false for a link to link. 
-    } catch (IOException x) {
-      assertEquals("Possible cyclic loop while following symbolic link "+
-                   link1.toString(), x.getMessage());
-    }    
-  }
-
-  /* Assert that the given link to a file behaves as expected. */
-  private void checkLink(Path linkAbs, Path expectedTarget, Path targetQual) 
-      throws IOException { 
-    Path dir = new Path(testBaseDir1());
-    // isFile/Directory
-    assertTrue(isFile(fc, linkAbs));
-    assertFalse(isDir(fc, linkAbs));
-
-    // Check getFileStatus 
-    assertFalse(fc.getFileStatus(linkAbs).isSymlink());
-    assertFalse(fc.getFileStatus(linkAbs).isDirectory());
-    assertEquals(fileSize, fc.getFileStatus(linkAbs).getLen());
-
-    // Check getFileLinkStatus
-    assertTrue(isSymlink(fc, linkAbs));
-    assertFalse(fc.getFileLinkStatus(linkAbs).isDirectory());
-
-    // Check getSymlink always returns a qualified target, except
-    // when partially qualified paths are used (see tests below).
-    assertEquals(targetQual.toString(), 
-        fc.getFileLinkStatus(linkAbs).getSymlink().toString());
-    assertEquals(targetQual, fc.getFileLinkStatus(linkAbs).getSymlink());
-    // Check that the target is qualified using the file system of the 
-    // path used to access the link (if the link target was not specified 
-    // fully qualified, in that case we use the link target verbatim).
-    if (!"file".equals(getScheme())) {
-      FileContext localFc = FileContext.getLocalFSFileContext();
-      Path linkQual = new Path(testURI().toString(), linkAbs);
-      assertEquals(targetQual, 
-                   localFc.getFileLinkStatus(linkQual).getSymlink());
-    }
-    
-    // Check getLinkTarget
-    assertEquals(expectedTarget, fc.getLinkTarget(linkAbs));
-    
-    // Now read using all path types..
-    fc.setWorkingDirectory(dir);    
-    readFile(new Path("linkToFile"));
-    readFile(linkAbs);
-    // And fully qualified.. (NB: for local fs this is partially qualified)
-    readFile(new Path(testURI().toString(), linkAbs));
-    // And partially qualified..
-    boolean failureExpected = "file".equals(getScheme()) ? false : true;
-    try {
-      readFile(new Path(getScheme()+"://"+testBaseDir1()+"/linkToFile"));
-      assertFalse(failureExpected);
-    } catch (Exception e) {
-      assertTrue(failureExpected);
-    }
-    
-    // Now read using a different file context (for HDFS at least)
-    if (!"file".equals(getScheme())) {
-      FileContext localFc = FileContext.getLocalFSFileContext();
-      readFile(localFc, new Path(testURI().toString(), linkAbs));
-    }
-  }
-  
-  @Test
-  /** Test creating a symlink using relative paths */
-  public void testCreateLinkUsingRelPaths() throws IOException {
-    Path fileAbs = new Path(testBaseDir1(), "file");
-    Path linkAbs = new Path(testBaseDir1(), "linkToFile");
-    Path schemeAuth = new Path(testURI().toString()); 
-    Path fileQual = new Path(schemeAuth, testBaseDir1()+"/file");
-    createAndWriteFile(fileAbs);
-    
-    fc.setWorkingDirectory(new Path(testBaseDir1()));
-    fc.createSymlink(new Path("file"), new Path("linkToFile"), false);
-    checkLink(linkAbs, new Path("file"), fileQual);
-    
-    // Now rename the link's parent. Because the target was specified 
-    // with a relative path the link should still resolve.
-    Path dir1        = new Path(testBaseDir1());
-    Path dir2        = new Path(testBaseDir2());
-    Path linkViaDir2 = new Path(testBaseDir2(), "linkToFile");
-    Path fileViaDir2 = new Path(schemeAuth, testBaseDir2()+"/file");
-    fc.rename(dir1, dir2, Rename.OVERWRITE);
-    assertEquals(fileViaDir2, fc.getFileLinkStatus(linkViaDir2).getSymlink());
-    readFile(linkViaDir2);
-  }
-
-  @Test
-  /** Test creating a symlink using absolute paths */
-  public void testCreateLinkUsingAbsPaths() throws IOException {
-    Path fileAbs = new Path(testBaseDir1()+"/file");
-    Path linkAbs = new Path(testBaseDir1()+"/linkToFile");
-    Path schemeAuth = new Path(testURI().toString()); 
-    Path fileQual = new Path(schemeAuth, testBaseDir1()+"/file");
-    createAndWriteFile(fileAbs);
-
-    fc.createSymlink(fileAbs, linkAbs, false);
-    checkLink(linkAbs, fileAbs, fileQual);
-
-    // Now rename the link's parent. The target doesn't change and
-    // now no longer exists so accessing the link should fail.
-    Path dir1        = new Path(testBaseDir1());
-    Path dir2        = new Path(testBaseDir2());
-    Path linkViaDir2 = new Path(testBaseDir2(), "linkToFile");
-    fc.rename(dir1, dir2, Rename.OVERWRITE);
-    assertEquals(fileQual, fc.getFileLinkStatus(linkViaDir2).getSymlink());    
-    try {
-      readFile(linkViaDir2);
-      fail("The target should not exist");
-    } catch (FileNotFoundException x) {
-      // Expected
-    }
-  } 
-  
-  @Test
-  /** 
-   * Test creating a symlink using fully and partially qualified paths.
-   * NB: For local fs this actually tests partially qualified paths,
-   * as they don't support fully qualified paths.
-   */
-  public void testCreateLinkUsingFullyQualPaths() throws IOException {
-    Path fileAbs  = new Path(testBaseDir1(), "file");
-    Path linkAbs  = new Path(testBaseDir1(), "linkToFile");
-    Path fileQual = new Path(testURI().toString(), fileAbs);
-    Path linkQual = new Path(testURI().toString(), linkAbs);
-    createAndWriteFile(fileAbs);
-    
-    fc.createSymlink(fileQual, linkQual, false);
-    checkLink(linkAbs, 
-              "file".equals(getScheme()) ? fileAbs : fileQual, 
-              fileQual);
-    
-    // Now rename the link's parent. The target doesn't change and
-    // now no longer exists so accessing the link should fail.
-    Path dir1        = new Path(testBaseDir1());
-    Path dir2        = new Path(testBaseDir2());
-    Path linkViaDir2 = new Path(testBaseDir2(), "linkToFile");
-    fc.rename(dir1, dir2, Rename.OVERWRITE);    
-    assertEquals(fileQual, fc.getFileLinkStatus(linkViaDir2).getSymlink());    
-    try {
-      readFile(linkViaDir2);
-      fail("The target should not exist");
-    } catch (FileNotFoundException x) {
-      // Expected
-    }
-  } 
-    
-  @Test
-  /** 
-   * Test creating a symlink using partially qualified paths, ie a scheme 
-   * but no authority and vice versa. We just test link targets here since
-   * creating using a partially qualified path is file system specific.
-   */
-  public void testCreateLinkUsingPartQualPath1() throws IOException {
-    // Partially qualified paths are covered for local file systems
-    // in the previous test.
-    assumeTrue(!"file".equals(getScheme()));
-    Path schemeAuth   = new Path(testURI().toString());
-    Path fileWoHost   = new Path(getScheme()+"://"+testBaseDir1()+"/file");
-    Path link         = new Path(testBaseDir1()+"/linkToFile");
-    Path linkQual     = new Path(schemeAuth, testBaseDir1()+"/linkToFile");
-    FileContext localFc = FileContext.getLocalFSFileContext();
-
-    fc.createSymlink(fileWoHost, link, false);
-    // Partially qualified path is stored
-    assertEquals(fileWoHost, fc.getLinkTarget(linkQual));    
-    // NB: We do not add an authority
-    assertEquals(fileWoHost.toString(),
-      fc.getFileLinkStatus(link).getSymlink().toString());
-    assertEquals(fileWoHost.toString(),
-      fc.getFileLinkStatus(linkQual).getSymlink().toString());
-    // Ditto even from another file system
-    assertEquals(fileWoHost.toString(),
-      localFc.getFileLinkStatus(linkQual).getSymlink().toString());
-    // Same as if we accessed a partially qualified path directly
-    try { 
-      readFile(link);
-      fail("DFS requires URIs with schemes have an authority");
-    } catch (java.lang.RuntimeException e) {
-      // Expected
-    }
-  }
-
-  @Test
-  /** Same as above but vice versa (authority but no scheme) */
-  public void testCreateLinkUsingPartQualPath2() throws IOException {
-    Path link         = new Path(testBaseDir1(), "linkToFile");
-    Path fileWoScheme = new Path("//"+testURI().getAuthority()+ 
-                                 testBaseDir1()+"/file");
-    if ("file".equals(getScheme())) {
-      return;
-    }
-    fc.createSymlink(fileWoScheme, link, false);
-    assertEquals(fileWoScheme, fc.getLinkTarget(link));
-    assertEquals(fileWoScheme.toString(),
-      fc.getFileLinkStatus(link).getSymlink().toString());
-    try {
-      readFile(link);
-      fail("Accessed a file with w/o scheme");
-    } catch (IOException e) {
-      // Expected      
-      assertEquals("No AbstractFileSystem for scheme: null", e.getMessage());
-    }
-  }
-
-  @Test
-  /** Lstat and readlink on a normal file and directory */
-  public void testLinkStatusAndTargetWithNonLink() throws IOException {
-    Path schemeAuth = new Path(testURI().toString());
-    Path dir        = new Path(testBaseDir1());
-    Path dirQual    = new Path(schemeAuth, dir.toString());
-    Path file       = new Path(testBaseDir1(), "file");
-    Path fileQual   = new Path(schemeAuth, file.toString());
-    createAndWriteFile(file);
-    assertEquals(fc.getFileStatus(file), fc.getFileLinkStatus(file));
-    assertEquals(fc.getFileStatus(dir), fc.getFileLinkStatus(dir));
-    try {
-      fc.getLinkTarget(file);
-      fail("Get link target on non-link should throw an IOException");
-    } catch (IOException x) {
-      assertEquals("Path "+fileQual+" is not a symbolic link", x.getMessage());
-    }
-    try {
-      fc.getLinkTarget(dir);
-      fail("Get link target on non-link should throw an IOException");
-    } catch (IOException x) {
-      assertEquals("Path "+dirQual+" is not a symbolic link", x.getMessage());
-    }    
-  }
-
-  @Test
-  /** Test create symlink to a directory */
-  public void testCreateLinkToDirectory() throws IOException {
-    Path dir1      = new Path(testBaseDir1());
-    Path file      = new Path(testBaseDir1(), "file");
-    Path linkToDir = new Path(testBaseDir2(), "linkToDir");
-    createAndWriteFile(file);
-    fc.createSymlink(dir1, linkToDir, false);
-    assertFalse(isFile(fc, linkToDir));
-    assertTrue(isDir(fc, linkToDir)); 
-    assertTrue(fc.getFileStatus(linkToDir).isDirectory());
-    assertTrue(fc.getFileLinkStatus(linkToDir).isSymlink());
-  }
-  
-  @Test
-  /** Test create and remove a file through a symlink */
-  public void testCreateFileViaSymlink() throws IOException {
-    Path dir         = new Path(testBaseDir1());
-    Path linkToDir   = new Path(testBaseDir2(), "linkToDir");
-    Path fileViaLink = new Path(linkToDir, "file");
-    fc.createSymlink(dir, linkToDir, false);
-    createAndWriteFile(fileViaLink);
-    assertTrue(isFile(fc, fileViaLink));
-    assertFalse(isDir(fc, fileViaLink));
-    assertFalse(fc.getFileLinkStatus(fileViaLink).isSymlink());
-    assertFalse(fc.getFileStatus(fileViaLink).isDirectory());
-    readFile(fileViaLink);
-    fc.delete(fileViaLink, true);
-    assertFalse(exists(fc, fileViaLink));
-  }
-  
-  @Test
-  /** Test make and delete directory through a symlink */
-  public void testCreateDirViaSymlink() throws IOException {
-    Path dir1          = new Path(testBaseDir1());
-    Path subDir        = new Path(testBaseDir1(), "subDir");
-    Path linkToDir     = new Path(testBaseDir2(), "linkToDir");
-    Path subDirViaLink = new Path(linkToDir, "subDir");
-    fc.createSymlink(dir1, linkToDir, false);
-    fc.mkdir(subDirViaLink, FileContext.DEFAULT_PERM, true);
-    assertTrue(isDir(fc, subDirViaLink));
-    fc.delete(subDirViaLink, false);
-    assertFalse(exists(fc, subDirViaLink));
-    assertFalse(exists(fc, subDir));
-  }
-
-  @Test
-  /** Create symlink through a symlink */
-  public void testCreateLinkViaLink() throws IOException {
-    Path dir1        = new Path(testBaseDir1());
-    Path file        = new Path(testBaseDir1(), "file");
-    Path linkToDir   = new Path(testBaseDir2(), "linkToDir");
-    Path fileViaLink = new Path(linkToDir, "file");
-    Path linkToFile  = new Path(linkToDir, "linkToFile");
-    /*
-     * /b2/linkToDir            -> /b1
-     * /b2/linkToDir/linkToFile -> /b2/linkToDir/file
-     */
-    createAndWriteFile(file);
-    fc.createSymlink(dir1, linkToDir, false);
-    fc.createSymlink(fileViaLink, linkToFile, false);
-    assertTrue(isFile(fc, linkToFile));
-    assertTrue(fc.getFileLinkStatus(linkToFile).isSymlink());
-    readFile(linkToFile);
-    assertEquals(fileSize, fc.getFileStatus(linkToFile).getLen());
-    assertEquals(fileViaLink, fc.getLinkTarget(linkToFile));
-  }
-
-  @Test
-  /** Test create symlink to a directory */
-  public void testListStatusUsingLink() throws IOException {
-    Path file  = new Path(testBaseDir1(), "file");
-    Path link  = new Path(testBaseDir1(), "link");
-    createAndWriteFile(file);
-    fc.createSymlink(new Path(testBaseDir1()), link, false);
-    // The size of the result is file system dependent, Hdfs is 2 (file 
-    // and link) and LocalFs is 3 (file, link, file crc).
-    FileStatus[] stats = fc.util().listStatus(link);
-    assertTrue(stats.length == 2 || stats.length == 3);
-    RemoteIterator<FileStatus> statsItor = fc.listStatus(link);
-    int dirLen = 0;
-    while(statsItor.hasNext()) {
-      statsItor.next();
-      dirLen++;
-    }
-    assertTrue(dirLen == 2 || dirLen == 3);
-  }
-  
-  @Test
-  /** Test create symlink using the same path */
-  public void testCreateLinkTwice() throws IOException {
-    Path file = new Path(testBaseDir1(), "file");
-    Path link = new Path(testBaseDir1(), "linkToFile");
-    createAndWriteFile(file);
-    fc.createSymlink(file, link, false);
-    try {
-      fc.createSymlink(file, link, false);
-      fail("link already exists");
-    } catch (IOException x) {
-      // Expected
-    }
-  } 
-  
-  @Test
-  /** Test access via a symlink to a symlink */
-  public void testCreateLinkToLink() throws IOException {
-    Path dir1        = new Path(testBaseDir1());
-    Path file        = new Path(testBaseDir1(), "file");
-    Path linkToDir   = new Path(testBaseDir2(), "linkToDir");
-    Path linkToLink  = new Path(testBaseDir2(), "linkToLink");
-    Path fileViaLink = new Path(testBaseDir2(), "linkToLink/file");
-    createAndWriteFile(file);
-    fc.createSymlink(dir1, linkToDir, false);
-    fc.createSymlink(linkToDir, linkToLink, false);
-    assertTrue(isFile(fc, fileViaLink));
-    assertFalse(isDir(fc, fileViaLink));
-    assertFalse(fc.getFileLinkStatus(fileViaLink).isSymlink());
-    assertFalse(fc.getFileStatus(fileViaLink).isDirectory());
-    readFile(fileViaLink);
-  }
-
-  @Test
-  /** Can not create a file with path that refers to a symlink */
-  public void testCreateFileDirExistingLink() throws IOException {
-    Path file = new Path(testBaseDir1(), "file");
-    Path link = new Path(testBaseDir1(), "linkToFile");
-    createAndWriteFile(file);
-    fc.createSymlink(file, link, false);
-    try {
-      createAndWriteFile(link);
-      fail("link already exists");
-    } catch (IOException x) {
-      // Expected
-    }
-    try {
-      fc.mkdir(link, FsPermission.getDefault(), false);
-      fail("link already exists");
-    } catch (IOException x) {
-      // Expected
-    }    
-  } 
-
-  @Test
-  /** Test deleting and recreating a symlink */
-  public void testUseLinkAferDeleteLink() throws IOException {
-    Path file = new Path(testBaseDir1(), "file");
-    Path link = new Path(testBaseDir1(), "linkToFile");
-    createAndWriteFile(file);
-    fc.createSymlink(file, link, false);
-    fc.delete(link, false);
-    try {
-      readFile(link);        
-      fail("link was deleted");
-    } catch (IOException x) {
-      // Expected
-    }
-    readFile(file);
-    fc.createSymlink(file, link, false);
-    readFile(link);    
-  } 
-  
-  
-  @Test
-  /** Test create symlink to . */
-  public void testCreateLinkToDot() throws IOException {
-    Path dir  = new Path(testBaseDir1());
-    Path file = new Path(testBaseDir1(), "file");    
-    Path link = new Path(testBaseDir1(), "linkToDot");
-    createAndWriteFile(file);    
-    fc.setWorkingDirectory(dir);
-    try {
-      fc.createSymlink(new Path("."), link, false);
-      fail("Created symlink to dot");
-    } catch (IOException x) {
-      // Expected. Path(".") resolves to "" because URI normalizes
-      // the dot away and AbstractFileSystem considers "" invalid.  
-    }
-  }
-
-  @Test
-  /** Test create symlink to .. */
-  public void testCreateLinkToDotDot() throws IOException {
-    Path file        = new Path(testBaseDir1(), "test/file");
-    Path dotDot      = new Path(testBaseDir1(), "test/..");
-    Path linkToDir   = new Path(testBaseDir2(), "linkToDir");
-    Path fileViaLink = new Path(linkToDir,      "test/file");
-    // Symlink to .. is not a problem since the .. is squashed early
-    assertEquals(testBaseDir1(), dotDot.toString());
-    createAndWriteFile(file);
-    fc.createSymlink(dotDot, linkToDir, false);
-    readFile(fileViaLink);
-    assertEquals(fileSize, fc.getFileStatus(fileViaLink).getLen());    
-  }
-
-  @Test
-  /** Test create symlink to ../file */
-  public void testCreateLinkToDotDotPrefix() throws IOException {
-    Path file = new Path(testBaseDir1(), "file");
-    Path dir  = new Path(testBaseDir1(), "test");
-    Path link = new Path(testBaseDir1(), "test/link");
-    createAndWriteFile(file);
-    fc.mkdir(dir, FsPermission.getDefault(), false);
-    fc.setWorkingDirectory(dir);
-    fc.createSymlink(new Path("../file"), link, false);
-    readFile(link);
-    assertEquals(new Path("../file"), fc.getLinkTarget(link));
-  }
-  
-  @Test
-  /** Test rename file using a path that contains a symlink. The rename should 
-   * work as if the path did not contain a symlink */
-  public void testRenameFileViaSymlink() throws IOException {
-    Path dir            = new Path(testBaseDir1());
-    Path file           = new Path(testBaseDir1(), "file");
-    Path linkToDir      = new Path(testBaseDir2(), "linkToDir");
-    Path fileViaLink    = new Path(linkToDir, "file");
-    Path fileNewViaLink = new Path(linkToDir, "fileNew");
-    createAndWriteFile(file);
-    fc.createSymlink(dir, linkToDir, false);
-    fc.rename(fileViaLink, fileNewViaLink);
-    assertFalse(exists(fc, fileViaLink));
-    assertFalse(exists(fc, file));
-    assertTrue(exists(fc, fileNewViaLink));
-  }
-
-  @Test
-  /** Test rename a file through a symlink but this time only the 
-   * destination path has an intermediate symlink. The rename should work 
-   * as if the path did not contain a symlink */
-  public void testRenameFileToDestViaSymlink() throws IOException {
-    Path dir       = new Path(testBaseDir1());
-    Path file      = new Path(testBaseDir1(), "file");
-    Path linkToDir = new Path(testBaseDir2(), "linkToDir");
-    Path subDir    = new Path(linkToDir, "subDir");
-    createAndWriteFile(file);
-    fc.createSymlink(dir, linkToDir, false);
-    fc.mkdir(subDir, FileContext.DEFAULT_PERM, false);
-    try {
-      fc.rename(file, subDir);
-      fail("Renamed file to a directory");
-    } catch (IOException e) {
-      // Expected. Both must be directories.
-      assertTrue(unwrapException(e) instanceof IOException);
-    }
-    assertTrue(exists(fc, file));
-  }
-  
-  @Test
-  /** Similar tests as the previous ones but rename a directory */
-  public void testRenameDirViaSymlink() throws IOException {
-    Path baseDir       = new Path(testBaseDir1());
-    Path dir           = new Path(baseDir, "dir");
-    Path linkToDir     = new Path(testBaseDir2(), "linkToDir");
-    Path dirViaLink    = new Path(linkToDir, "dir");
-    Path dirNewViaLink = new Path(linkToDir, "dirNew");
-    fc.mkdir(dir, FileContext.DEFAULT_PERM, false);
-    fc.createSymlink(baseDir, linkToDir, false);
-    assertTrue(exists(fc, dirViaLink));
-    fc.rename(dirViaLink, dirNewViaLink);
-    assertFalse(exists(fc, dirViaLink));
-    assertFalse(exists(fc, dir));
-    assertTrue(exists(fc, dirNewViaLink));
-  }
-    
-  @Test
-  /** Similar tests as the previous ones but rename a symlink */  
-  public void testRenameSymlinkViaSymlink() throws IOException {
-    Path baseDir        = new Path(testBaseDir1());
-    Path file           = new Path(testBaseDir1(), "file");
-    Path link           = new Path(testBaseDir1(), "link");
-    Path linkToDir      = new Path(testBaseDir2(), "linkToDir");
-    Path linkViaLink    = new Path(linkToDir, "link");
-    Path linkNewViaLink = new Path(linkToDir, "linkNew");
-    createAndWriteFile(file);
-    fc.createSymlink(file, link, false);
-    fc.createSymlink(baseDir, linkToDir, false);
-    fc.rename(linkViaLink, linkNewViaLink);
-    assertFalse(exists(fc, linkViaLink));
-    // Check that we didn't rename the link target
-    assertTrue(exists(fc, file));
-    assertTrue(fc.getFileLinkStatus(linkNewViaLink).isSymlink());
-    readFile(linkNewViaLink);
-  }
-
-  @Test
-  /** Test rename a directory to a symlink to a directory */
-  public void testRenameDirToSymlinkToDir() throws IOException {
-    Path dir1      = new Path(testBaseDir1());
-    Path subDir = new Path(testBaseDir2(), "subDir");
-    Path linkToDir = new Path(testBaseDir2(), "linkToDir");
-    fc.mkdir(subDir, FileContext.DEFAULT_PERM, false);
-    fc.createSymlink(subDir, linkToDir, false);
-    try {
-      fc.rename(dir1, linkToDir, Rename.OVERWRITE);
-      fail("Renamed directory to a symlink");
-    } catch (IOException e) {
-      // Expected. Both must be directories.
-      assertTrue(unwrapException(e) instanceof IOException);
-    }
-    assertTrue(exists(fc, dir1));
-    assertTrue(exists(fc, linkToDir));
-  }
-
-  @Test
-  /** Test rename a directory to a symlink to a file */
-  public void testRenameDirToSymlinkToFile() throws IOException {
-    Path dir1 = new Path(testBaseDir1());
-    Path file = new Path(testBaseDir2(), "file");
-    Path linkToFile = new Path(testBaseDir2(), "linkToFile");
-    createAndWriteFile(file);
-    fc.createSymlink(file, linkToFile, false);
-    try {
-      fc.rename(dir1, linkToFile, Rename.OVERWRITE);
-      fail("Renamed directory to a symlink");
-    } catch (IOException e) {
-      // Expected. Both must be directories.
-      assertTrue(unwrapException(e) instanceof IOException);
-    }
-    assertTrue(exists(fc, dir1));
-    assertTrue(exists(fc, linkToFile));
-  }
-
-  @Test
-  /** Test rename a directory to a dangling symlink */
-  public void testRenameDirToDanglingSymlink() throws IOException {
-    Path dir = new Path(testBaseDir1());
-    Path link = new Path(testBaseDir2(), "linkToFile");
-    fc.createSymlink(new Path("/doesNotExist"), link, false);
-    try { 
-      fc.rename(dir, link, Rename.OVERWRITE);
-      fail("Renamed directory to a symlink"); 
-    } catch (IOException e) {
-      // Expected. Both must be directories.
-      assertTrue(unwrapException(e) instanceof IOException);
-    }
-    assertTrue(exists(fc, dir));
-    assertTrue(fc.getFileLinkStatus(link) != null);
-  }
-
-  @Test
-  /** Test rename a file to a symlink to a directory */
-  public void testRenameFileToSymlinkToDir() throws IOException {
-    Path file   = new Path(testBaseDir1(), "file");
-    Path subDir = new Path(testBaseDir1(), "subDir");
-    Path link   = new Path(testBaseDir1(), "link");
-    fc.mkdir(subDir, FileContext.DEFAULT_PERM, false);
-    fc.createSymlink(subDir, link, false);
-    createAndWriteFile(file);
-    try {
-      fc.rename(file, link);
-      fail("Renamed file to symlink w/o overwrite"); 
-    } catch (IOException e) {
-      // Expected
-      assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
-    }
-    fc.rename(file, link, Rename.OVERWRITE);
-    assertFalse(exists(fc, file));
-    assertTrue(exists(fc, link));
-    assertTrue(isFile(fc, link));
-    assertFalse(fc.getFileLinkStatus(link).isSymlink());
-  }
-
-  @Test
-  /** Test rename a file to a symlink to a file */
-  public void testRenameFileToSymlinkToFile() throws IOException {
-    Path file1 = new Path(testBaseDir1(), "file1");
-    Path file2 = new Path(testBaseDir1(), "file2");
-    Path link = new Path(testBaseDir1(), "linkToFile");
-    createAndWriteFile(file1);
-    createAndWriteFile(file2);
-    fc.createSymlink(file2, link, false);
-    try {
-      fc.rename(file1, link);
-      fail("Renamed file to symlink w/o overwrite"); 
-    } catch (IOException e) {
-      // Expected
-      assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
-    }
-    fc.rename(file1, link, Rename.OVERWRITE);
-    assertFalse(exists(fc, file1));
-    assertTrue(exists(fc, link));
-    assertTrue(isFile(fc, link));
-    assertFalse(fc.getFileLinkStatus(link).isSymlink());
-  }
-
-  @Test
-  /** Test rename a file to a dangling symlink */
-  public void testRenameFileToDanglingSymlink() throws IOException {
-    /* NB: Local file system doesn't handle dangling links correctly
-     * since File.exists(danglinLink) returns false. */ 
-    if ("file".equals(getScheme())) {
-      return;
-    }
-    Path file1 = new Path(testBaseDir1(), "file1");
-    Path link = new Path(testBaseDir1(), "linkToFile");
-    createAndWriteFile(file1);
-    fc.createSymlink(new Path("/doesNotExist"), link, false);
-    try {
-      fc.rename(file1, link);  
-    } catch (IOException e) {
-      // Expected
-    }
-    fc.rename(file1, link, Rename.OVERWRITE);
-    assertFalse(exists(fc, file1));
-    assertTrue(exists(fc, link));
-    assertTrue(isFile(fc, link));
-    assertFalse(fc.getFileLinkStatus(link).isSymlink());    
-  }
-
-  @Test
-  /** Rename a symlink to a new non-existant name */
-  public void testRenameSymlinkNonExistantDest() throws IOException {
-    Path file  = new Path(testBaseDir1(), "file");
-    Path link1 = new Path(testBaseDir1(), "linkToFile1");
-    Path link2 = new Path(testBaseDir1(), "linkToFile2");
-    createAndWriteFile(file);
-    fc.createSymlink(file, link1, false);
-    fc.rename(link1, link2);
-    assertTrue(fc.getFileLinkStatus(link2).isSymlink());
-    readFile(link2);
-    readFile(file);
-    assertFalse(exists(fc, link1));
-  }
-
-  @Test
-  /** Rename a symlink to a file that exists */
-  public void testRenameSymlinkToExistingFile() throws IOException {
-    Path file1 = new Path(testBaseDir1(), "file");
-    Path file2 = new Path(testBaseDir1(), "someFile");
-    Path link = new Path(testBaseDir1(), "linkToFile");
-    createAndWriteFile(file1);
-    createAndWriteFile(file2);
-    fc.createSymlink(file2, link, false);
-    try {
-      fc.rename(link, file1);
-      fail("Renamed w/o passing overwrite");
-    } catch (IOException e) {
-      // Expected
-      assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
-    }
-    fc.rename(link, file1, Rename.OVERWRITE);
-    assertFalse(exists(fc, link));
-    assertTrue(fc.getFileLinkStatus(file1).isSymlink());
-    assertEquals(file2, fc.getLinkTarget(file1));
-  }
-
-  @Test
-  /** Rename a symlink to a directory that exists */
-  public void testRenameSymlinkToExistingDir() throws IOException {
-    Path dir1   = new Path(testBaseDir1());
-    Path dir2   = new Path(testBaseDir2());
-    Path subDir = new Path(testBaseDir2(), "subDir");
-    Path link   = new Path(testBaseDir1(), "linkToDir");    
-    fc.createSymlink(dir1, link, false);
-    try {
-      fc.rename(link, dir2);
-      fail("Renamed link to a directory");
-    } catch (IOException e) {
-      // Expected. Both must be directories.
-      assertTrue(unwrapException(e) instanceof IOException);
-    }
-    try {
-      fc.rename(link, dir2, Rename.OVERWRITE);
-      fail("Renamed link to a directory");
-    } catch (IOException e) {
-      // Expected. Both must be directories.
-      assertTrue(unwrapException(e) instanceof IOException);
-    }
-    // Also fails when dir2 has a sub-directory
-    fc.mkdir(subDir, FsPermission.getDefault(), false);
-    try {
-      fc.rename(link, dir2, Rename.OVERWRITE);
-      fail("Renamed link to a directory");
-    } catch (IOException e) {
-      // Expected. Both must be directories.
-      assertTrue(unwrapException(e) instanceof IOException);
-    }
-  }
-
-  @Test
-  /** Rename a symlink to itself */
-  public void testRenameSymlinkToItself() throws IOException {
-    Path link = new Path(testBaseDir1(), "linkToFile1");
-    fc.createSymlink(new Path("/doestNotExist"), link, false);
-    try {
-      fc.rename(link, link);
-    } catch (IOException e) {
-      assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
-    }
-    // Fails with overwrite as well
-    try {
-      fc.rename(link, link, Rename.OVERWRITE);
-    } catch (IOException e) {
-      assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
-    }
-  }
-
-  @Test
-  /** Rename a symlink */
-  public void testRenameSymlink() throws IOException {
-    Path file  = new Path(testBaseDir1(), "file");
-    Path link1 = new Path(testBaseDir1(), "linkToFile1");
-    Path link2 = new Path(testBaseDir1(), "linkToFile2");    
-    createAndWriteFile(file);
-    fc.createSymlink(file, link1, false);
-    fc.rename(link1, link2);
-    assertTrue(fc.getFileLinkStatus(link2).isSymlink());
-    assertFalse(fc.getFileStatus(link2).isDirectory());
-    readFile(link2);
-    readFile(file);
-    try {
-      createAndWriteFile(link2);
-      fail("link was not renamed");
-    } catch (IOException x) {
-      // Expected
-    } 
-  }
-
-  @Test
-  /** Rename a symlink to the file it links to */
-  public void testRenameSymlinkToFileItLinksTo() throws IOException {
-    /* NB: The rename is not atomic, so file is deleted before renaming
-     * linkToFile. In this interval linkToFile is dangling and local file 
-     * system does not handle dangling links because File.exists returns 
-     * false for dangling links. */
-    if ("file".equals(getScheme())) {
-      return;
-    }
-    Path file = new Path(testBaseDir1(), "file");
-    Path link = new Path(testBaseDir1(), "linkToFile");
-    createAndWriteFile(file);
-    fc.createSymlink(file, link, false);
-    try {
-      fc.rename(link, file);
-      fail("Renamed symlink to its target");
-    } catch (IOException e) {
-      assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
-    }
-    // Check the rename didn't happen
-    assertTrue(isFile(fc, file));
-    assertTrue(exists(fc, link));
-    assertTrue(isSymlink(fc, link));
-    assertEquals(file, fc.getLinkTarget(link));
-    try {
-      fc.rename(link, file, Rename.OVERWRITE);
-      fail("Renamed symlink to its target");
-    } catch (IOException e) {
-      assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
-    }
-    // Check the rename didn't happen
-    assertTrue(isFile(fc, file));
-    assertTrue(exists(fc, link));    
-    assertTrue(isSymlink(fc, link));
-    assertEquals(file, fc.getLinkTarget(link));    
-  }
-  
-  @Test
-  /** Rename a symlink to the directory it links to */
-  public void testRenameSymlinkToDirItLinksTo() throws IOException {
-    /* NB: The rename is not atomic, so dir is deleted before renaming
-     * linkToFile. In this interval linkToFile is dangling and local file 
-     * system does not handle dangling links because File.exists returns 
-     * false for dangling links. */
-    if ("file".equals(getScheme())) {
-      return;
-    }
-    Path dir  = new Path(testBaseDir1(), "dir");
-    Path link = new Path(testBaseDir1(), "linkToDir");
-    fc.mkdir(dir, FileContext.DEFAULT_PERM, false);
-    fc.createSymlink(dir, link, false);
-    try {
-      fc.rename(link, dir);
-      fail("Renamed symlink to its target");
-    } catch (IOException e) {
-      assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
-    }
-    // Check the rename didn't happen
-    assertTrue(isDir(fc, dir));
-    assertTrue(exists(fc, link));
-    assertTrue(isSymlink(fc, link));
-    assertEquals(dir, fc.getLinkTarget(link));
-    try {
-      fc.rename(link, dir, Rename.OVERWRITE);
-      fail("Renamed symlink to its target");
-    } catch (IOException e) {
-      assertTrue(unwrapException(e) instanceof FileAlreadyExistsException);
-    }
-    // Check the rename didn't happen
-    assertTrue(isDir(fc, dir));
-    assertTrue(exists(fc, link));
-    assertTrue(isSymlink(fc, link));
-    assertEquals(dir, fc.getLinkTarget(link));
-  }
-  
-  @Test
-  /** Test rename the symlink's target */
-  public void testRenameLinkTarget() throws IOException {
-    Path file    = new Path(testBaseDir1(), "file");
-    Path fileNew = new Path(testBaseDir1(), "fileNew");
-    Path link    = new Path(testBaseDir1(), "linkToFile");
-    createAndWriteFile(file);
-    fc.createSymlink(file, link, false);
-    fc.rename(file, fileNew, Rename.OVERWRITE);
-    try {
-      readFile(link);        
-      fail("Link should be dangling");
-    } catch (IOException x) {
-      // Expected
-    }
-    fc.rename(fileNew, file, Rename.OVERWRITE);
-    readFile(link);
-  }
-
-  @Test
-  /** Test rename a file to path with destination that has symlink parent */
-  public void testRenameFileWithDestParentSymlink() throws IOException {
-    Path link  = new Path(testBaseDir1(), "link");
-    Path file1 = new Path(testBaseDir1(), "file1");    
-    Path file2 = new Path(testBaseDir1(), "file2");    
-    Path file3 = new Path(link, "file3");
-    Path dir2  = new Path(testBaseDir2());
-    
-    // Renaming /dir1/file1 to non-existant file /dir1/link/file3 is OK
-    // if link points to a directory...
-    fc.createSymlink(dir2, link, false);
-    createAndWriteFile(file1);
-    fc.rename(file1, file3);
-    assertFalse(exists(fc, file1));
-    assertTrue(exists(fc, file3));
-    fc.rename(file3, file1);
-    
-    // But fails if link is dangling...
-    fc.delete(link, false);
-    fc.createSymlink(file2, link, false);    
-    try {
-      fc.rename(file1, file3);
-    } catch (IOException e) {
-      // Expected
-      assertTrue(unwrapException(e) instanceof FileNotFoundException);
-    }
-
-    // And if link points to a file...
-    createAndWriteFile(file2);
-    try {
-      fc.rename(file1, file3);
-    } catch (IOException e) {
-      // Expected
-      assertTrue(unwrapException(e) instanceof ParentNotDirectoryException);
-    }    
-  }
-  
-  @Test
-  /**
-   * Create, write, read, append, rename, get the block locations,
-   * checksums, and delete a file using a path with a symlink as an
-   * intermediate path component where the link target was specified
-   * using an absolute path. Rename is covered in more depth below.
-   */
-  public void testAccessFileViaInterSymlinkAbsTarget() throws IOException {
-    Path baseDir        = new Path(testBaseDir1());
-    Path file           = new Path(testBaseDir1(), "file");
-    Path fileNew        = new Path(baseDir, "fileNew");
-    Path linkToDir      = new Path(testBaseDir2(), "linkToDir");
-    Path fileViaLink    = new Path(linkToDir, "file");
-    Path fileNewViaLink = new Path(linkToDir, "fileNew");
-    fc.createSymlink(baseDir, linkToDir, false);
-    createAndWriteFile(fileViaLink);
-    assertTrue(exists(fc, fileViaLink));
-    assertTrue(isFile(fc, fileViaLink));
-    assertFalse(isDir(fc, fileViaLink));
-    assertFalse(fc.getFileLinkStatus(fileViaLink).isSymlink());
-    assertFalse(isDir(fc, fileViaLink));
-    assertEquals(fc.getFileStatus(file),
-                 fc.getFileLinkStatus(file));
-    assertEquals(fc.getFileStatus(fileViaLink),
-                 fc.getFileLinkStatus(fileViaLink));
-    readFile(fileViaLink);
-    appendToFile(fileViaLink);
-    fc.rename(fileViaLink, fileNewViaLink);
-    assertFalse(exists(fc, fileViaLink));
-    assertTrue(exists(fc, fileNewViaLink));
-    readFile(fileNewViaLink);
-    assertEquals(fc.getFileBlockLocations(fileNew, 0, 1).length,
-                 fc.getFileBlockLocations(fileNewViaLink, 0, 1).length);
-    assertEquals(fc.getFileChecksum(fileNew),
-                 fc.getFileChecksum(fileNewViaLink));
-    fc.delete(fileNewViaLink, true);
-    assertFalse(exists(fc, fileNewViaLink));
-  }
-
-  @Test
-  /**
-   * Operate on a file using a path with an intermediate symlink where
-   * the link target was specified as a fully qualified path.
-   */
-  public void testAccessFileViaInterSymlinkQualTarget() throws IOException {
-    Path baseDir        = new Path(testBaseDir1());
-    Path file           = new Path(testBaseDir1(), "file");
-    Path fileNew        = new Path(baseDir, "fileNew");
-    Path linkToDir      = new Path(testBaseDir2(), "linkToDir");
-    Path fileViaLink    = new Path(linkToDir, "file");
-    Path fileNewViaLink = new Path(linkToDir, "fileNew");
-    fc.createSymlink(fc.makeQualified(baseDir), linkToDir, false);
-    createAndWriteFile(fileViaLink);
-    assertEquals(fc.getFileStatus(file),
-                 fc.getFileLinkStatus(file));
-    assertEquals(fc.getFileStatus(fileViaLink),
-                 fc.getFileLinkStatus(fileViaLink));
-    readFile(fileViaLink);
-  }
-
-  @Test
-  /**
-   * Operate on a file using a path with an intermediate symlink where
-   * the link target was specified as a relative path.
-   */
-  public void testAccessFileViaInterSymlinkRelTarget() throws IOException {
-    assumeTrue(!"file".equals(getScheme()));
-    Path baseDir     = new Path(testBaseDir1());
-    Path dir         = new Path(testBaseDir1(), "dir");
-    Path file        = new Path(dir, "file");
-    Path linkToDir   = new Path(testBaseDir1(), "linkToDir");
-    Path fileViaLink = new Path(linkToDir, "file");
-
-    fc.mkdir(dir, FileContext.DEFAULT_PERM, false);
-    fc.createSymlink(new Path("dir"), linkToDir, false);
-    createAndWriteFile(fileViaLink);
-    // Note that getFileStatus returns fully qualified paths even
-    // when called on an absolute path.
-    assertEquals(fc.makeQualified(file),
-                 fc.getFileStatus(file).getPath());
-    // In each case getFileLinkStatus returns the same FileStatus
-    // as getFileStatus since we're not calling it on a link and
-    // FileStatus objects are compared by Path.
-    assertEquals(fc.getFileStatus(file),
-                 fc.getFileLinkStatus(file));
-    assertEquals(fc.getFileStatus(fileViaLink),
-                 fc.getFileLinkStatus(fileViaLink));
-    assertEquals(fc.getFileStatus(fileViaLink),
-                 fc.getFileLinkStatus(file));
-  }
-
-  @Test
-  /** Test create, list, and delete a directory through a symlink */
-  public void testAccessDirViaSymlink() throws IOException {
-    Path baseDir    = new Path(testBaseDir1());
-    Path dir        = new Path(testBaseDir1(), "dir");
-    Path linkToDir  = new Path(testBaseDir2(), "linkToDir");
-    Path dirViaLink = new Path(linkToDir, "dir");
-    fc.createSymlink(baseDir, linkToDir, false);
-    fc.mkdir(dirViaLink, FileContext.DEFAULT_PERM, true);
-    assertTrue(fc.getFileStatus(dirViaLink).isDirectory());
-    FileStatus[] stats = fc.util().listStatus(dirViaLink);
-    assertEquals(0, stats.length);
-    RemoteIterator<FileStatus> statsItor = fc.listStatus(dirViaLink);
-    assertFalse(statsItor.hasNext());
-    fc.delete(dirViaLink, false);
-    assertFalse(exists(fc, dirViaLink));
-    assertFalse(exists(fc, dir));
-  }
-
-  @Test
-  /** setTimes affects the target not the link */    
-  public void testSetTimes() throws IOException {
-    Path file = new Path(testBaseDir1(), "file");
-    Path link = new Path(testBaseDir1(), "linkToFile");
-    createAndWriteFile(file);
-    fc.createSymlink(file, link, false);
-    long at = fc.getFileLinkStatus(link).getAccessTime(); 
-    fc.setTimes(link, 2L, 3L);
-    // NB: local file systems don't implement setTimes
-    if (!"file".equals(getScheme())) {
-      assertEquals(at, fc.getFileLinkStatus(link).getAccessTime());
-      assertEquals(3, fc.getFileStatus(file).getAccessTime());
-      assertEquals(2, fc.getFileStatus(file).getModificationTime());
-    }
-  }
-}

Modified: hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestLocalFSFileContextSymlink.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestLocalFSFileContextSymlink.java?rev=1512028&r1=1512027&r2=1512028&view=diff
==============================================================================
--- hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestLocalFSFileContextSymlink.java (original)
+++ hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestLocalFSFileContextSymlink.java Thu Aug  8 21:05:10 2013
@@ -1,213 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.hadoop.fs;
-
-import java.io.*;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import org.apache.hadoop.fs.FileContext;
-import org.apache.hadoop.fs.permission.FsPermission;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.fs.FileUtil;
-import static org.junit.Assert.*;
-import static org.junit.Assume.assumeTrue;
-import org.junit.Test;
-import org.junit.Before;
-
-/**
- * Test symbolic links using FileContext and LocalFs.
- */
-public class TestLocalFSFileContextSymlink extends FileContextSymlinkBaseTest {
-  
-  @Override
-  protected String getScheme() {
-    return "file";
-  }
-
-  @Override
-  protected String testBaseDir1() throws IOException {
-    return fileContextTestHelper.getAbsoluteTestRootDir(fc)+"/test1";
-  }
-  
-  @Override
-  protected String testBaseDir2() throws IOException {
-    return fileContextTestHelper.getAbsoluteTestRootDir(fc)+"/test2";
-  }
-
-  @Override
-  protected URI testURI() {
-    try {
-      return new URI("file:///");
-    } catch (URISyntaxException e) {
-      return null;
-    }
-  }
-  
-  @Override
-  @Before
-  public void setUp() throws Exception {
-    fc = FileContext.getLocalFSFileContext();
-    super.setUp();
-  }
-
-  @Override
-  public void testCreateDanglingLink() throws IOException {
-    // Dangling symlinks are not supported on Windows local file system.
-    assumeTrue(!Path.WINDOWS);
-    super.testCreateDanglingLink();
-  }
-
-  @Override
-  public void testCreateFileViaDanglingLinkParent() throws IOException {
-    assumeTrue(!Path.WINDOWS);
-    super.testCreateFileViaDanglingLinkParent();
-  }
-
-  @Override
-  public void testOpenResolvesLinks() throws IOException {
-    assumeTrue(!Path.WINDOWS);
-    super.testOpenResolvesLinks();
-  }
-
-  @Override
-  public void testRecursiveLinks() throws IOException {
-    assumeTrue(!Path.WINDOWS);
-    super.testRecursiveLinks();
-  }
-
-  @Override
-  public void testRenameDirToDanglingSymlink() throws IOException {
-    assumeTrue(!Path.WINDOWS);
-    super.testRenameDirToDanglingSymlink();
-  }
-
-  @Override  
-  public void testStatDanglingLink() throws IOException {
-    assumeTrue(!Path.WINDOWS);
-    super.testStatDanglingLink();
-  }
-
-  @Test
-  /** lstat a non-existant file using a partially qualified path */
-  public void testDanglingLinkFilePartQual() throws IOException {
-    Path filePartQual = new Path(getScheme()+":///doesNotExist");
-    try {
-      fc.getFileLinkStatus(filePartQual);
-      fail("Got FileStatus for non-existant file");
-    } catch (FileNotFoundException f) {
-      // Expected
-    }
-    try {
-      fc.getLinkTarget(filePartQual);
-      fail("Got link target for non-existant file");      
-    } catch (FileNotFoundException f) {
-      // Expected
-    }
-  }
-  
-  @Test
-  /** Stat and lstat a dangling link */
-  public void testDanglingLink() throws IOException {
-    assumeTrue(!Path.WINDOWS);
-    Path fileAbs  = new Path(testBaseDir1()+"/file");    
-    Path fileQual = new Path(testURI().toString(), fileAbs);    
-    Path link     = new Path(testBaseDir1()+"/linkToFile");
-    fc.createSymlink(fileAbs, link, false);
-    // Deleting the link using FileContext currently fails because
-    // resolve looks up LocalFs rather than RawLocalFs for the path 
-    // so we call ChecksumFs delete (which doesn't delete dangling 
-    // links) instead of delegating to delete in RawLocalFileSystem 
-    // which deletes via fullyDelete. testDeleteLink above works 
-    // because the link is not dangling.
-    //assertTrue(fc.delete(link, false));
-    FileUtil.fullyDelete(new File(link.toUri().getPath()));
-    fc.createSymlink(fileAbs, link, false);
-    try {
-      fc.getFileStatus(link);
-      fail("Got FileStatus for dangling link");
-    } catch (FileNotFoundException f) {
-      // Expected. File's exists method returns false for dangling links
-    }
-    // We can stat a dangling link
-    FileStatus fsd = fc.getFileLinkStatus(link);
-    assertEquals(fileQual, fsd.getSymlink());
-    assertTrue(fsd.isSymlink());
-    assertFalse(fsd.isDirectory());
-    assertEquals("", fsd.getOwner());
-    assertEquals("", fsd.getGroup());
-    assertEquals(link, fsd.getPath());
-    assertEquals(0, fsd.getLen());
-    assertEquals(0, fsd.getBlockSize());
-    assertEquals(0, fsd.getReplication());
-    assertEquals(0, fsd.getAccessTime());
-    assertEquals(FsPermission.getDefault(), fsd.getPermission());
-    // Accessing the link 
-    try {
-      readFile(link);
-      fail("Got FileStatus for dangling link");
-    } catch (FileNotFoundException f) {
-      // Ditto.
-    }
-    // Creating the file makes the link work
-    createAndWriteFile(fileAbs);
-    fc.getFileStatus(link);
-  }
-
-  @Test
-  /** 
-   * Test getLinkTarget with a partially qualified target. 
-   * NB: Hadoop does not support fully qualified URIs for the 
-   * file scheme (eg file://host/tmp/test).
-   */  
-  public void testGetLinkStatusPartQualTarget() throws IOException {
-    Path fileAbs  = new Path(testBaseDir1()+"/file");
-    Path fileQual = new Path(testURI().toString(), fileAbs);
-    Path dir      = new Path(testBaseDir1());    
-    Path link     = new Path(testBaseDir1()+"/linkToFile");
-    Path dirNew   = new Path(testBaseDir2());
-    Path linkNew  = new Path(testBaseDir2()+"/linkToFile");
-    fc.delete(dirNew, true);
-    createAndWriteFile(fileQual);
-    fc.setWorkingDirectory(dir);
-    // Link target is partially qualified, we get the same back.
-    fc.createSymlink(fileQual, link, false);
-    assertEquals(fileQual, fc.getFileLinkStatus(link).getSymlink());
-    // Because the target was specified with an absolute path the
-    // link fails to resolve after moving the parent directory. 
-    fc.rename(dir, dirNew);
-    // The target is still the old path
-    assertEquals(fileQual, fc.getFileLinkStatus(linkNew).getSymlink());    
-    try {
-      readFile(linkNew);
-      fail("The link should be dangling now.");
-    } catch (FileNotFoundException x) {
-      // Expected.
-    }
-    // RawLocalFs only maintains the path part, not the URI, and
-    // therefore does not support links to other file systems.
-    Path anotherFs = new Path("hdfs://host:1000/dir/file");
-    FileUtil.fullyDelete(new File(linkNew.toString()));
-    try {
-      fc.createSymlink(anotherFs, linkNew, false);
-      fail("Created a local fs link to a non-local fs");
-    } catch (IOException x) {
-      // Excpected.
-    }
-  }
-}

Added: hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestSymlinkLocalFS.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestSymlinkLocalFS.java?rev=1512028&view=auto
==============================================================================
--- hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestSymlinkLocalFS.java (added)
+++ hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestSymlinkLocalFS.java Thu Aug  8 21:05:10 2013
@@ -0,0 +1,208 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.fs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.junit.Test;
+
+/**
+ * Test symbolic links using LocalFs.
+ */
+abstract public class TestSymlinkLocalFS extends SymlinkBaseTest {
+  
+  @Override
+  protected String getScheme() {
+    return "file";
+  }
+
+  @Override
+  protected String testBaseDir1() throws IOException {
+    return wrapper.getAbsoluteTestRootDir()+"/test1";
+  }
+  
+  @Override
+  protected String testBaseDir2() throws IOException {
+    return wrapper.getAbsoluteTestRootDir()+"/test2";
+  }
+
+  @Override
+  protected URI testURI() {
+    try {
+      return new URI("file:///");
+    } catch (URISyntaxException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public void testCreateDanglingLink() throws IOException {
+    // Dangling symlinks are not supported on Windows local file system.
+    assumeTrue(!Path.WINDOWS);
+    super.testCreateDanglingLink();
+  }
+
+  @Override
+  public void testCreateFileViaDanglingLinkParent() throws IOException {
+    assumeTrue(!Path.WINDOWS);
+    super.testCreateFileViaDanglingLinkParent();
+  }
+
+  @Override
+  public void testOpenResolvesLinks() throws IOException {
+    assumeTrue(!Path.WINDOWS);
+    super.testOpenResolvesLinks();
+  }
+
+  @Override
+  public void testRecursiveLinks() throws IOException {
+    assumeTrue(!Path.WINDOWS);
+    super.testRecursiveLinks();
+  }
+
+  @Override
+  public void testRenameDirToDanglingSymlink() throws IOException {
+    assumeTrue(!Path.WINDOWS);
+    super.testRenameDirToDanglingSymlink();
+  }
+
+  @Override  
+  public void testStatDanglingLink() throws IOException {
+    assumeTrue(!Path.WINDOWS);
+    super.testStatDanglingLink();
+  }
+
+  @Test(timeout=1000)
+  /** lstat a non-existant file using a partially qualified path */
+  public void testDanglingLinkFilePartQual() throws IOException {
+    Path filePartQual = new Path(getScheme()+":///doesNotExist");
+    try {
+      wrapper.getFileLinkStatus(filePartQual);
+      fail("Got FileStatus for non-existant file");
+    } catch (FileNotFoundException f) {
+      // Expected
+    }
+    try {
+      wrapper.getLinkTarget(filePartQual);
+      fail("Got link target for non-existant file");
+    } catch (FileNotFoundException f) {
+      // Expected
+    }
+  }
+  
+  @Test(timeout=1000)
+  /** Stat and lstat a dangling link */
+  public void testDanglingLink() throws IOException {
+    assumeTrue(!Path.WINDOWS);
+    Path fileAbs  = new Path(testBaseDir1()+"/file");
+    Path fileQual = new Path(testURI().toString(), fileAbs);
+    Path link     = new Path(testBaseDir1()+"/linkToFile");
+    wrapper.createSymlink(fileAbs, link, false);
+    // Deleting the link using FileContext currently fails because
+    // resolve looks up LocalFs rather than RawLocalFs for the path 
+    // so we call ChecksumFs delete (which doesn't delete dangling 
+    // links) instead of delegating to delete in RawLocalFileSystem 
+    // which deletes via fullyDelete. testDeleteLink above works 
+    // because the link is not dangling.
+    //assertTrue(fc.delete(link, false));
+    FileUtil.fullyDelete(new File(link.toUri().getPath()));
+    wrapper.createSymlink(fileAbs, link, false);
+    try {
+      wrapper.getFileStatus(link);
+      fail("Got FileStatus for dangling link");
+    } catch (FileNotFoundException f) {
+      // Expected. File's exists method returns false for dangling links
+    }
+    // We can stat a dangling link
+    FileStatus fsd = wrapper.getFileLinkStatus(link);
+    assertEquals(fileQual, fsd.getSymlink());
+    assertTrue(fsd.isSymlink());
+    assertFalse(fsd.isDirectory());
+    assertEquals("", fsd.getOwner());
+    assertEquals("", fsd.getGroup());
+    assertEquals(link, fsd.getPath());
+    assertEquals(0, fsd.getLen());
+    assertEquals(0, fsd.getBlockSize());
+    assertEquals(0, fsd.getReplication());
+    assertEquals(0, fsd.getAccessTime());
+    assertEquals(FsPermission.getDefault(), fsd.getPermission());
+    // Accessing the link 
+    try {
+      readFile(link);
+      fail("Got FileStatus for dangling link");
+    } catch (FileNotFoundException f) {
+      // Ditto.
+    }
+    // Creating the file makes the link work
+    createAndWriteFile(fileAbs);
+    wrapper.getFileStatus(link);
+  }
+
+  @Test(timeout=1000)
+  /** 
+   * Test getLinkTarget with a partially qualified target. 
+   * NB: Hadoop does not support fully qualified URIs for the 
+   * file scheme (eg file://host/tmp/test).
+   */  
+  public void testGetLinkStatusPartQualTarget() throws IOException {
+    Path fileAbs  = new Path(testBaseDir1()+"/file");
+    Path fileQual = new Path(testURI().toString(), fileAbs);
+    Path dir      = new Path(testBaseDir1());
+    Path link     = new Path(testBaseDir1()+"/linkToFile");
+    Path dirNew   = new Path(testBaseDir2());
+    Path linkNew  = new Path(testBaseDir2()+"/linkToFile");
+    wrapper.delete(dirNew, true);
+    createAndWriteFile(fileQual);
+    wrapper.setWorkingDirectory(dir);
+    // Link target is partially qualified, we get the same back.
+    wrapper.createSymlink(fileQual, link, false);
+    assertEquals(fileQual, wrapper.getFileLinkStatus(link).getSymlink());
+    // Because the target was specified with an absolute path the
+    // link fails to resolve after moving the parent directory. 
+    wrapper.rename(dir, dirNew);
+    // The target is still the old path
+    assertEquals(fileQual, wrapper.getFileLinkStatus(linkNew).getSymlink());    
+    try {
+      readFile(linkNew);
+      fail("The link should be dangling now.");
+    } catch (FileNotFoundException x) {
+      // Expected.
+    }
+    // RawLocalFs only maintains the path part, not the URI, and
+    // therefore does not support links to other file systems.
+    Path anotherFs = new Path("hdfs://host:1000/dir/file");
+    FileUtil.fullyDelete(new File(linkNew.toString()));
+    try {
+      wrapper.createSymlink(anotherFs, linkNew, false);
+      fail("Created a local fs link to a non-local fs");
+    } catch (IOException x) {
+      // Excpected.
+    }
+  }
+}

Added: hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestSymlinkLocalFSFileContext.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestSymlinkLocalFSFileContext.java?rev=1512028&view=auto
==============================================================================
--- hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestSymlinkLocalFSFileContext.java (added)
+++ hadoop/common/branches/branch-2.1-beta/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestSymlinkLocalFSFileContext.java Thu Aug  8 21:05:10 2013
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.fs;
+
+import org.junit.BeforeClass;
+
+public class TestSymlinkLocalFSFileContext extends TestSymlinkLocalFS {
+
+  @BeforeClass
+  public static void testSetup() throws Exception {
+    FileContext context = FileContext.getLocalFSFileContext();
+    wrapper = new FileContextTestWrapper(context);
+  }
+
+}