Skip to content

Commit

Permalink
Merge pull request real-logic#203 from vyazelenko/master
Browse files Browse the repository at this point in the history
[Java] Do not attempt to delete file/directory if it does not exist plus simplify `deleteIfExists`
  • Loading branch information
mjpt777 authored Feb 9, 2020
2 parents 43cdebd + 4e8abe9 commit 26ed0db
Show file tree
Hide file tree
Showing 2 changed files with 304 additions and 21 deletions.
44 changes: 23 additions & 21 deletions agrona/src/main/java/org/agrona/IoUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@

import static java.nio.channels.FileChannel.MapMode.READ_ONLY;
import static java.nio.channels.FileChannel.MapMode.READ_WRITE;
import static java.nio.file.StandardOpenOption.CREATE_NEW;
import static java.nio.file.StandardOpenOption.READ;
import static java.nio.file.StandardOpenOption.WRITE;
import static java.nio.file.StandardOpenOption.*;

/**
* Collection of IO utilities for dealing with files, especially mapping and un-mapping.
Expand Down Expand Up @@ -141,6 +139,11 @@ public static void fill(final FileChannel fileChannel, final long position, fina
*/
public static void delete(final File file, final boolean ignoreFailures)
{
if (!file.exists())
{
return;
}

if (file.isDirectory())
{
final File[] files = file.listFiles();
Expand Down Expand Up @@ -174,6 +177,11 @@ public static void delete(final File file, final boolean ignoreFailures)
*/
public static void delete(final File file, final ErrorHandler errorHandler)
{
if (!file.exists())
{
return;
}

if (file.isDirectory())
{
final File[] files = file.listFiles();
Expand Down Expand Up @@ -247,16 +255,13 @@ public static void ensureDirectoryIsRecreated(
*/
public static void deleteIfExists(final File file)
{
if (file.exists())
try
{
try
{
Files.delete(file.toPath());
}
catch (final IOException ex)
{
LangUtil.rethrowUnchecked(ex);
}
Files.deleteIfExists(file.toPath());
}
catch (final IOException ex)
{
LangUtil.rethrowUnchecked(ex);
}
}

Expand All @@ -268,16 +273,13 @@ public static void deleteIfExists(final File file)
*/
public static void deleteIfExists(final File file, final ErrorHandler errorHandler)
{
if (file.exists())
try
{
try
{
Files.delete(file.toPath());
}
catch (final Throwable ex)
{
errorHandler.onError(ex);
}
Files.deleteIfExists(file.toPath());
}
catch (final Throwable ex)
{
errorHandler.onError(ex);
}
}

Expand Down
281 changes: 281 additions & 0 deletions agrona/src/test/java/org/agrona/IoUtilTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
/*
* Copyright 2014-2020 Real Logic Limited.
*
* Licensed 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
*
* https://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.agrona;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class IoUtilTest
{

@TempDir
Path tempDir;

@Test
void deleteIgnoreFailuresNonExistingDirectory()
{
final File dir = tempDir.resolve("shadow-dir").toFile();
assertTrue(dir.mkdir());
assertTrue(dir.delete());

IoUtil.delete(dir, false);

assertFalse(dir.exists());
}

@Test
void deleteIgnoreFailuresNonExistingFile()
{
final File file = tempDir.resolve("shadow-file").toFile();

IoUtil.delete(file, false);

assertFalse(file.exists());
}

@Test
void deleteIgnoreFailuresDirectory() throws IOException
{
final Path dir2 = tempDir.resolve("dir1").resolve("dir2");
Files.createDirectories(dir2);
Files.createFile(dir2.resolve("file2.txt"));
Files.createFile(dir2.getParent().resolve("file1.txt"));
final File dir = dir2.getParent().toFile();

IoUtil.delete(dir, false);

assertFalse(dir.exists());
assertFalse(Files.exists(dir2));
}

@Test
void deleteIgnoreFailuresFile() throws IOException
{
final Path file = tempDir.resolve("file.txt");
Files.createFile(file);

IoUtil.delete(file.toFile(), false);

assertFalse(Files.exists(file));
}

@Test
void deleteIgnoreFailuresShouldThrowExceptionIfDeleteOfAFileFails() throws IOException
{
final File file = mock(File.class);
when(file.exists()).thenReturn(true);
when(file.delete()).thenReturn(false);

assertThrows(NullPointerException.class, () -> IoUtil.delete(file, false));
}

@Test
void deleteIgnoreFailuresShouldThrowExceptionIfDeleteOfADirectoryFails() throws IOException
{
final File dir = mock(File.class);
when(dir.exists()).thenReturn(true);
when(dir.isDirectory()).thenReturn(true);
when(dir.delete()).thenReturn(false);

assertThrows(NullPointerException.class, () -> IoUtil.delete(dir, false));
}

@Test
void deleteErrorHandlerNonExistingDirectory()
{
final ErrorHandler errorHandler = mock(ErrorHandler.class);
final File dir = tempDir.resolve("shadow-dir").toFile();
assertTrue(dir.mkdir());
assertTrue(dir.delete());

IoUtil.delete(dir, errorHandler);

assertFalse(dir.exists());
verifyNoInteractions(errorHandler);
}

@Test
void deleteErrorHandlerIgnoreFailuresNonExistingFile()
{
final ErrorHandler errorHandler = mock(ErrorHandler.class);
final File file = tempDir.resolve("shadow-file").toFile();

IoUtil.delete(file, errorHandler);

assertFalse(file.exists());
verifyNoInteractions(errorHandler);
}

@Test
void deleteErrorHandlerDirectory() throws IOException
{
final ErrorHandler errorHandler = mock(ErrorHandler.class);
final Path dir2 = tempDir.resolve("dir1").resolve("dir2");
Files.createDirectories(dir2);
Files.createFile(dir2.resolve("file2.txt"));
Files.createFile(dir2.getParent().resolve("file1.txt"));
final File dir = dir2.getParent().toFile();

IoUtil.delete(dir, errorHandler);

assertFalse(dir.exists());
assertFalse(Files.exists(dir2));
verifyNoInteractions(errorHandler);
}

@Test
void deleteErrorHandlerFile() throws IOException
{
final ErrorHandler errorHandler = mock(ErrorHandler.class);
final Path file = tempDir.resolve("file.txt");
Files.createFile(file);

IoUtil.delete(file.toFile(), errorHandler);

assertFalse(Files.exists(file));
verifyNoInteractions(errorHandler);
}

@Test
void deleteErrorHandlerShouldCatchExceptionIfDeleteOfAFileFails() throws IOException
{
final ErrorHandler errorHandler = mock(ErrorHandler.class);
final File file = mock(File.class);
when(file.exists()).thenReturn(true);
when(file.delete()).thenReturn(false);

IoUtil.delete(file, errorHandler);

verify(errorHandler).onError(isA(NullPointerException.class));
}

@Test
void deleteErrorHandlerShouldCatchExceptionIfDeleteOfADirectoryFails() throws IOException
{
final ErrorHandler errorHandler = mock(ErrorHandler.class);
final File dir = mock(File.class);
when(dir.exists()).thenReturn(true);
when(dir.isDirectory()).thenReturn(true);
when(dir.delete()).thenReturn(false);

IoUtil.delete(dir, errorHandler);

verify(errorHandler).onError(isA(NullPointerException.class));
}

@Test
void deleteIfExistsNonExistingFile()
{
final Path file = tempDir.resolve("non-existing.txt");

IoUtil.deleteIfExists(file.toFile());

assertFalse(Files.exists(file));
}

@Test
void deleteIfExistsFile() throws IOException
{
final Path file = tempDir.resolve("delete-me.txt");
Files.createFile(file);

IoUtil.deleteIfExists(file.toFile());

assertFalse(Files.exists(file));
}

@Test
void deleteIfExistsEmptyDirectory() throws IOException
{
final Path dir = tempDir.resolve("dir");
Files.createDirectory(dir);

IoUtil.deleteIfExists(dir.toFile());

assertFalse(Files.exists(dir));
}

@Test
void deleteIfExistsFailsOnNonEmptyDirectory() throws IOException
{
final Path dir = tempDir.resolve("dir");
Files.createDirectory(dir);
Files.createFile(dir.resolve("file.txt"));

assertThrows(DirectoryNotEmptyException.class, () -> IoUtil.deleteIfExists(dir.toFile()));
}

@Test
void deleteIfExistsErrorHandlerNonExistingFile()
{
final ErrorHandler errorHandler = mock(ErrorHandler.class);
final Path file = tempDir.resolve("non-existing.txt");

IoUtil.deleteIfExists(file.toFile(), errorHandler);

assertFalse(Files.exists(file));
verifyNoInteractions(errorHandler);
}

@Test
void deleteIfExistsErrorHandlerFile() throws IOException
{
final ErrorHandler errorHandler = mock(ErrorHandler.class);
final Path file = tempDir.resolve("delete-me.txt");
Files.createFile(file);

IoUtil.deleteIfExists(file.toFile(), errorHandler);

assertFalse(Files.exists(file));
verifyNoInteractions(errorHandler);
}

@Test
void deleteIfExistsErrorHandlerEmptyDirectory() throws IOException
{
final ErrorHandler errorHandler = mock(ErrorHandler.class);
final Path dir = tempDir.resolve("dir");
Files.createDirectory(dir);

IoUtil.deleteIfExists(dir.toFile(), errorHandler);

assertFalse(Files.exists(dir));
verifyNoInteractions(errorHandler);
}

@Test
void deleteIfExistsErrorHandlerFailsOnNonEmptyDirectory() throws IOException
{
final ErrorHandler errorHandler = mock(ErrorHandler.class);
final Path dir = tempDir.resolve("dir");
Files.createDirectory(dir);
Files.createFile(dir.resolve("file.txt"));

IoUtil.deleteIfExists(dir.toFile(), errorHandler);

verify(errorHandler).onError(isA(DirectoryNotEmptyException.class));
}

}

0 comments on commit 26ed0db

Please sign in to comment.