diff --git a/core/src/main/java/com/scalar/db/common/error/CoreError.java b/core/src/main/java/com/scalar/db/common/error/CoreError.java index 8bad18ad0c..6185493f20 100644 --- a/core/src/main/java/com/scalar/db/common/error/CoreError.java +++ b/core/src/main/java/com/scalar/db/common/error/CoreError.java @@ -865,6 +865,37 @@ public enum CoreError implements ScalarDbError { "The replication feature is not enabled. To use this feature, you must enable it", "", ""), + DATA_LOADER_IMPORT_TARGET_MISSING( + Category.USER_ERROR, + "0189", + "Missing option: either '--namespace' and'--table' or '--control-file' options must be specified.", + "", + ""), + DATA_LOADER_MISSING_IMPORT_FILE( + Category.USER_ERROR, + "0190", + "The file '%s' specified by the argument '%s' does not exist.", + "", + ""), + DATA_LOADER_LOG_DIRECTORY_WRITE_ACCESS_DENIED( + Category.USER_ERROR, "0191", "Cannot write to the log directory: %s", "", ""), + DATA_LOADER_LOG_DIRECTORY_CREATION_FAILED( + Category.USER_ERROR, "0192", "Failed to create the log directory: %s", "", ""), + DATA_LOADER_INVALID_CONTROL_FILE( + Category.USER_ERROR, "0193", "Failed to parse the control file: %s", "", ""), + DATA_LOADER_DIRECTORY_WRITE_ACCESS( + Category.USER_ERROR, + "0194", + "No permission to create or write files in the directory: %s", + "", + ""), + DATA_LOADER_DIRECTORY_CREATION_FAILED( + Category.USER_ERROR, "0195", "Failed to create the directory: %s", "", ""), + DATA_LOADER_PATH_IS_NOT_A_DIRECTORY( + Category.USER_ERROR, "0196", "Path exists but is not a directory: %s", "", ""), + DATA_LOADER_FILE_PATH_IS_BLANK( + Category.USER_ERROR, "0197", "File path must not be blank.", "", ""), + DATA_LOADER_FILE_NOT_FOUND(Category.USER_ERROR, "0198", "File not found: %s", "", ""), // // Errors for the concurrency error category diff --git a/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/command/dataexport/ExportCommand.java b/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/command/dataexport/ExportCommand.java index 873fad3c22..4c88be4594 100644 --- a/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/command/dataexport/ExportCommand.java +++ b/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/command/dataexport/ExportCommand.java @@ -49,9 +49,9 @@ private void validateOutputDirectory(@Nullable String path) private void validateDirectory(String directoryPath) throws DirectoryValidationException { // If the directory path is null or empty, use the current working directory if (directoryPath == null || directoryPath.isEmpty()) { - DirectoryUtils.validateTargetDirectory(DirectoryUtils.getCurrentWorkingDirectory()); + DirectoryUtils.validateOrCreateTargetDirectory(DirectoryUtils.getCurrentWorkingDirectory()); } else { - DirectoryUtils.validateTargetDirectory(directoryPath); + DirectoryUtils.validateOrCreateTargetDirectory(directoryPath); } } diff --git a/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/DirectoryUtils.java b/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/DirectoryUtils.java old mode 100644 new mode 100755 index decb0f9ae7..a9a14ca4d7 --- a/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/DirectoryUtils.java +++ b/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/DirectoryUtils.java @@ -15,6 +15,22 @@ private DirectoryUtils() { // restrict instantiation } + /** + * Validates the current working directory. Ensures that it is writable. + * + * @throws DirectoryValidationException if the current working directory is not writable + */ + public static void validateWorkingDirectory() throws DirectoryValidationException { + Path workingDirectoryPath = Paths.get(System.getProperty("user.dir")); + + // Check if the current working directory is writable + if (!Files.isWritable(workingDirectoryPath)) { + throw new DirectoryValidationException( + CoreError.DATA_LOADER_DIRECTORY_WRITE_ACCESS.buildMessage( + workingDirectoryPath.toAbsolutePath())); + } + } + /** * Validates the provided directory path. Ensures that the directory exists and is writable. If * the directory doesn't exist, a creation attempt is made. @@ -22,7 +38,7 @@ private DirectoryUtils() { * @param directoryPath the directory path to validate * @throws DirectoryValidationException if the directory is not writable or cannot be created */ - public static void validateTargetDirectory(String directoryPath) + public static void validateOrCreateTargetDirectory(String directoryPath) throws DirectoryValidationException { if (StringUtils.isBlank(directoryPath)) { throw new IllegalArgumentException( @@ -32,7 +48,10 @@ public static void validateTargetDirectory(String directoryPath) Path path = Paths.get(directoryPath); if (Files.exists(path)) { - // Check if the provided directory is writable + if (!Files.isDirectory(path)) { + throw new DirectoryValidationException( + CoreError.DATA_LOADER_PATH_IS_NOT_A_DIRECTORY.buildMessage(path)); + } if (!Files.isWritable(path)) { throw new DirectoryValidationException( CoreError.DATA_LOADER_DIRECTORY_WRITE_ACCESS_NOT_ALLOWED.buildMessage( diff --git a/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/FileUtils.java b/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/FileUtils.java new file mode 100755 index 0000000000..ecaf341409 --- /dev/null +++ b/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/FileUtils.java @@ -0,0 +1,27 @@ +package com.scalar.db.dataloader.cli.util; + +import com.scalar.db.common.error.CoreError; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.apache.commons.lang3.StringUtils; + +public class FileUtils { + + /** + * Validates the provided file path. + * + * @param filePath the file path to validate + * @throws InvalidFilePathException if the file path is invalid + */ + public static void validateFilePath(String filePath) throws InvalidFilePathException { + if (StringUtils.isBlank(filePath)) { + throw new IllegalArgumentException(CoreError.DATA_LOADER_FILE_PATH_IS_BLANK.buildMessage()); + } + Path pathToCheck = Paths.get(filePath); + + if (!pathToCheck.toFile().exists()) { + throw new InvalidFilePathException( + CoreError.DATA_LOADER_FILE_NOT_FOUND.buildMessage(pathToCheck)); + } + } +} diff --git a/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/InvalidFilePathException.java b/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/InvalidFilePathException.java new file mode 100755 index 0000000000..d9e018286d --- /dev/null +++ b/data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/InvalidFilePathException.java @@ -0,0 +1,12 @@ +package com.scalar.db.dataloader.cli.util; + +public class InvalidFilePathException extends Exception { + + public InvalidFilePathException(String message) { + super(message); + } + + public InvalidFilePathException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/util/DirectoryUtilsTest.java b/data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/util/DirectoryUtilsTest.java old mode 100644 new mode 100755 index 60c0eafa60..ad4db52f0d --- a/data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/util/DirectoryUtilsTest.java +++ b/data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/util/DirectoryUtilsTest.java @@ -30,26 +30,26 @@ public void cleanup() throws IOException { @Test void validateTargetDirectory_ValidDirectory_NoExceptionThrown() throws DirectoryValidationException { - DirectoryUtils.validateTargetDirectory(tempDir.toString()); + DirectoryUtils.validateOrCreateTargetDirectory(tempDir.toString()); } @Test - void validateTargetDirectory_DirectoryDoesNotExist_CreatesDirectory() + void validateOrCreateTargetDirectory_DirectoryDoesNotExist_CreatesDirectory() throws DirectoryValidationException { Path newDirectory = Paths.get(tempDir.toString(), "newDir"); - DirectoryUtils.validateTargetDirectory(newDirectory.toString()); + DirectoryUtils.validateOrCreateTargetDirectory(newDirectory.toString()); assertTrue(Files.exists(newDirectory)); } @Test - void validateTargetDirectory_DirectoryNotWritable_ThrowsException() throws IOException { + void validateOrCreateTargetDirectory_DirectoryNotWritable_ThrowsException() throws IOException { Path readOnlyDirectory = Files.createDirectory(Paths.get(tempDir.toString(), "readOnlyDir")); readOnlyDirectory.toFile().setWritable(false); assertThrows( DirectoryValidationException.class, () -> { - DirectoryUtils.validateTargetDirectory(readOnlyDirectory.toString()); + DirectoryUtils.validateOrCreateTargetDirectory(readOnlyDirectory.toString()); }); } @@ -58,16 +58,16 @@ void validateTargetDirectory_NullDirectory_ThrowsException() { assertThrows( IllegalArgumentException.class, () -> { - DirectoryUtils.validateTargetDirectory(null); + DirectoryUtils.validateOrCreateTargetDirectory(null); }); } @Test - void validateTargetDirectory_EmptyDirectory_ThrowsException() { + void validateOrCreateTargetDirectory_EmptyDirectory_ThrowsException() { assertThrows( IllegalArgumentException.class, () -> { - DirectoryUtils.validateTargetDirectory(""); + DirectoryUtils.validateOrCreateTargetDirectory(""); }); } diff --git a/data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/util/FileUtilsTest.java b/data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/util/FileUtilsTest.java new file mode 100755 index 0000000000..550fbd32f9 --- /dev/null +++ b/data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/util/FileUtilsTest.java @@ -0,0 +1,33 @@ +package com.scalar.db.dataloader.cli.util; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.scalar.db.common.error.CoreError; +import java.nio.file.Paths; +import org.junit.jupiter.api.Test; + +public class FileUtilsTest { + + private static final String currentPath = Paths.get("").toAbsolutePath().toString(); + + @Test + void validateFilePath_withValidFilePath_shouldNotThrowException() + throws InvalidFilePathException { + // Test and confirm no exception is thrown when a valid path is provided + FileUtils.validateFilePath(currentPath); + } + + @Test + void validateFilePath_withInvalidFilePath_shouldThrowException() { + assertThatThrownBy(() -> FileUtils.validateFilePath(currentPath + "/demo")) + .isInstanceOf(InvalidFilePathException.class) + .hasMessage(CoreError.DATA_LOADER_FILE_NOT_FOUND.buildMessage(currentPath + "/demo")); + } + + @Test + void validateFilePath_withBlankFilePath_shouldThrowException() { + assertThatThrownBy(() -> FileUtils.validateFilePath("")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage(CoreError.DATA_LOADER_FILE_PATH_IS_BLANK.buildMessage()); + } +}