1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.fs.shell.find; 19 20 import static org.junit.Assert.*; 21 import static org.mockito.Mockito.*; 22 import static org.mockito.Matchers.*; 23 24 import java.io.IOException; 25 import java.io.PrintStream; 26 import java.util.Arrays; 27 import java.util.Collections; 28 import java.util.LinkedList; 29 30 import org.apache.hadoop.conf.Configuration; 31 import org.apache.hadoop.fs.FileStatus; 32 import org.apache.hadoop.fs.FileSystem; 33 import org.apache.hadoop.fs.Path; 34 import org.apache.hadoop.fs.shell.PathData; 35 import org.apache.hadoop.fs.shell.find.BaseExpression; 36 import org.apache.hadoop.fs.shell.find.Expression; 37 import org.apache.hadoop.fs.shell.find.Find; 38 import org.apache.hadoop.fs.shell.find.FindOptions; 39 import org.apache.hadoop.fs.shell.find.Result; 40 import org.junit.Before; 41 import org.junit.Test; 42 import org.mockito.InOrder; 43 44 public class TestFind { 45 private static FileSystem mockFs; 46 private static Configuration conf; 47 48 @Before setup()49 public void setup() throws IOException { 50 mockFs = MockFileSystem.setup(); 51 conf = mockFs.getConf(); 52 } 53 54 // check follow link option is recognized 55 @Test(timeout = 1000) processOptionsFollowLink()56 public void processOptionsFollowLink() throws IOException { 57 Find find = new Find(); 58 String args = "-L path"; 59 find.processOptions(getArgs(args)); 60 assertTrue(find.getOptions().isFollowLink()); 61 assertFalse(find.getOptions().isFollowArgLink()); 62 } 63 64 // check follow arg link option is recognized 65 @Test(timeout = 1000) processOptionsFollowArgLink()66 public void processOptionsFollowArgLink() throws IOException { 67 Find find = new Find(); 68 String args = "-H path"; 69 find.processOptions(getArgs(args)); 70 assertFalse(find.getOptions().isFollowLink()); 71 assertTrue(find.getOptions().isFollowArgLink()); 72 } 73 74 // check follow arg link option is recognized 75 @Test(timeout = 1000) processOptionsFollowLinkFollowArgLink()76 public void processOptionsFollowLinkFollowArgLink() throws IOException { 77 Find find = new Find(); 78 String args = "-L -H path"; 79 find.processOptions(getArgs(args)); 80 assertTrue(find.getOptions().isFollowLink()); 81 82 // follow link option takes precedence over follow arg link 83 assertFalse(find.getOptions().isFollowArgLink()); 84 } 85 86 // check options and expressions are stripped from args leaving paths 87 @Test(timeout = 1000) processOptionsExpression()88 public void processOptionsExpression() throws IOException { 89 Find find = new Find(); 90 find.setConf(conf); 91 92 String paths = "path1 path2 path3"; 93 String args = "-L -H " + paths + " -print -name test"; 94 LinkedList<String> argsList = getArgs(args); 95 find.processOptions(argsList); 96 LinkedList<String> pathList = getArgs(paths); 97 assertEquals(pathList, argsList); 98 } 99 100 // check print is used as the default expression 101 @Test(timeout = 1000) processOptionsNoExpression()102 public void processOptionsNoExpression() throws IOException { 103 Find find = new Find(); 104 find.setConf(conf); 105 String args = "path"; 106 String expected = "Print(;)"; 107 find.processOptions(getArgs(args)); 108 Expression expression = find.getRootExpression(); 109 assertEquals(expected, expression.toString()); 110 } 111 112 // check unknown options are rejected 113 @Test(timeout = 1000) processOptionsUnknown()114 public void processOptionsUnknown() throws IOException { 115 Find find = new Find(); 116 find.setConf(conf); 117 String args = "path -unknown"; 118 try { 119 find.processOptions(getArgs(args)); 120 fail("Unknown expression not caught"); 121 } catch (IOException e) { 122 } 123 } 124 125 // check unknown options are rejected when mixed with known options 126 @Test(timeout = 1000) processOptionsKnownUnknown()127 public void processOptionsKnownUnknown() throws IOException { 128 Find find = new Find(); 129 find.setConf(conf); 130 String args = "path -print -unknown -print"; 131 try { 132 find.processOptions(getArgs(args)); 133 fail("Unknown expression not caught"); 134 } catch (IOException e) { 135 } 136 } 137 138 // check no path defaults to current working directory 139 @Test(timeout = 1000) processOptionsNoPath()140 public void processOptionsNoPath() throws IOException { 141 Find find = new Find(); 142 find.setConf(conf); 143 String args = "-print"; 144 145 LinkedList<String> argsList = getArgs(args); 146 find.processOptions(argsList); 147 assertEquals(Collections.singletonList(Path.CUR_DIR), argsList); 148 } 149 150 // check -name is handled correctly 151 @Test(timeout = 1000) processOptionsName()152 public void processOptionsName() throws IOException { 153 Find find = new Find(); 154 find.setConf(conf); 155 String args = "path -name namemask"; 156 String expected = "And(;Name(namemask;),Print(;))"; 157 find.processOptions(getArgs(args)); 158 Expression expression = find.getRootExpression(); 159 assertEquals(expected, expression.toString()); 160 } 161 162 // check -iname is handled correctly 163 @Test(timeout = 1000) processOptionsIname()164 public void processOptionsIname() throws IOException { 165 Find find = new Find(); 166 find.setConf(conf); 167 String args = "path -iname namemask"; 168 String expected = "And(;Iname-Name(namemask;),Print(;))"; 169 find.processOptions(getArgs(args)); 170 Expression expression = find.getRootExpression(); 171 assertEquals(expected, expression.toString()); 172 } 173 174 // check -print is handled correctly 175 @Test(timeout = 1000) processOptionsPrint()176 public void processOptionsPrint() throws IOException { 177 Find find = new Find(); 178 find.setConf(conf); 179 String args = "path -print"; 180 String expected = "Print(;)"; 181 find.processOptions(getArgs(args)); 182 Expression expression = find.getRootExpression(); 183 assertEquals(expected, expression.toString()); 184 } 185 186 // check -print0 is handled correctly 187 @Test(timeout = 1000) processOptionsPrint0()188 public void processOptionsPrint0() throws IOException { 189 Find find = new Find(); 190 find.setConf(conf); 191 String args = "path -print0"; 192 String expected = "Print0-Print(;)"; 193 find.processOptions(getArgs(args)); 194 Expression expression = find.getRootExpression(); 195 assertEquals(expected, expression.toString()); 196 } 197 198 // check an implicit and is handled correctly 199 @Test(timeout = 1000) processOptionsNoop()200 public void processOptionsNoop() throws IOException { 201 Find find = new Find(); 202 find.setConf(conf); 203 204 String args = "path -name one -name two -print"; 205 String expected = "And(;And(;Name(one;),Name(two;)),Print(;))"; 206 find.processOptions(getArgs(args)); 207 Expression expression = find.getRootExpression(); 208 assertEquals(expected, expression.toString()); 209 } 210 211 // check -a is handled correctly 212 @Test(timeout = 1000) processOptionsA()213 public void processOptionsA() throws IOException { 214 Find find = new Find(); 215 find.setConf(conf); 216 217 String args = "path -name one -a -name two -a -print"; 218 String expected = "And(;And(;Name(one;),Name(two;)),Print(;))"; 219 find.processOptions(getArgs(args)); 220 Expression expression = find.getRootExpression(); 221 assertEquals(expected, expression.toString()); 222 } 223 224 // check -and is handled correctly 225 @Test(timeout = 1000) processOptionsAnd()226 public void processOptionsAnd() throws IOException { 227 Find find = new Find(); 228 find.setConf(conf); 229 230 String args = "path -name one -and -name two -and -print"; 231 String expected = "And(;And(;Name(one;),Name(two;)),Print(;))"; 232 find.processOptions(getArgs(args)); 233 Expression expression = find.getRootExpression(); 234 assertEquals(expected, expression.toString()); 235 } 236 237 // check expressions are called in the correct order 238 @Test(timeout = 1000) processArguments()239 public void processArguments() throws IOException { 240 LinkedList<PathData> items = createDirectories(); 241 242 Find find = new Find(); 243 find.setConf(conf); 244 PrintStream out = mock(PrintStream.class); 245 find.getOptions().setOut(out); 246 PrintStream err = mock(PrintStream.class); 247 find.getOptions().setErr(err); 248 Expression expr = mock(Expression.class); 249 when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS); 250 FileStatusChecker fsCheck = mock(FileStatusChecker.class); 251 Expression test = new TestExpression(expr, fsCheck); 252 find.setRootExpression(test); 253 find.processArguments(items); 254 255 InOrder inOrder = inOrder(expr); 256 inOrder.verify(expr).setOptions(find.getOptions()); 257 inOrder.verify(expr).prepare(); 258 inOrder.verify(expr).apply(item1, 0); 259 inOrder.verify(expr).apply(item1a, 1); 260 inOrder.verify(expr).apply(item1aa, 2); 261 inOrder.verify(expr).apply(item1b, 1); 262 inOrder.verify(expr).apply(item2, 0); 263 inOrder.verify(expr).apply(item3, 0); 264 inOrder.verify(expr).apply(item4, 0); 265 inOrder.verify(expr).apply(item5, 0); 266 inOrder.verify(expr).apply(item5a, 1); 267 inOrder.verify(expr).apply(item5b, 1); 268 inOrder.verify(expr).apply(item5c, 1); 269 inOrder.verify(expr).apply(item5ca, 2); 270 inOrder.verify(expr).apply(item5d, 1); 271 inOrder.verify(expr).apply(item5e, 1); 272 inOrder.verify(expr).finish(); 273 verifyNoMoreInteractions(expr); 274 275 InOrder inOrderFsCheck = inOrder(fsCheck); 276 inOrderFsCheck.verify(fsCheck).check(item1.stat); 277 inOrderFsCheck.verify(fsCheck).check(item1a.stat); 278 inOrderFsCheck.verify(fsCheck).check(item1aa.stat); 279 inOrderFsCheck.verify(fsCheck).check(item1b.stat); 280 inOrderFsCheck.verify(fsCheck).check(item2.stat); 281 inOrderFsCheck.verify(fsCheck).check(item3.stat); 282 inOrderFsCheck.verify(fsCheck).check(item4.stat); 283 inOrderFsCheck.verify(fsCheck).check(item5.stat); 284 inOrderFsCheck.verify(fsCheck).check(item5a.stat); 285 inOrderFsCheck.verify(fsCheck).check(item5b.stat); 286 inOrderFsCheck.verify(fsCheck).check(item5c.stat); 287 inOrderFsCheck.verify(fsCheck).check(item5ca.stat); 288 inOrderFsCheck.verify(fsCheck).check(item5d.stat); 289 inOrderFsCheck.verify(fsCheck).check(item5e.stat); 290 verifyNoMoreInteractions(fsCheck); 291 292 verifyNoMoreInteractions(out); 293 verifyNoMoreInteractions(err); 294 } 295 296 // check that directories are descended correctly when -depth is specified 297 @Test(timeout = 1000) processArgumentsDepthFirst()298 public void processArgumentsDepthFirst() throws IOException { 299 LinkedList<PathData> items = createDirectories(); 300 301 Find find = new Find(); 302 find.getOptions().setDepthFirst(true); 303 find.setConf(conf); 304 PrintStream out = mock(PrintStream.class); 305 find.getOptions().setOut(out); 306 PrintStream err = mock(PrintStream.class); 307 find.getOptions().setErr(err); 308 Expression expr = mock(Expression.class); 309 when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS); 310 FileStatusChecker fsCheck = mock(FileStatusChecker.class); 311 Expression test = new TestExpression(expr, fsCheck); 312 find.setRootExpression(test); 313 find.processArguments(items); 314 315 InOrder inOrder = inOrder(expr); 316 inOrder.verify(expr).setOptions(find.getOptions()); 317 inOrder.verify(expr).prepare(); 318 inOrder.verify(expr).apply(item1aa, 2); 319 inOrder.verify(expr).apply(item1a, 1); 320 inOrder.verify(expr).apply(item1b, 1); 321 inOrder.verify(expr).apply(item1, 0); 322 inOrder.verify(expr).apply(item2, 0); 323 inOrder.verify(expr).apply(item3, 0); 324 inOrder.verify(expr).apply(item4, 0); 325 inOrder.verify(expr).apply(item5a, 1); 326 inOrder.verify(expr).apply(item5b, 1); 327 inOrder.verify(expr).apply(item5ca, 2); 328 inOrder.verify(expr).apply(item5c, 1); 329 inOrder.verify(expr).apply(item5d, 1); 330 inOrder.verify(expr).apply(item5e, 1); 331 inOrder.verify(expr).apply(item5, 0); 332 inOrder.verify(expr).finish(); 333 verifyNoMoreInteractions(expr); 334 335 InOrder inOrderFsCheck = inOrder(fsCheck); 336 inOrderFsCheck.verify(fsCheck).check(item1aa.stat); 337 inOrderFsCheck.verify(fsCheck).check(item1a.stat); 338 inOrderFsCheck.verify(fsCheck).check(item1b.stat); 339 inOrderFsCheck.verify(fsCheck).check(item1.stat); 340 inOrderFsCheck.verify(fsCheck).check(item2.stat); 341 inOrderFsCheck.verify(fsCheck).check(item3.stat); 342 inOrderFsCheck.verify(fsCheck).check(item4.stat); 343 inOrderFsCheck.verify(fsCheck).check(item5a.stat); 344 inOrderFsCheck.verify(fsCheck).check(item5b.stat); 345 inOrderFsCheck.verify(fsCheck).check(item5ca.stat); 346 inOrderFsCheck.verify(fsCheck).check(item5c.stat); 347 inOrderFsCheck.verify(fsCheck).check(item5d.stat); 348 inOrderFsCheck.verify(fsCheck).check(item5e.stat); 349 inOrderFsCheck.verify(fsCheck).check(item5.stat); 350 verifyNoMoreInteractions(fsCheck); 351 352 verifyNoMoreInteractions(out); 353 verifyNoMoreInteractions(err); 354 } 355 356 // check symlinks given as path arguments are processed correctly with the 357 // follow arg option set 358 @Test(timeout = 1000) processArgumentsOptionFollowArg()359 public void processArgumentsOptionFollowArg() throws IOException { 360 LinkedList<PathData> items = createDirectories(); 361 362 Find find = new Find(); 363 find.getOptions().setFollowArgLink(true); 364 find.setConf(conf); 365 PrintStream out = mock(PrintStream.class); 366 find.getOptions().setOut(out); 367 PrintStream err = mock(PrintStream.class); 368 find.getOptions().setErr(err); 369 Expression expr = mock(Expression.class); 370 when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS); 371 FileStatusChecker fsCheck = mock(FileStatusChecker.class); 372 Expression test = new TestExpression(expr, fsCheck); 373 find.setRootExpression(test); 374 find.processArguments(items); 375 376 InOrder inOrder = inOrder(expr); 377 inOrder.verify(expr).setOptions(find.getOptions()); 378 inOrder.verify(expr).prepare(); 379 inOrder.verify(expr).apply(item1, 0); 380 inOrder.verify(expr).apply(item1a, 1); 381 inOrder.verify(expr).apply(item1aa, 2); 382 inOrder.verify(expr).apply(item1b, 1); 383 inOrder.verify(expr).apply(item2, 0); 384 inOrder.verify(expr).apply(item3, 0); 385 inOrder.verify(expr).apply(item4, 0); 386 inOrder.verify(expr).apply(item5, 0); 387 inOrder.verify(expr).apply(item5a, 1); 388 inOrder.verify(expr).apply(item5b, 1); 389 inOrder.verify(expr).apply(item5c, 1); 390 inOrder.verify(expr).apply(item5ca, 2); 391 inOrder.verify(expr).apply(item5d, 1); 392 inOrder.verify(expr).apply(item5e, 1); 393 inOrder.verify(expr).finish(); 394 verifyNoMoreInteractions(expr); 395 396 InOrder inOrderFsCheck = inOrder(fsCheck); 397 inOrderFsCheck.verify(fsCheck).check(item1.stat); 398 inOrderFsCheck.verify(fsCheck).check(item1a.stat); 399 inOrderFsCheck.verify(fsCheck).check(item1aa.stat); 400 inOrderFsCheck.verify(fsCheck).check(item1b.stat); 401 inOrderFsCheck.verify(fsCheck).check(item2.stat); 402 inOrderFsCheck.verify(fsCheck, times(2)).check(item3.stat); 403 inOrderFsCheck.verify(fsCheck).check(item5.stat); 404 inOrderFsCheck.verify(fsCheck).check(item5a.stat); 405 inOrderFsCheck.verify(fsCheck).check(item5b.stat); 406 inOrderFsCheck.verify(fsCheck).check(item5c.stat); 407 inOrderFsCheck.verify(fsCheck).check(item5ca.stat); 408 inOrderFsCheck.verify(fsCheck).check(item5d.stat); 409 inOrderFsCheck.verify(fsCheck).check(item5e.stat); 410 verifyNoMoreInteractions(fsCheck); 411 412 verifyNoMoreInteractions(out); 413 verifyNoMoreInteractions(err); 414 } 415 416 // check symlinks given as path arguments are processed correctly with the 417 // follow option 418 @Test(timeout = 1000) processArgumentsOptionFollow()419 public void processArgumentsOptionFollow() throws IOException { 420 LinkedList<PathData> items = createDirectories(); 421 422 Find find = new Find(); 423 find.getOptions().setFollowLink(true); 424 find.setConf(conf); 425 PrintStream out = mock(PrintStream.class); 426 find.getOptions().setOut(out); 427 PrintStream err = mock(PrintStream.class); 428 find.getOptions().setErr(err); 429 Expression expr = mock(Expression.class); 430 when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS); 431 FileStatusChecker fsCheck = mock(FileStatusChecker.class); 432 Expression test = new TestExpression(expr, fsCheck); 433 find.setRootExpression(test); 434 find.processArguments(items); 435 436 InOrder inOrder = inOrder(expr); 437 inOrder.verify(expr).setOptions(find.getOptions()); 438 inOrder.verify(expr).prepare(); 439 inOrder.verify(expr).apply(item1, 0); 440 inOrder.verify(expr).apply(item1a, 1); 441 inOrder.verify(expr).apply(item1aa, 2); 442 inOrder.verify(expr).apply(item1b, 1); 443 inOrder.verify(expr).apply(item2, 0); 444 inOrder.verify(expr).apply(item3, 0); 445 inOrder.verify(expr).apply(item4, 0); 446 inOrder.verify(expr).apply(item5, 0); 447 inOrder.verify(expr).apply(item5a, 1); 448 inOrder.verify(expr).apply(item5b, 1); // triggers infinite loop message 449 inOrder.verify(expr).apply(item5c, 1); 450 inOrder.verify(expr).apply(item5ca, 2); 451 inOrder.verify(expr).apply(item5d, 1); 452 inOrder.verify(expr).apply(item5ca, 2); // following item5d symlink 453 inOrder.verify(expr).apply(item5e, 1); 454 inOrder.verify(expr).finish(); 455 verifyNoMoreInteractions(expr); 456 457 InOrder inOrderFsCheck = inOrder(fsCheck); 458 inOrderFsCheck.verify(fsCheck).check(item1.stat); 459 inOrderFsCheck.verify(fsCheck).check(item1a.stat); 460 inOrderFsCheck.verify(fsCheck).check(item1aa.stat); 461 inOrderFsCheck.verify(fsCheck).check(item1b.stat); 462 inOrderFsCheck.verify(fsCheck).check(item2.stat); 463 inOrderFsCheck.verify(fsCheck, times(2)).check(item3.stat); 464 inOrderFsCheck.verify(fsCheck).check(item5.stat); 465 inOrderFsCheck.verify(fsCheck).check(item1b.stat); 466 inOrderFsCheck.verify(fsCheck).check(item5.stat); 467 inOrderFsCheck.verify(fsCheck).check(item5c.stat); 468 inOrderFsCheck.verify(fsCheck).check(item5ca.stat); 469 inOrderFsCheck.verify(fsCheck).check(item5c.stat); 470 inOrderFsCheck.verify(fsCheck, times(2)).check(item5ca.stat); 471 verifyNoMoreInteractions(fsCheck); 472 473 verifyNoMoreInteractions(out); 474 verify(err).println( 475 "Infinite loop ignored: " + item5b.toString() + " -> " 476 + item5.toString()); 477 verifyNoMoreInteractions(err); 478 } 479 480 // check minimum depth is handledfollowLink 481 @Test(timeout = 1000) processArgumentsMinDepth()482 public void processArgumentsMinDepth() throws IOException { 483 LinkedList<PathData> items = createDirectories(); 484 485 Find find = new Find(); 486 find.getOptions().setMinDepth(1); 487 find.setConf(conf); 488 PrintStream out = mock(PrintStream.class); 489 find.getOptions().setOut(out); 490 PrintStream err = mock(PrintStream.class); 491 find.getOptions().setErr(err); 492 Expression expr = mock(Expression.class); 493 when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS); 494 FileStatusChecker fsCheck = mock(FileStatusChecker.class); 495 Expression test = new TestExpression(expr, fsCheck); 496 find.setRootExpression(test); 497 find.processArguments(items); 498 499 InOrder inOrder = inOrder(expr); 500 inOrder.verify(expr).setOptions(find.getOptions()); 501 inOrder.verify(expr).prepare(); 502 inOrder.verify(expr).apply(item1a, 1); 503 inOrder.verify(expr).apply(item1aa, 2); 504 inOrder.verify(expr).apply(item1b, 1); 505 inOrder.verify(expr).apply(item5a, 1); 506 inOrder.verify(expr).apply(item5b, 1); 507 inOrder.verify(expr).apply(item5c, 1); 508 inOrder.verify(expr).apply(item5ca, 2); 509 inOrder.verify(expr).apply(item5d, 1); 510 inOrder.verify(expr).apply(item5e, 1); 511 inOrder.verify(expr).finish(); 512 verifyNoMoreInteractions(expr); 513 514 InOrder inOrderFsCheck = inOrder(fsCheck); 515 inOrderFsCheck.verify(fsCheck).check(item1a.stat); 516 inOrderFsCheck.verify(fsCheck).check(item1aa.stat); 517 inOrderFsCheck.verify(fsCheck).check(item1b.stat); 518 inOrderFsCheck.verify(fsCheck).check(item5a.stat); 519 inOrderFsCheck.verify(fsCheck).check(item5b.stat); 520 inOrderFsCheck.verify(fsCheck).check(item5c.stat); 521 inOrderFsCheck.verify(fsCheck).check(item5ca.stat); 522 inOrderFsCheck.verify(fsCheck).check(item5d.stat); 523 inOrderFsCheck.verify(fsCheck).check(item5e.stat); 524 verifyNoMoreInteractions(fsCheck); 525 526 verifyNoMoreInteractions(out); 527 verifyNoMoreInteractions(err); 528 } 529 530 // check maximum depth is handled 531 @Test(timeout = 1000) processArgumentsMaxDepth()532 public void processArgumentsMaxDepth() throws IOException { 533 LinkedList<PathData> items = createDirectories(); 534 535 Find find = new Find(); 536 find.getOptions().setMaxDepth(1); 537 find.setConf(conf); 538 PrintStream out = mock(PrintStream.class); 539 find.getOptions().setOut(out); 540 PrintStream err = mock(PrintStream.class); 541 find.getOptions().setErr(err); 542 Expression expr = mock(Expression.class); 543 when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS); 544 FileStatusChecker fsCheck = mock(FileStatusChecker.class); 545 Expression test = new TestExpression(expr, fsCheck); 546 find.setRootExpression(test); 547 find.processArguments(items); 548 549 InOrder inOrder = inOrder(expr); 550 inOrder.verify(expr).setOptions(find.getOptions()); 551 inOrder.verify(expr).prepare(); 552 inOrder.verify(expr).apply(item1, 0); 553 inOrder.verify(expr).apply(item1a, 1); 554 inOrder.verify(expr).apply(item1b, 1); 555 inOrder.verify(expr).apply(item2, 0); 556 inOrder.verify(expr).apply(item3, 0); 557 inOrder.verify(expr).apply(item4, 0); 558 inOrder.verify(expr).apply(item5, 0); 559 inOrder.verify(expr).apply(item5a, 1); 560 inOrder.verify(expr).apply(item5b, 1); 561 inOrder.verify(expr).apply(item5c, 1); 562 inOrder.verify(expr).apply(item5d, 1); 563 inOrder.verify(expr).apply(item5e, 1); 564 inOrder.verify(expr).finish(); 565 verifyNoMoreInteractions(expr); 566 567 InOrder inOrderFsCheck = inOrder(fsCheck); 568 inOrderFsCheck.verify(fsCheck).check(item1.stat); 569 inOrderFsCheck.verify(fsCheck).check(item1a.stat); 570 inOrderFsCheck.verify(fsCheck).check(item1b.stat); 571 inOrderFsCheck.verify(fsCheck).check(item2.stat); 572 inOrderFsCheck.verify(fsCheck).check(item3.stat); 573 inOrderFsCheck.verify(fsCheck).check(item4.stat); 574 inOrderFsCheck.verify(fsCheck).check(item5.stat); 575 inOrderFsCheck.verify(fsCheck).check(item5a.stat); 576 inOrderFsCheck.verify(fsCheck).check(item5b.stat); 577 inOrderFsCheck.verify(fsCheck).check(item5c.stat); 578 inOrderFsCheck.verify(fsCheck).check(item5d.stat); 579 inOrderFsCheck.verify(fsCheck).check(item5e.stat); 580 verifyNoMoreInteractions(fsCheck); 581 582 verifyNoMoreInteractions(out); 583 verifyNoMoreInteractions(err); 584 } 585 586 // check min depth is handled when -depth is specified 587 @Test(timeout = 1000) processArgumentsDepthFirstMinDepth()588 public void processArgumentsDepthFirstMinDepth() throws IOException { 589 LinkedList<PathData> items = createDirectories(); 590 591 Find find = new Find(); 592 find.getOptions().setDepthFirst(true); 593 find.getOptions().setMinDepth(1); 594 find.setConf(conf); 595 PrintStream out = mock(PrintStream.class); 596 find.getOptions().setOut(out); 597 PrintStream err = mock(PrintStream.class); 598 find.getOptions().setErr(err); 599 Expression expr = mock(Expression.class); 600 when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS); 601 FileStatusChecker fsCheck = mock(FileStatusChecker.class); 602 Expression test = new TestExpression(expr, fsCheck); 603 find.setRootExpression(test); 604 find.processArguments(items); 605 606 InOrder inOrder = inOrder(expr); 607 inOrder.verify(expr).setOptions(find.getOptions()); 608 inOrder.verify(expr).prepare(); 609 inOrder.verify(expr).apply(item1aa, 2); 610 inOrder.verify(expr).apply(item1a, 1); 611 inOrder.verify(expr).apply(item1b, 1); 612 inOrder.verify(expr).apply(item5a, 1); 613 inOrder.verify(expr).apply(item5b, 1); 614 inOrder.verify(expr).apply(item5ca, 2); 615 inOrder.verify(expr).apply(item5c, 1); 616 inOrder.verify(expr).apply(item5d, 1); 617 inOrder.verify(expr).apply(item5e, 1); 618 inOrder.verify(expr).finish(); 619 verifyNoMoreInteractions(expr); 620 621 InOrder inOrderFsCheck = inOrder(fsCheck); 622 inOrderFsCheck.verify(fsCheck).check(item1aa.stat); 623 inOrderFsCheck.verify(fsCheck).check(item1a.stat); 624 inOrderFsCheck.verify(fsCheck).check(item1b.stat); 625 inOrderFsCheck.verify(fsCheck).check(item5a.stat); 626 inOrderFsCheck.verify(fsCheck).check(item5b.stat); 627 inOrderFsCheck.verify(fsCheck).check(item5ca.stat); 628 inOrderFsCheck.verify(fsCheck).check(item5c.stat); 629 inOrderFsCheck.verify(fsCheck).check(item5d.stat); 630 inOrderFsCheck.verify(fsCheck).check(item5e.stat); 631 verifyNoMoreInteractions(fsCheck); 632 633 verifyNoMoreInteractions(out); 634 verifyNoMoreInteractions(err); 635 } 636 637 // check max depth is handled when -depth is specified 638 @Test(timeout = 1000) processArgumentsDepthFirstMaxDepth()639 public void processArgumentsDepthFirstMaxDepth() throws IOException { 640 LinkedList<PathData> items = createDirectories(); 641 642 Find find = new Find(); 643 find.getOptions().setDepthFirst(true); 644 find.getOptions().setMaxDepth(1); 645 find.setConf(conf); 646 PrintStream out = mock(PrintStream.class); 647 find.getOptions().setOut(out); 648 PrintStream err = mock(PrintStream.class); 649 find.getOptions().setErr(err); 650 Expression expr = mock(Expression.class); 651 when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS); 652 FileStatusChecker fsCheck = mock(FileStatusChecker.class); 653 Expression test = new TestExpression(expr, fsCheck); 654 find.setRootExpression(test); 655 find.processArguments(items); 656 657 InOrder inOrder = inOrder(expr); 658 inOrder.verify(expr).setOptions(find.getOptions()); 659 inOrder.verify(expr).prepare(); 660 inOrder.verify(expr).apply(item1a, 1); 661 inOrder.verify(expr).apply(item1b, 1); 662 inOrder.verify(expr).apply(item1, 0); 663 inOrder.verify(expr).apply(item2, 0); 664 inOrder.verify(expr).apply(item3, 0); 665 inOrder.verify(expr).apply(item4, 0); 666 inOrder.verify(expr).apply(item5a, 1); 667 inOrder.verify(expr).apply(item5b, 1); 668 inOrder.verify(expr).apply(item5c, 1); 669 inOrder.verify(expr).apply(item5d, 1); 670 inOrder.verify(expr).apply(item5e, 1); 671 inOrder.verify(expr).apply(item5, 0); 672 inOrder.verify(expr).finish(); 673 verifyNoMoreInteractions(expr); 674 675 InOrder inOrderFsCheck = inOrder(fsCheck); 676 inOrderFsCheck.verify(fsCheck).check(item1a.stat); 677 inOrderFsCheck.verify(fsCheck).check(item1b.stat); 678 inOrderFsCheck.verify(fsCheck).check(item1.stat); 679 inOrderFsCheck.verify(fsCheck).check(item2.stat); 680 inOrderFsCheck.verify(fsCheck).check(item3.stat); 681 inOrderFsCheck.verify(fsCheck).check(item4.stat); 682 inOrderFsCheck.verify(fsCheck).check(item5a.stat); 683 inOrderFsCheck.verify(fsCheck).check(item5b.stat); 684 inOrderFsCheck.verify(fsCheck).check(item5c.stat); 685 inOrderFsCheck.verify(fsCheck).check(item5d.stat); 686 inOrderFsCheck.verify(fsCheck).check(item5e.stat); 687 inOrderFsCheck.verify(fsCheck).check(item5.stat); 688 verifyNoMoreInteractions(fsCheck); 689 690 verifyNoMoreInteractions(out); 691 verifyNoMoreInteractions(err); 692 } 693 694 // check expressions are called in the correct order 695 @Test(timeout = 1000) processArgumentsNoDescend()696 public void processArgumentsNoDescend() throws IOException { 697 LinkedList<PathData> items = createDirectories(); 698 699 Find find = new Find(); 700 find.setConf(conf); 701 PrintStream out = mock(PrintStream.class); 702 find.getOptions().setOut(out); 703 PrintStream err = mock(PrintStream.class); 704 find.getOptions().setErr(err); 705 Expression expr = mock(Expression.class); 706 when(expr.apply((PathData) any(), anyInt())).thenReturn(Result.PASS); 707 when(expr.apply(eq(item1a), anyInt())).thenReturn(Result.STOP); 708 FileStatusChecker fsCheck = mock(FileStatusChecker.class); 709 Expression test = new TestExpression(expr, fsCheck); 710 find.setRootExpression(test); 711 find.processArguments(items); 712 713 InOrder inOrder = inOrder(expr); 714 inOrder.verify(expr).setOptions(find.getOptions()); 715 inOrder.verify(expr).prepare(); 716 inOrder.verify(expr).apply(item1, 0); 717 inOrder.verify(expr).apply(item1a, 1); 718 inOrder.verify(expr).apply(item1b, 1); 719 inOrder.verify(expr).apply(item2, 0); 720 inOrder.verify(expr).apply(item3, 0); 721 inOrder.verify(expr).apply(item4, 0); 722 inOrder.verify(expr).apply(item5, 0); 723 inOrder.verify(expr).apply(item5a, 1); 724 inOrder.verify(expr).apply(item5b, 1); 725 inOrder.verify(expr).apply(item5c, 1); 726 inOrder.verify(expr).apply(item5ca, 2); 727 inOrder.verify(expr).apply(item5d, 1); 728 inOrder.verify(expr).apply(item5e, 1); 729 inOrder.verify(expr).finish(); 730 verifyNoMoreInteractions(expr); 731 732 InOrder inOrderFsCheck = inOrder(fsCheck); 733 inOrderFsCheck.verify(fsCheck).check(item1.stat); 734 inOrderFsCheck.verify(fsCheck).check(item1a.stat); 735 inOrderFsCheck.verify(fsCheck).check(item1b.stat); 736 inOrderFsCheck.verify(fsCheck).check(item2.stat); 737 inOrderFsCheck.verify(fsCheck).check(item3.stat); 738 inOrderFsCheck.verify(fsCheck).check(item4.stat); 739 inOrderFsCheck.verify(fsCheck).check(item5.stat); 740 inOrderFsCheck.verify(fsCheck).check(item5a.stat); 741 inOrderFsCheck.verify(fsCheck).check(item5b.stat); 742 inOrderFsCheck.verify(fsCheck).check(item5c.stat); 743 inOrderFsCheck.verify(fsCheck).check(item5ca.stat); 744 inOrderFsCheck.verify(fsCheck).check(item5d.stat); 745 inOrderFsCheck.verify(fsCheck).check(item5e.stat); 746 verifyNoMoreInteractions(fsCheck); 747 748 verifyNoMoreInteractions(out); 749 verifyNoMoreInteractions(err); 750 } 751 752 private interface FileStatusChecker { check(FileStatus fileStatus)753 public void check(FileStatus fileStatus); 754 } 755 756 private class TestExpression extends BaseExpression implements Expression { 757 private Expression expr; 758 private FileStatusChecker checker; TestExpression(Expression expr, FileStatusChecker checker)759 public TestExpression(Expression expr, FileStatusChecker checker) { 760 this.expr = expr; 761 this.checker = checker; 762 } 763 @Override apply(PathData item, int depth)764 public Result apply(PathData item, int depth) throws IOException { 765 FileStatus fileStatus = getFileStatus(item, depth); 766 checker.check(fileStatus); 767 return expr.apply(item, depth); 768 } 769 @Override setOptions(FindOptions options)770 public void setOptions(FindOptions options) throws IOException { 771 super.setOptions(options); 772 expr.setOptions(options); 773 } 774 @Override prepare()775 public void prepare() throws IOException { 776 expr.prepare(); 777 } 778 @Override finish()779 public void finish() throws IOException { 780 expr.finish(); 781 } 782 } 783 784 // creates a directory structure for traversal 785 // item1 (directory) 786 // \- item1a (directory) 787 // \- item1aa (file) 788 // \- item1b (file) 789 // item2 (directory) 790 // item3 (file) 791 // item4 (link) -> item3 792 // item5 (directory) 793 // \- item5a (link) -> item1b 794 // \- item5b (link) -> item5 (infinite loop) 795 // \- item5c (directory) 796 // \- item5ca (file) 797 // \- item5d (link) -> item5c 798 // \- item5e (link) -> item5c/item5ca 799 private PathData item1 = null; 800 private PathData item1a = null; 801 private PathData item1aa = null; 802 private PathData item1b = null; 803 private PathData item2 = null; 804 private PathData item3 = null; 805 private PathData item4 = null; 806 private PathData item5 = null; 807 private PathData item5a = null; 808 private PathData item5b = null; 809 private PathData item5c = null; 810 private PathData item5ca = null; 811 private PathData item5d = null; 812 private PathData item5e = null; 813 createDirectories()814 private LinkedList<PathData> createDirectories() throws IOException { 815 item1 = createPathData("item1"); 816 item1a = createPathData("item1/item1a"); 817 item1aa = createPathData("item1/item1a/item1aa"); 818 item1b = createPathData("item1/item1b"); 819 item2 = createPathData("item2"); 820 item3 = createPathData("item3"); 821 item4 = createPathData("item4"); 822 item5 = createPathData("item5"); 823 item5a = createPathData("item5/item5a"); 824 item5b = createPathData("item5/item5b"); 825 item5c = createPathData("item5/item5c"); 826 item5ca = createPathData("item5/item5c/item5ca"); 827 item5d = createPathData("item5/item5d"); 828 item5e = createPathData("item5/item5e"); 829 830 LinkedList<PathData> args = new LinkedList<PathData>(); 831 832 when(item1.stat.isDirectory()).thenReturn(true); 833 when(item1a.stat.isDirectory()).thenReturn(true); 834 when(item1aa.stat.isDirectory()).thenReturn(false); 835 when(item1b.stat.isDirectory()).thenReturn(false); 836 when(item2.stat.isDirectory()).thenReturn(true); 837 when(item3.stat.isDirectory()).thenReturn(false); 838 when(item4.stat.isDirectory()).thenReturn(false); 839 when(item5.stat.isDirectory()).thenReturn(true); 840 when(item5a.stat.isDirectory()).thenReturn(false); 841 when(item5b.stat.isDirectory()).thenReturn(false); 842 when(item5c.stat.isDirectory()).thenReturn(true); 843 when(item5ca.stat.isDirectory()).thenReturn(false); 844 when(item5d.stat.isDirectory()).thenReturn(false); 845 when(item5e.stat.isDirectory()).thenReturn(false); 846 847 when(mockFs.listStatus(eq(item1.path))).thenReturn( 848 new FileStatus[] { item1a.stat, item1b.stat }); 849 when(mockFs.listStatus(eq(item1a.path))).thenReturn( 850 new FileStatus[] { item1aa.stat }); 851 when(mockFs.listStatus(eq(item2.path))).thenReturn(new FileStatus[0]); 852 when(mockFs.listStatus(eq(item5.path))).thenReturn( 853 new FileStatus[] { item5a.stat, item5b.stat, item5c.stat, item5d.stat, 854 item5e.stat }); 855 when(mockFs.listStatus(eq(item5c.path))).thenReturn( 856 new FileStatus[] { item5ca.stat }); 857 858 when(item1.stat.isSymlink()).thenReturn(false); 859 when(item1a.stat.isSymlink()).thenReturn(false); 860 when(item1aa.stat.isSymlink()).thenReturn(false); 861 when(item1b.stat.isSymlink()).thenReturn(false); 862 when(item2.stat.isSymlink()).thenReturn(false); 863 when(item3.stat.isSymlink()).thenReturn(false); 864 when(item4.stat.isSymlink()).thenReturn(true); 865 when(item5.stat.isSymlink()).thenReturn(false); 866 when(item5a.stat.isSymlink()).thenReturn(true); 867 when(item5b.stat.isSymlink()).thenReturn(true); 868 when(item5d.stat.isSymlink()).thenReturn(true); 869 when(item5e.stat.isSymlink()).thenReturn(true); 870 871 when(item4.stat.getSymlink()).thenReturn(item3.path); 872 when(item5a.stat.getSymlink()).thenReturn(item1b.path); 873 when(item5b.stat.getSymlink()).thenReturn(item5.path); 874 when(item5d.stat.getSymlink()).thenReturn(item5c.path); 875 when(item5e.stat.getSymlink()).thenReturn(item5ca.path); 876 877 args.add(item1); 878 args.add(item2); 879 args.add(item3); 880 args.add(item4); 881 args.add(item5); 882 883 return args; 884 } 885 createPathData(String name)886 private PathData createPathData(String name) throws IOException { 887 Path path = new Path(name); 888 FileStatus fstat = mock(FileStatus.class); 889 when(fstat.getPath()).thenReturn(path); 890 when(fstat.toString()).thenReturn("fileStatus:" + name); 891 892 when(mockFs.getFileStatus(eq(path))).thenReturn(fstat); 893 PathData item = new PathData(path.toString(), conf); 894 return item; 895 } 896 getArgs(String cmd)897 private LinkedList<String> getArgs(String cmd) { 898 return new LinkedList<String>(Arrays.asList(cmd.split(" "))); 899 } 900 } 901