-2

I run test case and save files created during execution in 'execution' directory (files from each tests in separated subdirectory) At the beginning of suite I want to clean this folder

So in @BeforeSuite method I read all items from 'execution' directory:

public static List<File> getRecursivelyAllFilesFromDirectory(String directory) throws IOException {
    List<File> files = new ArrayList<>();
    files.addAll(readAllFilesFromDirectory(directory));

    List<File> subDirs = readSubdirectories(directory);

    subDirs.forEach(dir -> {
        try {
            files.addAll(readAllFilesFromDirectory(dir.getPath()));
            files.add(dir);
        } catch (IOException e) {
            e.printStackTrace();
        }
    });

    return files;
}

and then I want to delete everything

public static void cleanExecutionDirectory() throws IOException {
    LOGGER.info("Cleaning execution directory...");
    String executionDir = getExecutionDir();
    List<File> files = FileUtils.getRecursivelyAllFilesFromDirectory(executionDir);
    for (File file : files) {
        file.delete();
    }
    LOGGER.info(String.format("%d items deleted", files.size()));
}

But then next in @BeforeScenario I try to create subfolder with same name for new execution

public static void setTestCaseDir(String testCaseName) throws IOException {
    testCaseDir = testCaseName.split(StringUtils.SPACE)[0];
    String executionDir = getExecutionDir();
    Path testCaseDirPath = Paths.get(executionDir, testCaseDir);
    boolean isSubDir = readSubdirectories(executionDir)
            .stream()
            .filter(subDir -> subDir.getPath().equals(testCaseDirPath))
            .findFirst()
            .isPresent();
    if (!isSubDir) {
        Files.createDirectory(testCaseDirPath);
    }
    testCaseDir = testCaseDirPath.toString();
}

I receive an eexception:

java.nio.file.AccessDeniedException: D:\...\src\test\resources\execution\TC01

at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:83)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.createDirectory(WindowsFileSystemProvider.java:504)
at java.nio.file.Files.createDirectory(Files.java:674)
at utils.ExecutionUtils.setTestCaseDir(ExecutionUtils.java:56)
at integration.steps.StepDefs.beforeScenario(StepDefs.java:29)

It happens although readSubdirectories() in setTestCaseDir method returns empty list. I see in file explorer that this subdirectories are visible but also with I can't access them. When this execution failed due to this exception this subdfolders are unlocked and disappears.

What process might locked this subfolders and how to solve this problem ?

Jim Garrison
  • 81,234
  • 19
  • 144
  • 183
kris82pl
  • 637
  • 2
  • 8
  • 13
  • You don't show `readSubdirectories`, does this use directory stream? – DuncG Apr 13 '21 at 16:54
  • Is that the COMPLETE stack trace? Lots missing here. Show `getExecutionDir()` , `readSubdirectories()`, `readAllFilesFromDirectory()` and the values of relevant variables at the time of the error. – Jim Garrison Apr 13 '21 at 17:09
  • Does `readSubdirs()` return the files depth-first or breadth-first? Without seeing the methods listed in my previous comment, we cannot possibly help you. – Jim Garrison Apr 13 '21 at 17:19

2 Answers2

2

Note that any lingering un-closed operations on files in the hierarchy can prevent delete from working - so check other tests working on these directories and add try-with-resources for directory streams (Files list / newDirectoryStream) and File Input/Output Streams (also MappedByteBuffer on Windows).

Once that is fixed, a FileVisitor with Files.walkFileTree gives a more reliable way to delete a tree and it will be quicker than recursive File.list on large directory trees:

public static void main(String[] args) throws IOException {
    var paths = Arrays.stream(args).map(Path::of).collect(Collectors.toList());

    FileVisitor<Path> deleteTree = new FileVisitor<>() {
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException  {
            return FileVisitResult.CONTINUE;
        }
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            System.out.println("Delete FILE "+file);
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
            throw exc;
        }
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            System.out.println("Delete DIR "+dir);
            Files.delete(dir);
            return FileVisitResult.CONTINUE;
        }
    };

    for (Path p : paths) {
        Files.walkFileTree(p, deleteTree);
    }
}
DuncG
  • 4,270
  • 1
  • 9
  • 18
0

Inspired by @DuncG I resolved it using NIO2 with Java8

public static void cleanExecutionDirectory() throws IOException {
    LOGGER.info("Cleaning execution directory...");
    File executionDir = new File(getExecutionDir());
    if (executionDir.exists()) {
        Path executionDirPath = Paths.get(getExecutionDir());
        Files.walk(executionDirPath)
                .sorted(Comparator.reverseOrder())
                .forEach(path -> {
                    try {
                        Files.delete(path);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
        LOGGER.info(String.format("Items deleted"));
    }
    executionDir.mkdir();
}
kris82pl
  • 637
  • 2
  • 8
  • 13