Skip to content

Commit

Permalink
refactor: use commons module in server (#272)
Browse files Browse the repository at this point in the history
Signed-off-by: Atanas Atanasov <[email protected]>
  • Loading branch information
ata-nas authored Oct 31, 2024
1 parent 5fe56b2 commit 791af49
Show file tree
Hide file tree
Showing 20 changed files with 361 additions and 488 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,104 +38,73 @@ public final class FileUtilities {
* Default permissions are set to: rw-r--r--
*/
private static final FileAttribute<Set<PosixFilePermission>> DEFAULT_FILE_PERMISSIONS =
PosixFilePermissions.asFileAttribute(
Set.of(
PosixFilePermission.OWNER_READ,
PosixFilePermission.OWNER_WRITE,
PosixFilePermission.GROUP_READ,
PosixFilePermission.OTHERS_READ));
PosixFilePermissions.asFileAttribute(Set.of(
PosixFilePermission.OWNER_READ,
PosixFilePermission.OWNER_WRITE,
PosixFilePermission.GROUP_READ,
PosixFilePermission.OTHERS_READ));

/**
* Default folder permissions for new folders.
* <p>
* Default permissions are set to: rwxr-xr-x
*/
private static final FileAttribute<Set<PosixFilePermission>> DEFAULT_FOLDER_PERMISSIONS =
PosixFilePermissions.asFileAttribute(
Set.of(
PosixFilePermission.OWNER_READ,
PosixFilePermission.OWNER_WRITE,
PosixFilePermission.OWNER_EXECUTE,
PosixFilePermission.GROUP_READ,
PosixFilePermission.GROUP_EXECUTE,
PosixFilePermission.OTHERS_READ,
PosixFilePermission.OTHERS_EXECUTE));
PosixFilePermissions.asFileAttribute(Set.of(
PosixFilePermission.OWNER_READ,
PosixFilePermission.OWNER_WRITE,
PosixFilePermission.OWNER_EXECUTE,
PosixFilePermission.GROUP_READ,
PosixFilePermission.GROUP_EXECUTE,
PosixFilePermission.OTHERS_READ,
PosixFilePermission.OTHERS_EXECUTE));

/**
* Log message template used when a path is not created because a file
* or folder already exists at the requested path.
*/
private static final String PRE_EXISTING_FOLDER_MESSAGE =
"Requested %s [%s] not created because %s already exists at %s";

/**
* Create a new path (folder or file) if it does not exist.
* Any folders or files created will use default permissions.
* Create a new path (folder) if it does not exist.
* Any folders created will use default permissions.
*
* @param toCreate valid, non-null instance of {@link Path} to be created
* @param logLevel valid, non-null instance of {@link System.Logger.Level} to use
* @param semanticPathName valid, non-blank {@link String} used for logging that represents the
* desired path semantically
* @param createDir {@link Boolean} value if we should create a directory or a file
* @throws IOException if the path cannot be created
*/
public static void createPathIfNotExists(
public static void createFolderPathIfNotExists(
@NonNull final Path toCreate,
@NonNull final System.Logger.Level logLevel,
@NonNull final String semanticPathName,
final boolean createDir)
@NonNull final String semanticPathName)
throws IOException {
createPathIfNotExists(
toCreate,
logLevel,
DEFAULT_FILE_PERMISSIONS,
DEFAULT_FOLDER_PERMISSIONS,
semanticPathName,
createDir);
createFolderPathIfNotExists(toCreate, logLevel, DEFAULT_FOLDER_PERMISSIONS, semanticPathName);
}

/**
* Create a new path (folder or file) if it does not exist.
* Create a new path (folder) if it does not exist.
*
* @param toCreate The path to be created.
* @param logLevel The logging level to use when logging this event.
* @param filePermissions Permissions to use when creating a new file.
* @param folderPermissions Permissions to use when creating a new folder.
* @param semanticPathName A name to represent the path in a logging
* @param permissions Permissions to use when creating the path.
* @param semanticPathName A name (non-blank) to represent the path in a logging
* statement.
* @param createDir A flag indicating we should create a directory
* (true) or a file (false)
* @throws IOException if the path cannot be created due to a filesystem
* error.
*/
public static void createPathIfNotExists(
public static void createFolderPathIfNotExists(
@NonNull final Path toCreate,
@NonNull final System.Logger.Level logLevel,
@NonNull final FileAttribute<Set<PosixFilePermission>> filePermissions,
@NonNull final FileAttribute<Set<PosixFilePermission>> folderPermissions,
@NonNull final String semanticPathName,
final boolean createDir)
@NonNull final FileAttribute<Set<PosixFilePermission>> permissions,
@NonNull final String semanticPathName)
throws IOException {
Objects.requireNonNull(toCreate);
Objects.requireNonNull(logLevel);
Objects.requireNonNull(filePermissions);
Objects.requireNonNull(folderPermissions);
Objects.requireNonNull(permissions);
StringUtilities.requireNotBlank(semanticPathName);
final String requestedType = createDir ? "directory" : "file";
if (Files.notExists(toCreate)) {
if (createDir) {
Files.createDirectories(toCreate, folderPermissions);
} else {
Files.createFile(toCreate, filePermissions);
}
final String logMessage =
"Created %s [%s] at %s".formatted(requestedType, semanticPathName, toCreate);
Files.createDirectories(toCreate, permissions);
final String logMessage = "Created [%s] at '%s'".formatted(semanticPathName, toCreate);
LOGGER.log(logLevel, logMessage);
} else {
final String actualType = Files.isDirectory(toCreate) ? "directory" : "file";
final String logMessage =
PRE_EXISTING_FOLDER_MESSAGE.formatted(
requestedType, semanticPathName, actualType, toCreate);
final String logMessage = "Requested [%s] not created because the directory already exists at '%s'"
.formatted(semanticPathName, toCreate);
LOGGER.log(logLevel, logMessage);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,29 @@
import java.lang.System.Logger.Level;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

/**
* Tests for {@link FileUtilities} functionality.
*/
class FileUtilitiesTest {
private static final String FILE_WITH_UNRECOGNIZED_EXTENSION = "src/test/resources/nonexistent.unrecognized";

/**
* This test aims to verify that a folder path will be created for a given
* path if it does not exist. First we assert that the path we want to make
* does not exist, then we run the actual method and assert that the path
* was created and is an empty folder.
*
* @param tempDir junit temp dir
* @throws IOException propagated from {@link FileUtilities#createFolderPathIfNotExists(Path, Level, String)}
*/
@Test
void test_createPathIfNotExists_CreatesDirIfDoesNotExist(@TempDir final Path tempDir) throws IOException {
void testCreateFolderPathIfNotExists(@TempDir final Path tempDir) throws IOException {
final String newDir = "newDir";
final Path toCreate = tempDir.resolve(newDir);

Expand All @@ -44,15 +55,24 @@ void test_createPathIfNotExists_CreatesDirIfDoesNotExist(@TempDir final Path tem
assertThat(toCreate).doesNotExist();

// run actual
FileUtilities.createPathIfNotExists(toCreate, Level.ERROR, "test dir 1", true);
FileUtilities.createFolderPathIfNotExists(toCreate, Level.ERROR, "test dir 1");

// assert
assertThat(toCreate).exists().isDirectory();
assertThat(tempDir.toFile().listFiles()).hasSize(1).contains(toCreate.toFile());
}

/**
* This test aims to verify that a folder path will not be created for a
* given path if it already exists. First we assert that the path we want to
* make already exists, then we run the actual method and assert that the
* path was unchanged and is an empty folder and nothing else was created.
*
* @param tempDir junit temp dir
* @throws IOException propagated from {@link FileUtilities#createFolderPathIfNotExists(Path, Level, String)}
*/
@Test
void test_createPathIfNotExists_DoesNotCreateDirIfExists(@TempDir final Path tempDir) throws IOException {
void testSkipFolderCreationIfPathExists(@TempDir final Path tempDir) throws IOException {
final String newDir = "newDir";
final Path toCreate = tempDir.resolve(newDir);

Expand All @@ -70,60 +90,24 @@ void test_createPathIfNotExists_DoesNotCreateDirIfExists(@TempDir final Path tem
assertThat(toCreate).exists().isDirectory();

// run actual
FileUtilities.createPathIfNotExists(toCreate, Level.ERROR, "test dir 1", true);
FileUtilities.createFolderPathIfNotExists(toCreate, Level.ERROR, "test dir 1");

// assert
assertThat(toCreate).exists().isDirectory();
assertThat(tempDirAsFile.listFiles()).hasSize(1).contains(toCreateAsFile);
}

@Test
void test_createPathIfNotExists_CreatesFileIfDoesNotExist(@TempDir final Path tempDir) throws IOException {
final String newFile = "newFile";
final Path toCreate = tempDir.resolve(newFile);

// ensure the temp directory is empty in the beginning
assertThat(tempDir).isEmptyDirectory();
assertThat(toCreate).doesNotExist();

// run actual
FileUtilities.createPathIfNotExists(toCreate, Level.ERROR, "test file 1", false);

// assert
assertThat(toCreate).exists().isEmptyFile();
assertThat(tempDir.toFile().listFiles()).hasSize(1).contains(toCreate.toFile());
}

@Test
void test_createPathIfNotExists_DoesNotCreateFileIfExists(@TempDir final Path tempDir) throws IOException {
final String newFile = "newFile";
final Path toCreate = tempDir.resolve(newFile);

// ensure the temp directory is empty in the beginning
assertThat(tempDir).isEmptyDirectory();
assertThat(toCreate).doesNotExist();

// create 'newFile'
Files.createFile(toCreate);

// ensure the temp directory contains only 'newFile' before running actual
final File tempDirAsFile = tempDir.toFile();
final File toCreateAsFile = toCreate.toFile();
assertThat(tempDirAsFile.listFiles()).hasSize(1).contains(toCreateAsFile);
assertThat(toCreate).exists().isEmptyFile();

// run actual
FileUtilities.createPathIfNotExists(toCreate, Level.ERROR, "test file 1", false);

// assert
assertThat(toCreate).exists().isEmptyFile();
assertThat(tempDirAsFile.listFiles()).hasSize(1).contains(toCreateAsFile);
}

/**
* This test aims to verify that reading a gzip file that exists and is
* valid, will return a byte array with the expected content.
*
* @param filePath parameterized, to read gzip files from
* @param expectedContent parameterized, expected content after reading the file
* @throws IOException propagated from {@link FileUtilities#readGzipFileUnsafe(Path)}
*/
@ParameterizedTest
@MethodSource("validGzipFiles")
void test_readGzipFileUnsafe_ReturnsByteArrayWithValidContentForValidGzipFile(
final Path filePath, final String expectedContent) throws IOException {
void testReadGzipFileUnsafe(final Path filePath, final String expectedContent) throws IOException {
final byte[] actualContent = FileUtilities.readGzipFileUnsafe(filePath);
assertThat(actualContent)
.isNotNull()
Expand All @@ -134,63 +118,77 @@ void test_readGzipFileUnsafe_ReturnsByteArrayWithValidContentForValidGzipFile(
.isEqualTo(expectedContent);
}

/**
* This test aims to verify that reading an invalid gzip file throws an
* {@link IOException}.
*
* @param filePath parameterized, to read gzip files from
*/
@ParameterizedTest
@MethodSource("invalidFiles")
void test_readGzipFileUnsafe_ThrowsIOExceptionForInvalidGzipFile(final Path filePath) {
void testReadGzipFileUnsafeThrows(final Path filePath) {
assertThatIOException().isThrownBy(() -> FileUtilities.readGzipFileUnsafe(filePath));
}

/**
* This test aims to verify that reading a file that exists and is valid and
* is found by the extension parameter, will return a byte array with the
* expected content.
*
* @param filePath parameterized, to read files from
* @param expectedContent parameterized, expected content after reading the file
* @throws IOException propagated from {@link FileUtilities#readFileBytesUnsafe(Path)}
* and {@link FileUtilities#readFileBytesUnsafe(Path, String, String)}
*/
@ParameterizedTest
@MethodSource({"validGzipFiles", "validBlkFiles"})
void test_readFileBytesUnsafe_ReturnsByteArrayWithValidContentForValidFile(
final Path filePath, final String expectedContent) throws IOException {
final byte[] actualContent = FileUtilities.readFileBytesUnsafe(filePath);
assertThat(actualContent)
.isNotNull()
.isNotEmpty()
.asString()
.isNotNull()
.isNotBlank()
.isEqualTo(expectedContent);
}

@Test
void test_readFileBytesUnsafe_ReturnsNullByteArrayWhenExtensionIsNotRecognized() throws IOException {
final byte[] actualContent = FileUtilities.readFileBytesUnsafe(Path.of(FILE_WITH_UNRECOGNIZED_EXTENSION));
assertThat(actualContent).isNull();
}

@ParameterizedTest
@MethodSource("invalidFiles")
void test_readFileBytesUnsafe_ThrowsIOExceptionForInvalidGzipFile(final Path filePath) {
assertThatIOException().isThrownBy(() -> FileUtilities.readFileBytesUnsafe(filePath));
}
void testReadFileBytesUnsafe(final Path filePath, final String expectedContent) throws IOException {
final Consumer<byte[]> asserts = actual -> {
assertThat(actual)
.isNotNull()
.isNotEmpty()
.asString()
.isNotNull()
.isNotBlank()
.isEqualTo(expectedContent);
};

@ParameterizedTest
@MethodSource({"validGzipFiles", "validBlkFiles"})
void test_readFileBytesUnsafe_ReturnsByteArrayWithValidContentForValidFileWithGivenExtension(
final Path filePath, final String expectedContent) throws IOException {
final byte[] actualContent = FileUtilities.readFileBytesUnsafe(filePath, ".blk", ".gz");
assertThat(actualContent)
.isNotNull()
.isNotEmpty()
.asString()
.isNotNull()
.isNotBlank()
.isEqualTo(expectedContent);
assertThat(actualContent).satisfies(asserts);

// overloaded has same extensions as above
final byte[] actualContentOverloaded = FileUtilities.readFileBytesUnsafe(filePath);
assertThat(actualContentOverloaded).satisfies(asserts);
}

/**
* This test aims to verify that reading a file that is not recognized by
* the block file extension we provide, will return null.
*
* @throws IOException propagated from {@link FileUtilities#readFileBytesUnsafe(Path)}
* and {@link FileUtilities#readFileBytesUnsafe(Path, String, String)}
*/
@Test
void test_readFileBytesUnsafe_ReturnsNullByteArrayWhenExtensionIsNotRecognizedWithGivenExtension()
throws IOException {
final byte[] actualContent =
FileUtilities.readFileBytesUnsafe(Path.of(FILE_WITH_UNRECOGNIZED_EXTENSION), ".blk", ".gz");
void testReadFileBytesUnsafeReturnsNull() throws IOException {
final Path path = Path.of("src/test/resources/nonexistent.unrecognized");

final byte[] actualContent = FileUtilities.readFileBytesUnsafe(path, ".blk", ".gz");
assertThat(actualContent).isNull();

final byte[] actualContentOverloaded = FileUtilities.readFileBytesUnsafe(path);
assertThat(actualContentOverloaded).isNull();
}

/**
* This test aims to verify that reading an invalid file, be that it is
* in some way corrupted or nonexistent, will throw an {@link IOException}.
*
* @param filePath parameterized, to read block files from
*/
@ParameterizedTest
@MethodSource("invalidFiles")
void test_readFileBytesUnsafe_ThrowsIOExceptionForInvalidGzipFileWithGivenExtension(final Path filePath) {
void testReadFileBytesUnsafeThrows(final Path filePath) {
assertThatIOException().isThrownBy(() -> FileUtilities.readFileBytesUnsafe(filePath));
assertThatIOException().isThrownBy(() -> FileUtilities.readFileBytesUnsafe(filePath, ".blk", ".gz"));
}

Expand All @@ -208,6 +206,8 @@ private static Stream<Arguments> validBlkFiles() {

private static Stream<Arguments> invalidFiles() {
return Stream.of(
Arguments.of("src/test/resources/invalid1.gz"), Arguments.of("src/test/resources/nonexistent.gz"));
Arguments.of("src/test/resources/invalid1.gz"),
Arguments.of("src/test/resources/nonexistent.gz"),
Arguments.of("src/test/resources/nonexistent.blk"));
}
}
Loading

0 comments on commit 791af49

Please sign in to comment.