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 vi...@apache.org on 2014/11/17 07:30:24 UTC

[22/45] hadoop git commit: HADOOP-8989. hadoop fs -find feature (Jonathan Allen via aw)

http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba879a5d/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestFind.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestFind.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestFind.java
new file mode 100644
index 0000000..7d79420
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestFind.java
@@ -0,0 +1,900 @@
+/**
+ * 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.shell.find;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+import static org.mockito.Matchers.*;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.shell.PathData;
+import org.apache.hadoop.fs.shell.find.BaseExpression;
+import org.apache.hadoop.fs.shell.find.Expression;
+import org.apache.hadoop.fs.shell.find.Find;
+import org.apache.hadoop.fs.shell.find.FindOptions;
+import org.apache.hadoop.fs.shell.find.Result;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+
+public class TestFind {
+  private static FileSystem mockFs;
+  private static Configuration conf;
+
+  @Before
+  public void setup() throws IOException {
+    mockFs = MockFileSystem.setup();
+    conf = mockFs.getConf();
+  }
+  
+  // check follow link option is recognized
+  @Test(timeout = 1000)
+  public void processOptionsFollowLink() throws IOException {
+    Find find = new Find();
+    String args = "-L path";
+    find.processOptions(getArgs(args));
+    assertTrue(find.getOptions().isFollowLink());
+    assertFalse(find.getOptions().isFollowArgLink());
+  }
+
+  // check follow arg link option is recognized
+  @Test(timeout = 1000)
+  public void processOptionsFollowArgLink() throws IOException {
+    Find find = new Find();
+    String args = "-H path";
+    find.processOptions(getArgs(args));
+    assertFalse(find.getOptions().isFollowLink());
+    assertTrue(find.getOptions().isFollowArgLink());
+  }
+
+  // check follow arg link option is recognized
+  @Test(timeout = 1000)
+  public void processOptionsFollowLinkFollowArgLink() throws IOException {
+    Find find = new Find();
+    String args = "-L -H path";
+    find.processOptions(getArgs(args));
+    assertTrue(find.getOptions().isFollowLink());
+    
+    // follow link option takes precedence over follow arg link
+    assertFalse(find.getOptions().isFollowArgLink());
+  }
+  
+  // check options and expressions are stripped from args leaving paths
+  @Test(timeout = 1000)
+  public void processOptionsExpression() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+
+    String paths = "path1 path2 path3";
+    String args = "-L -H " + paths + " -print -name test";
+    LinkedList<String> argsList = getArgs(args);
+    find.processOptions(argsList);
+    LinkedList<String> pathList = getArgs(paths);
+    assertEquals(pathList, argsList);
+  }
+
+  // check print is used as the default expression
+  @Test(timeout = 1000)
+  public void processOptionsNoExpression() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+    String args = "path";
+    String expected = "Print(;)";
+    find.processOptions(getArgs(args));
+    Expression expression = find.getRootExpression();
+    assertEquals(expected, expression.toString());
+  }
+
+  // check unknown options are rejected
+  @Test(timeout = 1000)
+  public void processOptionsUnknown() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+    String args = "path -unknown";
+    try {
+      find.processOptions(getArgs(args));
+      fail("Unknown expression not caught");
+    } catch (IOException e) {
+    }
+  }
+
+  // check unknown options are rejected when mixed with known options
+  @Test(timeout = 1000)
+  public void processOptionsKnownUnknown() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+    String args = "path -print -unknown -print";
+    try {
+      find.processOptions(getArgs(args));
+      fail("Unknown expression not caught");
+    } catch (IOException e) {
+    }
+  }
+
+  // check no path defaults to current working directory
+  @Test(timeout = 1000)
+  public void processOptionsNoPath() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+    String args = "-print";
+    
+    LinkedList<String> argsList = getArgs(args);
+    find.processOptions(argsList);
+    assertEquals(Collections.singletonList(Path.CUR_DIR), argsList);
+  }
+
+  // check -name is handled correctly
+  @Test(timeout = 1000)
+  public void processOptionsName() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+    String args = "path -name namemask";
+    String expected = "And(;Name(namemask;),Print(;))";
+    find.processOptions(getArgs(args));
+    Expression expression = find.getRootExpression();
+    assertEquals(expected, expression.toString());
+  }
+
+  // check -iname is handled correctly
+  @Test(timeout = 1000)
+  public void processOptionsIname() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+    String args = "path -iname namemask";
+    String expected = "And(;Iname-Name(namemask;),Print(;))";
+    find.processOptions(getArgs(args));
+    Expression expression = find.getRootExpression();
+    assertEquals(expected, expression.toString());
+  }
+
+  // check -print is handled correctly
+  @Test(timeout = 1000)
+  public void processOptionsPrint() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+    String args = "path -print";
+    String expected = "Print(;)";
+    find.processOptions(getArgs(args));
+    Expression expression = find.getRootExpression();
+    assertEquals(expected, expression.toString());
+  }
+
+  // check -print0 is handled correctly
+  @Test(timeout = 1000)
+  public void processOptionsPrint0() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+    String args = "path -print0";
+    String expected = "Print0-Print(;)";
+    find.processOptions(getArgs(args));
+    Expression expression = find.getRootExpression();
+    assertEquals(expected, expression.toString());
+  }
+
+  // check an implicit and is handled correctly
+  @Test(timeout = 1000)
+  public void processOptionsNoop() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+
+    String args = "path -name one -name two -print";
+    String expected = "And(;And(;Name(one;),Name(two;)),Print(;))";
+    find.processOptions(getArgs(args));
+    Expression expression = find.getRootExpression();
+    assertEquals(expected, expression.toString());
+  }
+
+  // check -a is handled correctly
+  @Test(timeout = 1000)
+  public void processOptionsA() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+
+    String args = "path -name one -a -name two -a -print";
+    String expected = "And(;And(;Name(one;),Name(two;)),Print(;))";
+    find.processOptions(getArgs(args));
+    Expression expression = find.getRootExpression();
+    assertEquals(expected, expression.toString());
+  }
+
+  // check -and is handled correctly
+  @Test(timeout = 1000)
+  public void processOptionsAnd() throws IOException {
+    Find find = new Find();
+    find.setConf(conf);
+
+    String args = "path -name one -and -name two -and -print";
+    String expected = "And(;And(;Name(one;),Name(two;)),Print(;))";
+    find.processOptions(getArgs(args));
+    Expression expression = find.getRootExpression();
+    assertEquals(expected, expression.toString());
+  }
+
+  // check expressions are called in the correct order
+  @Test(timeout = 1000)
+  public void processArguments() throws IOException {
+    LinkedList<PathData> items = createDirectories();
+
+    Find find = new Find();
+    find.setConf(conf);
+    PrintStream out = mock(PrintStream.class);
+    find.getOptions().setOut(out);
+    PrintStream err = mock(PrintStream.class);
+    find.getOptions().setErr(err);
+    Expression expr = mock(Expression.class);
+    when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS);
+    FileStatusChecker fsCheck = mock(FileStatusChecker.class);
+    Expression test = new TestExpression(expr, fsCheck);
+    find.setRootExpression(test);
+    find.processArguments(items);
+
+    InOrder inOrder = inOrder(expr);
+    inOrder.verify(expr).setOptions(find.getOptions());
+    inOrder.verify(expr).prepare();
+    inOrder.verify(expr).apply(item1, 0);
+    inOrder.verify(expr).apply(item1a, 1);
+    inOrder.verify(expr).apply(item1aa, 2);
+    inOrder.verify(expr).apply(item1b, 1);
+    inOrder.verify(expr).apply(item2, 0);
+    inOrder.verify(expr).apply(item3, 0);
+    inOrder.verify(expr).apply(item4, 0);
+    inOrder.verify(expr).apply(item5, 0);
+    inOrder.verify(expr).apply(item5a, 1);
+    inOrder.verify(expr).apply(item5b, 1);
+    inOrder.verify(expr).apply(item5c, 1);
+    inOrder.verify(expr).apply(item5ca, 2);
+    inOrder.verify(expr).apply(item5d, 1);
+    inOrder.verify(expr).apply(item5e, 1);
+    inOrder.verify(expr).finish();
+    verifyNoMoreInteractions(expr);
+
+    InOrder inOrderFsCheck = inOrder(fsCheck);
+    inOrderFsCheck.verify(fsCheck).check(item1.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1aa.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item2.stat);
+    inOrderFsCheck.verify(fsCheck).check(item3.stat);
+    inOrderFsCheck.verify(fsCheck).check(item4.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5c.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5ca.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5d.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5e.stat);
+    verifyNoMoreInteractions(fsCheck);
+
+    verifyNoMoreInteractions(out);
+    verifyNoMoreInteractions(err);
+  }
+
+  // check that directories are descended correctly when -depth is specified
+  @Test(timeout = 1000)
+  public void processArgumentsDepthFirst() throws IOException {
+    LinkedList<PathData> items = createDirectories();
+
+    Find find = new Find();
+    find.getOptions().setDepthFirst(true);
+    find.setConf(conf);
+    PrintStream out = mock(PrintStream.class);
+    find.getOptions().setOut(out);
+    PrintStream err = mock(PrintStream.class);
+    find.getOptions().setErr(err);
+    Expression expr = mock(Expression.class);
+    when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS);
+    FileStatusChecker fsCheck = mock(FileStatusChecker.class);
+    Expression test = new TestExpression(expr, fsCheck);
+    find.setRootExpression(test);
+    find.processArguments(items);
+
+    InOrder inOrder = inOrder(expr);
+    inOrder.verify(expr).setOptions(find.getOptions());
+    inOrder.verify(expr).prepare();
+    inOrder.verify(expr).apply(item1aa, 2);
+    inOrder.verify(expr).apply(item1a, 1);
+    inOrder.verify(expr).apply(item1b, 1);
+    inOrder.verify(expr).apply(item1, 0);
+    inOrder.verify(expr).apply(item2, 0);
+    inOrder.verify(expr).apply(item3, 0);
+    inOrder.verify(expr).apply(item4, 0);
+    inOrder.verify(expr).apply(item5a, 1);
+    inOrder.verify(expr).apply(item5b, 1);
+    inOrder.verify(expr).apply(item5ca, 2);
+    inOrder.verify(expr).apply(item5c, 1);
+    inOrder.verify(expr).apply(item5d, 1);
+    inOrder.verify(expr).apply(item5e, 1);
+    inOrder.verify(expr).apply(item5, 0);
+    inOrder.verify(expr).finish();
+    verifyNoMoreInteractions(expr);
+
+    InOrder inOrderFsCheck = inOrder(fsCheck);
+    inOrderFsCheck.verify(fsCheck).check(item1aa.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1.stat);
+    inOrderFsCheck.verify(fsCheck).check(item2.stat);
+    inOrderFsCheck.verify(fsCheck).check(item3.stat);
+    inOrderFsCheck.verify(fsCheck).check(item4.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5ca.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5c.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5d.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5e.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5.stat);
+    verifyNoMoreInteractions(fsCheck);
+
+    verifyNoMoreInteractions(out);
+    verifyNoMoreInteractions(err);
+  }
+
+  // check symlinks given as path arguments are processed correctly with the
+  // follow arg option set
+  @Test(timeout = 1000)
+  public void processArgumentsOptionFollowArg() throws IOException {
+    LinkedList<PathData> items = createDirectories();
+
+    Find find = new Find();
+    find.getOptions().setFollowArgLink(true);
+    find.setConf(conf);
+    PrintStream out = mock(PrintStream.class);
+    find.getOptions().setOut(out);
+    PrintStream err = mock(PrintStream.class);
+    find.getOptions().setErr(err);
+    Expression expr = mock(Expression.class);
+    when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS);
+    FileStatusChecker fsCheck = mock(FileStatusChecker.class);
+    Expression test = new TestExpression(expr, fsCheck);
+    find.setRootExpression(test);
+    find.processArguments(items);
+
+    InOrder inOrder = inOrder(expr);
+    inOrder.verify(expr).setOptions(find.getOptions());
+    inOrder.verify(expr).prepare();
+    inOrder.verify(expr).apply(item1, 0);
+    inOrder.verify(expr).apply(item1a, 1);
+    inOrder.verify(expr).apply(item1aa, 2);
+    inOrder.verify(expr).apply(item1b, 1);
+    inOrder.verify(expr).apply(item2, 0);
+    inOrder.verify(expr).apply(item3, 0);
+    inOrder.verify(expr).apply(item4, 0);
+    inOrder.verify(expr).apply(item5, 0);
+    inOrder.verify(expr).apply(item5a, 1);
+    inOrder.verify(expr).apply(item5b, 1);
+    inOrder.verify(expr).apply(item5c, 1);
+    inOrder.verify(expr).apply(item5ca, 2);
+    inOrder.verify(expr).apply(item5d, 1);
+    inOrder.verify(expr).apply(item5e, 1);
+    inOrder.verify(expr).finish();
+    verifyNoMoreInteractions(expr);
+
+    InOrder inOrderFsCheck = inOrder(fsCheck);
+    inOrderFsCheck.verify(fsCheck).check(item1.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1aa.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item2.stat);
+    inOrderFsCheck.verify(fsCheck, times(2)).check(item3.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5c.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5ca.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5d.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5e.stat);
+    verifyNoMoreInteractions(fsCheck);
+
+    verifyNoMoreInteractions(out);
+    verifyNoMoreInteractions(err);
+  }
+
+  // check symlinks given as path arguments are processed correctly with the
+  // follow option
+  @Test(timeout = 1000)
+  public void processArgumentsOptionFollow() throws IOException {
+    LinkedList<PathData> items = createDirectories();
+
+    Find find = new Find();
+    find.getOptions().setFollowLink(true);
+    find.setConf(conf);
+    PrintStream out = mock(PrintStream.class);
+    find.getOptions().setOut(out);
+    PrintStream err = mock(PrintStream.class);
+    find.getOptions().setErr(err);
+    Expression expr = mock(Expression.class);
+    when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS);
+    FileStatusChecker fsCheck = mock(FileStatusChecker.class);
+    Expression test = new TestExpression(expr, fsCheck);
+    find.setRootExpression(test);
+    find.processArguments(items);
+
+    InOrder inOrder = inOrder(expr);
+    inOrder.verify(expr).setOptions(find.getOptions());
+    inOrder.verify(expr).prepare();
+    inOrder.verify(expr).apply(item1, 0);
+    inOrder.verify(expr).apply(item1a, 1);
+    inOrder.verify(expr).apply(item1aa, 2);
+    inOrder.verify(expr).apply(item1b, 1);
+    inOrder.verify(expr).apply(item2, 0);
+    inOrder.verify(expr).apply(item3, 0);
+    inOrder.verify(expr).apply(item4, 0);
+    inOrder.verify(expr).apply(item5, 0);
+    inOrder.verify(expr).apply(item5a, 1);
+    inOrder.verify(expr).apply(item5b, 1); // triggers infinite loop message
+    inOrder.verify(expr).apply(item5c, 1);
+    inOrder.verify(expr).apply(item5ca, 2);
+    inOrder.verify(expr).apply(item5d, 1);
+    inOrder.verify(expr).apply(item5ca, 2); // following item5d symlink
+    inOrder.verify(expr).apply(item5e, 1);
+    inOrder.verify(expr).finish();
+    verifyNoMoreInteractions(expr);
+
+    InOrder inOrderFsCheck = inOrder(fsCheck);
+    inOrderFsCheck.verify(fsCheck).check(item1.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1aa.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item2.stat);
+    inOrderFsCheck.verify(fsCheck, times(2)).check(item3.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5c.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5ca.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5c.stat);
+    inOrderFsCheck.verify(fsCheck, times(2)).check(item5ca.stat);
+    verifyNoMoreInteractions(fsCheck);
+
+    verifyNoMoreInteractions(out);
+    verify(err).println(
+        "Infinite loop ignored: " + item5b.toString() + " -> "
+            + item5.toString());
+    verifyNoMoreInteractions(err);
+  }
+
+  // check minimum depth is handledfollowLink
+  @Test(timeout = 1000)
+  public void processArgumentsMinDepth() throws IOException {
+    LinkedList<PathData> items = createDirectories();
+
+    Find find = new Find();
+    find.getOptions().setMinDepth(1);
+    find.setConf(conf);
+    PrintStream out = mock(PrintStream.class);
+    find.getOptions().setOut(out);
+    PrintStream err = mock(PrintStream.class);
+    find.getOptions().setErr(err);
+    Expression expr = mock(Expression.class);
+    when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS);
+    FileStatusChecker fsCheck = mock(FileStatusChecker.class);
+    Expression test = new TestExpression(expr, fsCheck);
+    find.setRootExpression(test);
+    find.processArguments(items);
+
+    InOrder inOrder = inOrder(expr);
+    inOrder.verify(expr).setOptions(find.getOptions());
+    inOrder.verify(expr).prepare();
+    inOrder.verify(expr).apply(item1a, 1);
+    inOrder.verify(expr).apply(item1aa, 2);
+    inOrder.verify(expr).apply(item1b, 1);
+    inOrder.verify(expr).apply(item5a, 1);
+    inOrder.verify(expr).apply(item5b, 1);
+    inOrder.verify(expr).apply(item5c, 1);
+    inOrder.verify(expr).apply(item5ca, 2);
+    inOrder.verify(expr).apply(item5d, 1);
+    inOrder.verify(expr).apply(item5e, 1);
+    inOrder.verify(expr).finish();
+    verifyNoMoreInteractions(expr);
+
+    InOrder inOrderFsCheck = inOrder(fsCheck);
+    inOrderFsCheck.verify(fsCheck).check(item1a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1aa.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5c.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5ca.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5d.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5e.stat);
+    verifyNoMoreInteractions(fsCheck);
+
+    verifyNoMoreInteractions(out);
+    verifyNoMoreInteractions(err);
+  }
+
+  // check maximum depth is handled
+  @Test(timeout = 1000)
+  public void processArgumentsMaxDepth() throws IOException {
+    LinkedList<PathData> items = createDirectories();
+
+    Find find = new Find();
+    find.getOptions().setMaxDepth(1);
+    find.setConf(conf);
+    PrintStream out = mock(PrintStream.class);
+    find.getOptions().setOut(out);
+    PrintStream err = mock(PrintStream.class);
+    find.getOptions().setErr(err);
+    Expression expr = mock(Expression.class);
+    when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS);
+    FileStatusChecker fsCheck = mock(FileStatusChecker.class);
+    Expression test = new TestExpression(expr, fsCheck);
+    find.setRootExpression(test);
+    find.processArguments(items);
+
+    InOrder inOrder = inOrder(expr);
+    inOrder.verify(expr).setOptions(find.getOptions());
+    inOrder.verify(expr).prepare();
+    inOrder.verify(expr).apply(item1, 0);
+    inOrder.verify(expr).apply(item1a, 1);
+    inOrder.verify(expr).apply(item1b, 1);
+    inOrder.verify(expr).apply(item2, 0);
+    inOrder.verify(expr).apply(item3, 0);
+    inOrder.verify(expr).apply(item4, 0);
+    inOrder.verify(expr).apply(item5, 0);
+    inOrder.verify(expr).apply(item5a, 1);
+    inOrder.verify(expr).apply(item5b, 1);
+    inOrder.verify(expr).apply(item5c, 1);
+    inOrder.verify(expr).apply(item5d, 1);
+    inOrder.verify(expr).apply(item5e, 1);
+    inOrder.verify(expr).finish();
+    verifyNoMoreInteractions(expr);
+
+    InOrder inOrderFsCheck = inOrder(fsCheck);
+    inOrderFsCheck.verify(fsCheck).check(item1.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item2.stat);
+    inOrderFsCheck.verify(fsCheck).check(item3.stat);
+    inOrderFsCheck.verify(fsCheck).check(item4.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5c.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5d.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5e.stat);
+    verifyNoMoreInteractions(fsCheck);
+
+    verifyNoMoreInteractions(out);
+    verifyNoMoreInteractions(err);
+  }
+
+  // check min depth is handled when -depth is specified
+  @Test(timeout = 1000)
+  public void processArgumentsDepthFirstMinDepth() throws IOException {
+    LinkedList<PathData> items = createDirectories();
+
+    Find find = new Find();
+    find.getOptions().setDepthFirst(true);
+    find.getOptions().setMinDepth(1);
+    find.setConf(conf);
+    PrintStream out = mock(PrintStream.class);
+    find.getOptions().setOut(out);
+    PrintStream err = mock(PrintStream.class);
+    find.getOptions().setErr(err);
+    Expression expr = mock(Expression.class);
+    when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS);
+    FileStatusChecker fsCheck = mock(FileStatusChecker.class);
+    Expression test = new TestExpression(expr, fsCheck);
+    find.setRootExpression(test);
+    find.processArguments(items);
+
+    InOrder inOrder = inOrder(expr);
+    inOrder.verify(expr).setOptions(find.getOptions());
+    inOrder.verify(expr).prepare();
+    inOrder.verify(expr).apply(item1aa, 2);
+    inOrder.verify(expr).apply(item1a, 1);
+    inOrder.verify(expr).apply(item1b, 1);
+    inOrder.verify(expr).apply(item5a, 1);
+    inOrder.verify(expr).apply(item5b, 1);
+    inOrder.verify(expr).apply(item5ca, 2);
+    inOrder.verify(expr).apply(item5c, 1);
+    inOrder.verify(expr).apply(item5d, 1);
+    inOrder.verify(expr).apply(item5e, 1);
+    inOrder.verify(expr).finish();
+    verifyNoMoreInteractions(expr);
+
+    InOrder inOrderFsCheck = inOrder(fsCheck);
+    inOrderFsCheck.verify(fsCheck).check(item1aa.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5ca.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5c.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5d.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5e.stat);
+    verifyNoMoreInteractions(fsCheck);
+
+    verifyNoMoreInteractions(out);
+    verifyNoMoreInteractions(err);
+  }
+
+  // check max depth is handled when -depth is specified
+  @Test(timeout = 1000)
+  public void processArgumentsDepthFirstMaxDepth() throws IOException {
+    LinkedList<PathData> items = createDirectories();
+
+    Find find = new Find();
+    find.getOptions().setDepthFirst(true);
+    find.getOptions().setMaxDepth(1);
+    find.setConf(conf);
+    PrintStream out = mock(PrintStream.class);
+    find.getOptions().setOut(out);
+    PrintStream err = mock(PrintStream.class);
+    find.getOptions().setErr(err);
+    Expression expr = mock(Expression.class);
+    when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS);
+    FileStatusChecker fsCheck = mock(FileStatusChecker.class);
+    Expression test = new TestExpression(expr, fsCheck);
+    find.setRootExpression(test);
+    find.processArguments(items);
+
+    InOrder inOrder = inOrder(expr);
+    inOrder.verify(expr).setOptions(find.getOptions());
+    inOrder.verify(expr).prepare();
+    inOrder.verify(expr).apply(item1a, 1);
+    inOrder.verify(expr).apply(item1b, 1);
+    inOrder.verify(expr).apply(item1, 0);
+    inOrder.verify(expr).apply(item2, 0);
+    inOrder.verify(expr).apply(item3, 0);
+    inOrder.verify(expr).apply(item4, 0);
+    inOrder.verify(expr).apply(item5a, 1);
+    inOrder.verify(expr).apply(item5b, 1);
+    inOrder.verify(expr).apply(item5c, 1);
+    inOrder.verify(expr).apply(item5d, 1);
+    inOrder.verify(expr).apply(item5e, 1);
+    inOrder.verify(expr).apply(item5, 0);
+    inOrder.verify(expr).finish();
+    verifyNoMoreInteractions(expr);
+
+    InOrder inOrderFsCheck = inOrder(fsCheck);
+    inOrderFsCheck.verify(fsCheck).check(item1a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1.stat);
+    inOrderFsCheck.verify(fsCheck).check(item2.stat);
+    inOrderFsCheck.verify(fsCheck).check(item3.stat);
+    inOrderFsCheck.verify(fsCheck).check(item4.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5c.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5d.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5e.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5.stat);
+    verifyNoMoreInteractions(fsCheck);
+
+    verifyNoMoreInteractions(out);
+    verifyNoMoreInteractions(err);
+  }
+
+  // check expressions are called in the correct order
+  @Test(timeout = 1000)
+  public void processArgumentsNoDescend() throws IOException {
+    LinkedList<PathData> items = createDirectories();
+
+    Find find = new Find();
+    find.setConf(conf);
+    PrintStream out = mock(PrintStream.class);
+    find.getOptions().setOut(out);
+    PrintStream err = mock(PrintStream.class);
+    find.getOptions().setErr(err);
+    Expression expr = mock(Expression.class);
+    when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS);
+    when(expr.apply(eq(item1a), anyInt())).thenReturn(Result.STOP);
+    FileStatusChecker fsCheck = mock(FileStatusChecker.class);
+    Expression test = new TestExpression(expr, fsCheck);
+    find.setRootExpression(test);
+    find.processArguments(items);
+
+    InOrder inOrder = inOrder(expr);
+    inOrder.verify(expr).setOptions(find.getOptions());
+    inOrder.verify(expr).prepare();
+    inOrder.verify(expr).apply(item1, 0);
+    inOrder.verify(expr).apply(item1a, 1);
+    inOrder.verify(expr).apply(item1b, 1);
+    inOrder.verify(expr).apply(item2, 0);
+    inOrder.verify(expr).apply(item3, 0);
+    inOrder.verify(expr).apply(item4, 0);
+    inOrder.verify(expr).apply(item5, 0);
+    inOrder.verify(expr).apply(item5a, 1);
+    inOrder.verify(expr).apply(item5b, 1);
+    inOrder.verify(expr).apply(item5c, 1);
+    inOrder.verify(expr).apply(item5ca, 2);
+    inOrder.verify(expr).apply(item5d, 1);
+    inOrder.verify(expr).apply(item5e, 1);
+    inOrder.verify(expr).finish();
+    verifyNoMoreInteractions(expr);
+
+    InOrder inOrderFsCheck = inOrder(fsCheck);
+    inOrderFsCheck.verify(fsCheck).check(item1.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item1b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item2.stat);
+    inOrderFsCheck.verify(fsCheck).check(item3.stat);
+    inOrderFsCheck.verify(fsCheck).check(item4.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5a.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5b.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5c.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5ca.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5d.stat);
+    inOrderFsCheck.verify(fsCheck).check(item5e.stat);
+    verifyNoMoreInteractions(fsCheck);
+
+    verifyNoMoreInteractions(out);
+    verifyNoMoreInteractions(err);
+  }
+
+  private interface FileStatusChecker {
+    public void check(FileStatus fileStatus);
+  }
+
+  private class TestExpression extends BaseExpression implements Expression {
+    private Expression expr;
+    private FileStatusChecker checker;
+    public TestExpression(Expression expr, FileStatusChecker checker) {
+      this.expr = expr;
+      this.checker = checker;
+    }
+    @Override
+    public Result apply(PathData item, int depth) throws IOException {
+      FileStatus fileStatus = getFileStatus(item, depth);
+      checker.check(fileStatus);
+      return expr.apply(item, depth);
+    }
+    @Override
+    public void setOptions(FindOptions options) throws IOException {
+      super.setOptions(options);
+      expr.setOptions(options);
+    }
+    @Override
+    public void prepare() throws IOException {
+      expr.prepare();
+    }
+    @Override
+    public void finish() throws IOException {
+      expr.finish();
+    }
+  }
+
+  // creates a directory structure for traversal
+  // item1 (directory)
+  // \- item1a (directory)
+  //    \- item1aa (file)
+  // \- item1b (file)
+  // item2 (directory)
+  // item3 (file)
+  // item4 (link) -> item3
+  // item5 (directory)
+  // \- item5a (link) -> item1b
+  // \- item5b (link) -> item5 (infinite loop)
+  // \- item5c (directory)
+  //    \- item5ca (file)
+  // \- item5d (link) -> item5c
+  // \- item5e (link) -> item5c/item5ca
+  private PathData item1 = null;
+  private PathData item1a = null;
+  private PathData item1aa = null;
+  private PathData item1b = null;
+  private PathData item2 = null;
+  private PathData item3 = null;
+  private PathData item4 = null;
+  private PathData item5 = null;
+  private PathData item5a = null;
+  private PathData item5b = null;
+  private PathData item5c = null;
+  private PathData item5ca = null;
+  private PathData item5d = null;
+  private PathData item5e = null;
+
+  private LinkedList<PathData> createDirectories() throws IOException {
+    item1 = createPathData("item1");
+    item1a = createPathData("item1/item1a");
+    item1aa = createPathData("item1/item1a/item1aa");
+    item1b = createPathData("item1/item1b");
+    item2 = createPathData("item2");
+    item3 = createPathData("item3");
+    item4 = createPathData("item4");
+    item5 = createPathData("item5");
+    item5a = createPathData("item5/item5a");
+    item5b = createPathData("item5/item5b");
+    item5c = createPathData("item5/item5c");
+    item5ca = createPathData("item5/item5c/item5ca");
+    item5d = createPathData("item5/item5d");
+    item5e = createPathData("item5/item5e");
+
+    LinkedList<PathData> args = new LinkedList<PathData>();
+
+    when(item1.stat.isDirectory()).thenReturn(true);
+    when(item1a.stat.isDirectory()).thenReturn(true);
+    when(item1aa.stat.isDirectory()).thenReturn(false);
+    when(item1b.stat.isDirectory()).thenReturn(false);
+    when(item2.stat.isDirectory()).thenReturn(true);
+    when(item3.stat.isDirectory()).thenReturn(false);
+    when(item4.stat.isDirectory()).thenReturn(false);
+    when(item5.stat.isDirectory()).thenReturn(true);
+    when(item5a.stat.isDirectory()).thenReturn(false);
+    when(item5b.stat.isDirectory()).thenReturn(false);
+    when(item5c.stat.isDirectory()).thenReturn(true);
+    when(item5ca.stat.isDirectory()).thenReturn(false);
+    when(item5d.stat.isDirectory()).thenReturn(false);
+    when(item5e.stat.isDirectory()).thenReturn(false);
+
+    when(mockFs.listStatus(eq(item1.path))).thenReturn(
+        new FileStatus[] { item1a.stat, item1b.stat });
+    when(mockFs.listStatus(eq(item1a.path))).thenReturn(
+        new FileStatus[] { item1aa.stat });
+    when(mockFs.listStatus(eq(item2.path))).thenReturn(new FileStatus[0]);
+    when(mockFs.listStatus(eq(item5.path))).thenReturn(
+        new FileStatus[] { item5a.stat, item5b.stat, item5c.stat, item5d.stat,
+            item5e.stat });
+    when(mockFs.listStatus(eq(item5c.path))).thenReturn(
+        new FileStatus[] { item5ca.stat });
+
+    when(item1.stat.isSymlink()).thenReturn(false);
+    when(item1a.stat.isSymlink()).thenReturn(false);
+    when(item1aa.stat.isSymlink()).thenReturn(false);
+    when(item1b.stat.isSymlink()).thenReturn(false);
+    when(item2.stat.isSymlink()).thenReturn(false);
+    when(item3.stat.isSymlink()).thenReturn(false);
+    when(item4.stat.isSymlink()).thenReturn(true);
+    when(item5.stat.isSymlink()).thenReturn(false);
+    when(item5a.stat.isSymlink()).thenReturn(true);
+    when(item5b.stat.isSymlink()).thenReturn(true);
+    when(item5d.stat.isSymlink()).thenReturn(true);
+    when(item5e.stat.isSymlink()).thenReturn(true);
+
+    when(item4.stat.getSymlink()).thenReturn(item3.path);
+    when(item5a.stat.getSymlink()).thenReturn(item1b.path);
+    when(item5b.stat.getSymlink()).thenReturn(item5.path);
+    when(item5d.stat.getSymlink()).thenReturn(item5c.path);
+    when(item5e.stat.getSymlink()).thenReturn(item5ca.path);
+
+    args.add(item1);
+    args.add(item2);
+    args.add(item3);
+    args.add(item4);
+    args.add(item5);
+
+    return args;
+  }
+
+  private PathData createPathData(String name) throws IOException {
+    Path path = new Path(name);
+    FileStatus fstat = mock(FileStatus.class);
+    when(fstat.getPath()).thenReturn(path);
+    when(fstat.toString()).thenReturn("fileStatus:" + name);
+
+    when(mockFs.getFileStatus(eq(path))).thenReturn(fstat);
+    PathData item = new PathData(path.toString(), conf);
+    return item;
+  }
+
+  private LinkedList<String> getArgs(String cmd) {
+    return new LinkedList<String>(Arrays.asList(cmd.split(" ")));
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba879a5d/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestHelper.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestHelper.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestHelper.java
new file mode 100644
index 0000000..d4866b5
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestHelper.java
@@ -0,0 +1,35 @@
+/**
+ * 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.shell.find;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+
+/** Helper methods for the find expression unit tests. */
+class TestHelper {
+  /** Adds an argument string to an expression */
+  static void addArgument(Expression expr, String arg) {
+    expr.addArguments(new LinkedList<String>(Collections.singletonList(arg)));
+  }
+
+  /** Converts a command string into a list of arguments. */
+  static LinkedList<String> getArgs(String cmd) {
+    return new LinkedList<String>(Arrays.asList(cmd.split(" ")));
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba879a5d/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestIname.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestIname.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestIname.java
new file mode 100644
index 0000000..6e42fce
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestIname.java
@@ -0,0 +1,93 @@
+/**
+ * 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.shell.find;
+
+import static org.junit.Assert.*;
+import static org.apache.hadoop.fs.shell.find.TestHelper.*;
+
+import java.io.IOException;
+
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.shell.PathData;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestIname {
+  private FileSystem mockFs;
+  private Name.Iname name;
+
+  @Before
+  public void resetMock() throws IOException {
+    mockFs = MockFileSystem.setup();
+  }
+
+  private void setup(String arg) throws IOException {
+    name = new Name.Iname();
+    addArgument(name, arg);
+    name.setOptions(new FindOptions());
+    name.prepare();
+  }
+
+  // test a matching name (same case)
+  @Test(timeout = 1000)
+  public void applyMatch() throws IOException {
+    setup("name");
+    PathData item = new PathData("/directory/path/name", mockFs.getConf());
+    assertEquals(Result.PASS, name.apply(item, -1));
+  }
+
+  // test a non-matching name
+  @Test(timeout = 1000)
+  public void applyNotMatch() throws IOException {
+    setup("name");
+    PathData item = new PathData("/directory/path/notname", mockFs.getConf());
+    assertEquals(Result.FAIL, name.apply(item, -1));
+  }
+
+  // test a matching name (different case)
+  @Test(timeout = 1000)
+  public void applyMixedCase() throws IOException {
+    setup("name");
+    PathData item = new PathData("/directory/path/NaMe", mockFs.getConf());
+    assertEquals(Result.PASS, name.apply(item, -1));
+  }
+
+  // test a matching glob pattern (same case)
+  @Test(timeout = 1000)
+  public void applyGlob() throws IOException {
+    setup("n*e");
+    PathData item = new PathData("/directory/path/name", mockFs.getConf());
+    assertEquals(Result.PASS, name.apply(item, -1));
+  }
+
+  // test a matching glob pattern (different case)
+  @Test(timeout = 1000)
+  public void applyGlobMixedCase() throws IOException {
+    setup("n*e");
+    PathData item = new PathData("/directory/path/NaMe", mockFs.getConf());
+    assertEquals(Result.PASS, name.apply(item, -1));
+  }
+
+  // test a non-matching glob pattern
+  @Test(timeout = 1000)
+  public void applyGlobNotMatch() throws IOException {
+    setup("n*e");
+    PathData item = new PathData("/directory/path/notmatch", mockFs.getConf());
+    assertEquals(Result.FAIL, name.apply(item, -1));
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba879a5d/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestName.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestName.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestName.java
new file mode 100644
index 0000000..2c77fe1
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestName.java
@@ -0,0 +1,93 @@
+/**
+ * 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.shell.find;
+
+import static org.junit.Assert.*;
+import static org.apache.hadoop.fs.shell.find.TestHelper.*;
+
+import java.io.IOException;
+
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.shell.PathData;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestName {
+  private FileSystem mockFs;
+  private Name name;
+
+  @Before
+  public void resetMock() throws IOException {
+    mockFs = MockFileSystem.setup();
+  }
+
+  private void setup(String arg) throws IOException {
+    name = new Name();
+    addArgument(name, arg);
+    name.setOptions(new FindOptions());
+    name.prepare();
+  }
+
+  // test a matching name
+  @Test(timeout = 1000)
+  public void applyMatch() throws IOException {
+    setup("name");
+    PathData item = new PathData("/directory/path/name", mockFs.getConf());
+    assertEquals(Result.PASS, name.apply(item, -1));
+  }
+
+  // test a non-matching name
+  @Test(timeout = 1000)
+  public void applyNotMatch() throws IOException {
+    setup("name");
+    PathData item = new PathData("/directory/path/notname", mockFs.getConf());
+    assertEquals(Result.FAIL, name.apply(item, -1));
+  }
+
+  // test a different case name
+  @Test(timeout = 1000)
+  public void applyMixedCase() throws IOException {
+    setup("name");
+    PathData item = new PathData("/directory/path/NaMe", mockFs.getConf());
+    assertEquals(Result.FAIL, name.apply(item, -1));
+  }
+
+  // test a matching glob pattern
+  @Test(timeout = 1000)
+  public void applyGlob() throws IOException {
+    setup("n*e");
+    PathData item = new PathData("/directory/path/name", mockFs.getConf());
+    assertEquals(Result.PASS, name.apply(item, -1));
+  }
+
+  // test a glob pattern with different case
+  @Test(timeout = 1000)
+  public void applyGlobMixedCase() throws IOException {
+    setup("n*e");
+    PathData item = new PathData("/directory/path/NaMe", mockFs.getConf());
+    assertEquals(Result.FAIL, name.apply(item, -1));
+  }
+
+  // test a non-matching glob pattern
+  @Test(timeout = 1000)
+  public void applyGlobNotMatch() throws IOException {
+    setup("n*e");
+    PathData item = new PathData("/directory/path/notmatch", mockFs.getConf());
+    assertEquals(Result.FAIL, name.apply(item, -1));
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba879a5d/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestPrint.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestPrint.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestPrint.java
new file mode 100644
index 0000000..2d27665
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestPrint.java
@@ -0,0 +1,56 @@
+/**
+ * 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.shell.find;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.io.IOException;
+
+import org.apache.hadoop.fs.shell.PathData;
+import org.junit.Test;
+
+import java.io.PrintStream;
+
+import org.apache.hadoop.fs.FileSystem;
+import org.junit.Before;
+
+public class TestPrint {
+  private FileSystem mockFs;
+
+  @Before
+  public void resetMock() throws IOException {
+    mockFs = MockFileSystem.setup();
+  }
+
+  // test the full path is printed to stdout
+  @Test(timeout = 1000)
+  public void testPrint() throws IOException {
+    Print print = new Print();
+    PrintStream out = mock(PrintStream.class);
+    FindOptions options = new FindOptions();
+    options.setOut(out);
+    print.setOptions(options);
+
+    String filename = "/one/two/test";
+    PathData item = new PathData(filename, mockFs.getConf());
+    assertEquals(Result.PASS, print.apply(item, -1));
+    verify(out).print(filename + '\n');
+    verifyNoMoreInteractions(out);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba879a5d/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestPrint0.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestPrint0.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestPrint0.java
new file mode 100644
index 0000000..3b89438
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestPrint0.java
@@ -0,0 +1,56 @@
+/**
+ * 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.shell.find;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.io.IOException;
+
+import org.apache.hadoop.fs.shell.PathData;
+import org.junit.Test;
+
+import java.io.PrintStream;
+
+import org.apache.hadoop.fs.FileSystem;
+import org.junit.Before;
+
+public class TestPrint0 {
+  private FileSystem mockFs;
+
+  @Before
+  public void resetMock() throws IOException {
+    mockFs = MockFileSystem.setup();
+  }
+
+  // test the full path is printed to stdout with a '\0'
+  @Test(timeout = 1000)
+  public void testPrint() throws IOException {
+    Print.Print0 print = new Print.Print0();
+    PrintStream out = mock(PrintStream.class);
+    FindOptions options = new FindOptions();
+    options.setOut(out);
+    print.setOptions(options);
+
+    String filename = "/one/two/test";
+    PathData item = new PathData(filename, mockFs.getConf());
+    assertEquals(Result.PASS, print.apply(item, -1));
+    verify(out).print(filename + '\0');
+    verifyNoMoreInteractions(out);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba879a5d/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestResult.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestResult.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestResult.java
new file mode 100644
index 0000000..1139220
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestResult.java
@@ -0,0 +1,172 @@
+/**
+ * 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.shell.find;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class TestResult {
+
+  // test the PASS value
+  @Test(timeout = 1000)
+  public void testPass() {
+    Result result = Result.PASS;
+    assertTrue(result.isPass());
+    assertTrue(result.isDescend());
+  }
+
+  // test the FAIL value
+  @Test(timeout = 1000)
+  public void testFail() {
+    Result result = Result.FAIL;
+    assertFalse(result.isPass());
+    assertTrue(result.isDescend());
+  }
+
+  // test the STOP value
+  @Test(timeout = 1000)
+  public void testStop() {
+    Result result = Result.STOP;
+    assertTrue(result.isPass());
+    assertFalse(result.isDescend());
+  }
+
+  // test combine method with two PASSes
+  @Test(timeout = 1000)
+  public void combinePassPass() {
+    Result result = Result.PASS.combine(Result.PASS);
+    assertTrue(result.isPass());
+    assertTrue(result.isDescend());
+  }
+
+  // test the combine method with a PASS and a FAIL
+  @Test(timeout = 1000)
+  public void combinePassFail() {
+    Result result = Result.PASS.combine(Result.FAIL);
+    assertFalse(result.isPass());
+    assertTrue(result.isDescend());
+  }
+
+  // test the combine method with a FAIL and a PASS
+  @Test(timeout = 1000)
+  public void combineFailPass() {
+    Result result = Result.FAIL.combine(Result.PASS);
+    assertFalse(result.isPass());
+    assertTrue(result.isDescend());
+  }
+
+  // test the combine method with two FAILs
+  @Test(timeout = 1000)
+  public void combineFailFail() {
+    Result result = Result.FAIL.combine(Result.FAIL);
+    assertFalse(result.isPass());
+    assertTrue(result.isDescend());
+  }
+
+  // test the combine method with a PASS and STOP
+  @Test(timeout = 1000)
+  public void combinePassStop() {
+    Result result = Result.PASS.combine(Result.STOP);
+    assertTrue(result.isPass());
+    assertFalse(result.isDescend());
+  }
+
+  // test the combine method with a STOP and FAIL
+  @Test(timeout = 1000)
+  public void combineStopFail() {
+    Result result = Result.STOP.combine(Result.FAIL);
+    assertFalse(result.isPass());
+    assertFalse(result.isDescend());
+  }
+
+  // test the combine method with a STOP and a PASS
+  @Test(timeout = 1000)
+  public void combineStopPass() {
+    Result result = Result.STOP.combine(Result.PASS);
+    assertTrue(result.isPass());
+    assertFalse(result.isDescend());
+  }
+
+  // test the combine method with a FAIL and a STOP
+  @Test(timeout = 1000)
+  public void combineFailStop() {
+    Result result = Result.FAIL.combine(Result.STOP);
+    assertFalse(result.isPass());
+    assertFalse(result.isDescend());
+  }
+
+  // test the negation of PASS
+  @Test(timeout = 1000)
+  public void negatePass() {
+    Result result = Result.PASS.negate();
+    assertFalse(result.isPass());
+    assertTrue(result.isDescend());
+  }
+
+  // test the negation of FAIL
+  @Test(timeout = 1000)
+  public void negateFail() {
+    Result result = Result.FAIL.negate();
+    assertTrue(result.isPass());
+    assertTrue(result.isDescend());
+  }
+
+  // test the negation of STOP
+  @Test(timeout = 1000)
+  public void negateStop() {
+    Result result = Result.STOP.negate();
+    assertFalse(result.isPass());
+    assertFalse(result.isDescend());
+  }
+
+  // test equals with two PASSes
+  @Test(timeout = 1000)
+  public void equalsPass() {
+    Result one = Result.PASS;
+    Result two = Result.PASS.combine(Result.PASS);
+    assertEquals(one, two);
+  }
+
+  // test equals with two FAILs
+  @Test(timeout = 1000)
+  public void equalsFail() {
+    Result one = Result.FAIL;
+    Result two = Result.FAIL.combine(Result.FAIL);
+    assertEquals(one, two);
+  }
+
+  // test equals with two STOPS
+  @Test(timeout = 1000)
+  public void equalsStop() {
+    Result one = Result.STOP;
+    Result two = Result.STOP.combine(Result.STOP);
+    assertEquals(one, two);
+  }
+
+  // test all combinations of not equals
+  @Test(timeout = 1000)
+  public void notEquals() {
+    assertFalse(Result.PASS.equals(Result.FAIL));
+    assertFalse(Result.PASS.equals(Result.STOP));
+    assertFalse(Result.FAIL.equals(Result.PASS));
+    assertFalse(Result.FAIL.equals(Result.STOP));
+    assertFalse(Result.STOP.equals(Result.PASS));
+    assertFalse(Result.STOP.equals(Result.FAIL));
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba879a5d/hadoop-common-project/hadoop-common/src/test/resources/testConf.xml
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/resources/testConf.xml b/hadoop-common-project/hadoop-common/src/test/resources/testConf.xml
index dcf8fb4..5196641 100644
--- a/hadoop-common-project/hadoop-common/src/test/resources/testConf.xml
+++ b/hadoop-common-project/hadoop-common/src/test/resources/testConf.xml
@@ -964,6 +964,50 @@
     </test>
 
     <test> <!-- TESTED -->
+      <description>help: help for find</description>
+      <test-commands>
+        <command>-help find</command>
+      </test-commands>
+      <cleanup-commands>
+      </cleanup-commands>
+      <comparators>
+        <comparator>
+          <type>RegexpAcrossOutputComparator</type>
+          <expected-output>-find &lt;path&gt; \.\.\. &lt;expression&gt; \.\.\. :
+  Finds all files that match the specified expression and
+  applies selected actions to them\. If no &lt;path&gt; is specified
+  then defaults to the current working directory\. If no
+  expression is specified then defaults to -print\.
+  
+  The following primary expressions are recognised:
+    -name pattern
+    -iname pattern
+      Evaluates as true if the basename of the file matches the
+      pattern using standard file system globbing\.
+      If -iname is used then the match is case insensitive\.
+  
+    -print
+    -print0
+      Always evaluates to true. Causes the current pathname to be
+      written to standard output followed by a newline. If the -print0
+      expression is used then an ASCII NULL character is appended rather
+      than a newline.
+  
+  The following operators are recognised:
+    expression -a expression
+    expression -and expression
+    expression expression
+      Logical AND operator for joining two expressions\. Returns
+      true if both child expressions return true\. Implied by the
+      juxtaposition of two expressions and so does not need to be
+      explicitly specified\. The second expression will not be
+      applied if the first fails\.
+</expected-output>	
+        </comparator>
+      </comparators>
+    </test>
+
+    <test> <!-- TESTED -->
       <description>help: help for help</description>
       <test-commands>
         <command>-help help</command>

http://git-wip-us.apache.org/repos/asf/hadoop/blob/ba879a5d/hadoop-hdfs-project/hadoop-hdfs/src/test/resources/testHDFSConf.xml
----------------------------------------------------------------------
diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/resources/testHDFSConf.xml b/hadoop-hdfs-project/hadoop-hdfs/src/test/resources/testHDFSConf.xml
index 8939f87..c86b06d 100644
--- a/hadoop-hdfs-project/hadoop-hdfs/src/test/resources/testHDFSConf.xml
+++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/resources/testHDFSConf.xml
@@ -16841,5 +16841,228 @@
         </comparator>
       </comparators>
     </test>
+
+    <!-- Tests for find -->
+    <test> <!-- TESTED -->
+      <description>find: default expression</description>
+      <test-commands>
+        <command>-fs NAMENODE -mkdir /donotfind</command>
+        <command>-fs NAMENODE -mkdir donotfind</command>
+        <command>-fs NAMENODE -mkdir /findtest</command>
+        <command>-fs NAMENODE -mkdir /findtest/item1</command>
+        <command>-fs NAMENODE -mkdir /findtest/item1/item1a</command>
+        <command>-fs NAMENODE -touchz /findtest/item1/item1a/item1aa</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes /findtest/item1/item1b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes /findtest/item2</command>
+        <command>-fs NAMENODE -mkdir /findtest/item3</command>
+        <command>-fs NAMENODE -mkdir /findtest/item4</command>
+        <command>-fs NAMENODE -mkdir /findtest/item4/item4a</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data120bytes /findtest/item4/item4b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data1k /findtest/item5</command>
+        <command>-fs NAMENODE -find /findtest</command>
+      </test-commands>
+      <cleanup-commands>
+        <command>-fs NAMENODE -rm -r /donotfind</command>
+        <command>-fs NAMENODE -rm -r donotfind</command>
+        <command>-fs NAMENODE -rm -r /findtest</command>
+      </cleanup-commands>
+      <comparators>
+        <comparator>
+          <type>RegexpAcrossOutputComparator</type>
+          <expected-output>^/findtest
+/findtest/item1
+/findtest/item1/item1a
+/findtest/item1/item1a/item1aa
+/findtest/item1/item1b
+/findtest/item2
+/findtest/item3
+/findtest/item4
+/findtest/item4/item4a
+/findtest/item4/item4b
+/findtest/item5
+$</expected-output>
+        </comparator>
+      </comparators>
+    </test>
+    <test> <!-- TESTED -->
+      <description>find: -print </description>
+      <test-commands>
+        <command>-fs NAMENODE -mkdir /donotfind</command>
+        <command>-fs NAMENODE -mkdir donotfind</command>
+        <command>-fs NAMENODE -mkdir /findtest</command>
+        <command>-fs NAMENODE -mkdir /findtest/item1</command>
+        <command>-fs NAMENODE -mkdir /findtest/item1/item1a</command>
+        <command>-fs NAMENODE -touchz /findtest/item1/item1a/item1aa</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes /findtest/item1/item1b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes /findtest/item2</command>
+        <command>-fs NAMENODE -mkdir /findtest/item3</command>
+        <command>-fs NAMENODE -mkdir /findtest/item4</command>
+        <command>-fs NAMENODE -mkdir /findtest/item4/item4a</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data120bytes /findtest/item4/item4b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data1k /findtest/item5</command>
+        <command>-fs NAMENODE -find /findtest -print</command>
+      </test-commands>
+      <cleanup-commands>
+        <command>-fs NAMENODE -rm -r /donotfind</command>
+        <command>-fs NAMENODE -rm -r donotfind</command>
+        <command>-fs NAMENODE -rm -r /findtest</command>
+      </cleanup-commands>
+      <comparators>
+        <comparator>
+          <type>RegexpAcrossOutputComparator</type>
+          <expected-output>^/findtest
+/findtest/item1
+/findtest/item1/item1a
+/findtest/item1/item1a/item1aa
+/findtest/item1/item1b
+/findtest/item2
+/findtest/item3
+/findtest/item4
+/findtest/item4/item4a
+/findtest/item4/item4b
+/findtest/item5
+$</expected-output>
+        </comparator>
+      </comparators>
+    </test>
+    <test> <!-- TESTED -->
+      <description>find: -print (relative path) </description>
+      <test-commands>
+        <command>-fs NAMENODE -mkdir /donotfind</command>
+        <command>-fs NAMENODE -mkdir -p donotfind</command>
+        <command>-fs NAMENODE -mkdir -p findtest</command>
+        <command>-fs NAMENODE -mkdir -p findtest/item1</command>
+        <command>-fs NAMENODE -mkdir -p findtest/item1/item1a</command>
+        <command>-fs NAMENODE -touchz findtest/item1/item1a/item1aa</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes findtest/item1/item1b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes findtest/item2</command>
+        <command>-fs NAMENODE -mkdir -p findtest/item3</command>
+        <command>-fs NAMENODE -mkdir -p findtest/item4</command>
+        <command>-fs NAMENODE -mkdir -p findtest/item4/item4a</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data120bytes findtest/item4/item4b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data1k findtest/item5</command>
+        <command>-fs NAMENODE -find findtest -print</command>
+      </test-commands>
+      <cleanup-commands>
+        <command>-fs NAMENODE -rm -r /donotfind</command>
+        <command>-fs NAMENODE -rm -r donotfind</command>
+        <command>-fs NAMENODE -rm -r findtest</command>
+      </cleanup-commands>
+      <comparators>
+        <comparator>
+          <type>RegexpAcrossOutputComparator</type>
+          <expected-output>^findtest
+findtest/item1
+findtest/item1/item1a
+findtest/item1/item1a/item1aa
+findtest/item1/item1b
+findtest/item2
+findtest/item3
+findtest/item4
+findtest/item4/item4a
+findtest/item4/item4b
+findtest/item5
+$</expected-output>
+        </comparator>
+      </comparators>
+    </test>
+    <test> <!-- TESTED -->
+      <description>find: -print (cwd) </description>
+      <test-commands>
+        <command>-fs NAMENODE -mkdir /donotfind</command>
+        <command>-fs NAMENODE -mkdir findtest</command>
+        <command>-fs NAMENODE -mkdir findtest/item1</command>
+        <command>-fs NAMENODE -mkdir findtest/item1/item1a</command>
+        <command>-fs NAMENODE -touchz findtest/item1/item1a/item1aa</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes findtest/item1/item1b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes findtest/item2</command>
+        <command>-fs NAMENODE -mkdir findtest/item3</command>
+        <command>-fs NAMENODE -mkdir findtest/item4</command>
+        <command>-fs NAMENODE -mkdir findtest/item4/item4a</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data120bytes findtest/item4/item4b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data1k findtest/item5</command>
+        <command>-fs NAMENODE -find -print</command>
+      </test-commands>
+      <cleanup-commands>
+        <command>-fs NAMENODE -rm -r findtest</command>
+        <command>-fs NAMENODE -rm -r /donotfind</command>
+      </cleanup-commands>
+      <comparators>
+        <comparator>
+          <type>RegexpAcrossOutputComparator</type>
+          <expected-output>^.
+findtest
+findtest/item1
+findtest/item1/item1a
+findtest/item1/item1a/item1aa
+findtest/item1/item1b
+findtest/item2
+findtest/item3
+findtest/item4
+findtest/item4/item4a
+findtest/item4/item4b
+findtest/item5
+$</expected-output>
+        </comparator>
+      </comparators>
+    </test>
+    <test> <!-- TESTED -->
+      <description>find: -name </description>
+      <test-commands>
+        <command>-fs NAMENODE -mkdir /findtest</command>
+        <command>-fs NAMENODE -mkdir /findtest/item1</command>
+        <command>-fs NAMENODE -mkdir /findtest/item1/item1a</command>
+        <command>-fs NAMENODE -touchz /findtest/item1/item1a/item1aa</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes /findtest/item1/item1b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes /findtest/item2</command>
+        <command>-fs NAMENODE -mkdir /findtest/item3</command>
+        <command>-fs NAMENODE -mkdir /findtest/item4</command>
+        <command>-fs NAMENODE -mkdir /findtest/item4/item4a</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data120bytes /findtest/item4/item4b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data1k /findtest/item5</command>
+        <command>-fs NAMENODE -find /findtest -name item*a</command>
+      </test-commands>
+      <cleanup-commands>
+        <command>-fs NAMENODE -rm -r /findtest</command>
+      </cleanup-commands>
+      <comparators>
+        <comparator>
+          <type>RegexpAcrossOutputComparator</type>
+          <expected-output>^/findtest/item1/item1a
+/findtest/item1/item1a/item1aa
+/findtest/item4/item4a
+$</expected-output>
+        </comparator>
+      </comparators>
+    </test>
+    <test> <!-- TESTED -->
+      <description>find: -iname </description>
+      <test-commands>
+        <command>-fs NAMENODE -mkdir /findtest</command>
+        <command>-fs NAMENODE -mkdir /findtest/item1</command>
+        <command>-fs NAMENODE -mkdir /findtest/item1/item1a</command>
+        <command>-fs NAMENODE -touchz /findtest/item1/item1a/item1aa</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes /findtest/item1/item1b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data60bytes /findtest/item2</command>
+        <command>-fs NAMENODE -mkdir /findtest/item3</command>
+        <command>-fs NAMENODE -mkdir /findtest/item4</command>
+        <command>-fs NAMENODE -mkdir /findtest/item4/item4a</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data120bytes /findtest/item4/item4b</command>
+        <command>-fs NAMENODE -put CLITEST_DATA/data1k /findtest/item5</command>
+        <command>-fs NAMENODE -find /findtest -iname ITEM*a</command>
+      </test-commands>
+      <cleanup-commands>
+        <command>-fs NAMENODE -rm -r /findtest</command>
+      </cleanup-commands>
+      <comparators>
+        <comparator>
+          <type>RegexpAcrossOutputComparator</type>
+          <expected-output>^/findtest/item1/item1a
+/findtest/item1/item1a/item1aa
+/findtest/item4/item4a
+$</expected-output>
+        </comparator>
+      </comparators>
+    </test>
   </tests>
 </configuration>