Skip to content

Commit d549568

Browse files
committed
Add validation for import/export interger params to make sure they are positive
1 parent 5b268f7 commit d549568

File tree

7 files changed

+139
-0
lines changed

7 files changed

+139
-0
lines changed

core/src/main/java/com/scalar/db/common/error/CoreError.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,14 @@ public enum CoreError implements ScalarDbError {
911911
Category.USER_ERROR, "0203", "Delimiter must not be null", "", ""),
912912
DATA_LOADER_CONFIG_FILE_PATH_BLANK(
913913
Category.USER_ERROR, "0204", "Config file path must not be blank", "", ""),
914+
DATA_LOADER_INVALID_DATA_CHUNK_SIZE(
915+
Category.USER_ERROR, "0206", "Data chunk size must be greater than 0", "", ""),
916+
DATA_LOADER_INVALID_TRANSACTION_SIZE(
917+
Category.USER_ERROR, "0207", "Transaction size must be greater than 0", "", ""),
918+
DATA_LOADER_INVALID_MAX_THREADS(
919+
Category.USER_ERROR, "0208", "Number of max threads must be greater than 0", "", ""),
920+
DATA_LOADER_INVALID_DATA_CHUNK_QUEUE_SIZE(
921+
Category.USER_ERROR, "0209", "Data chunk queue size must be greater than 0", "", ""),
914922

915923
//
916924
// Errors for the concurrency error category

data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/command/dataexport/ExportCommand.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.scalar.db.dataloader.cli.command.dataexport;
22

3+
import static com.scalar.db.dataloader.cli.util.CommandLineInputUtils.validatePositiveValue;
34
import static java.nio.file.StandardOpenOption.APPEND;
45
import static java.nio.file.StandardOpenOption.CREATE;
56

@@ -56,6 +57,10 @@ public Integer call() throws Exception {
5657
try {
5758
validateOutputDirectory();
5859
FileUtils.validateFilePath(scalarDbPropertiesFilePath);
60+
validatePositiveValue(
61+
spec.commandLine(), dataChunkSize, CoreError.DATA_LOADER_INVALID_DATA_CHUNK_SIZE);
62+
validatePositiveValue(
63+
spec.commandLine(), maxThreads, CoreError.DATA_LOADER_INVALID_MAX_THREADS);
5964

6065
StorageFactory storageFactory = StorageFactory.create(scalarDbPropertiesFilePath);
6166
TableMetadataService metaDataService =

data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/command/dataimport/ImportCommand.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.scalar.db.dataloader.cli.command.dataimport;
22

3+
import static com.scalar.db.dataloader.cli.util.CommandLineInputUtils.validatePositiveValue;
4+
35
import com.fasterxml.jackson.databind.ObjectMapper;
46
import com.scalar.db.api.DistributedStorageAdmin;
57
import com.scalar.db.api.TableMetadata;
@@ -52,6 +54,16 @@ public class ImportCommand extends ImportCommandOptions implements Callable<Inte
5254
public Integer call() throws Exception {
5355
validateImportTarget(controlFilePath, namespace, tableName);
5456
validateLogDirectory(logDirectory);
57+
validatePositiveValue(
58+
spec.commandLine(), dataChunkSize, CoreError.DATA_LOADER_INVALID_DATA_CHUNK_SIZE);
59+
validatePositiveValue(
60+
spec.commandLine(), transactionSize, CoreError.DATA_LOADER_INVALID_TRANSACTION_SIZE);
61+
validatePositiveValue(
62+
spec.commandLine(), maxThreads, CoreError.DATA_LOADER_INVALID_MAX_THREADS);
63+
validatePositiveValue(
64+
spec.commandLine(),
65+
dataChunkQueueSize,
66+
CoreError.DATA_LOADER_INVALID_DATA_CHUNK_QUEUE_SIZE);
5567
ControlFile controlFile = parseControlFileFromPath(controlFilePath).orElse(null);
5668
ImportOptions importOptions = createImportOptions(controlFile);
5769
ImportLoggerConfig config =

data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/CommandLineInputUtils.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.Map;
66
import java.util.Objects;
77
import org.apache.commons.lang3.StringUtils;
8+
import picocli.CommandLine;
89

910
public class CommandLineInputUtils {
1011

@@ -46,4 +47,17 @@ public static String[] splitByDelimiter(String value, String delimiter, int limi
4647
delimiter, CoreError.DATA_LOADER_SPLIT_INPUT_DELIMITER_NULL.buildMessage());
4748
return value.split(delimiter, limit);
4849
}
50+
51+
/**
52+
* Validates that a given integer value is positive. If the value is less than 1, it throws a
53+
* {@link CommandLine.ParameterException} with the specified error message.
54+
*
55+
* @param commandLine the {@link CommandLine} instance used to provide context for the exception
56+
* @param value the integer value to validate @
57+
*/
58+
public static void validatePositiveValue(CommandLine commandLine, int value, CoreError error) {
59+
if (value < 1) {
60+
throw new CommandLine.ParameterException(commandLine, error.buildMessage());
61+
}
62+
}
4963
}

data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/command/dataexport/ExportCommandTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ void call_withBlankScalarDBConfigurationFile_shouldThrowException() {
2727
ExportCommand exportCommand = new ExportCommand();
2828
exportCommand.configFilePath = "";
2929
exportCommand.dataChunkSize = 100;
30+
exportCommand.maxThreads = 4;
3031
exportCommand.namespace = "scalar";
3132
exportCommand.table = "asset";
3233
exportCommand.outputDirectory = "";
@@ -46,6 +47,7 @@ void call_withInvalidScalarDBConfigurationFile_shouldReturnOne() throws Exceptio
4647
ExportCommand exportCommand = new ExportCommand();
4748
exportCommand.configFilePath = "scalardb.properties";
4849
exportCommand.dataChunkSize = 100;
50+
exportCommand.maxThreads = 4;
4951
exportCommand.namespace = "scalar";
5052
exportCommand.table = "asset";
5153
exportCommand.outputDirectory = "";

data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/command/dataimport/ImportCommandTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ void call_WithoutValidConfigFile_ShouldThrowException() throws Exception {
4747
importCommand.sourceFileFormat = FileFormat.JSON;
4848
importCommand.sourceFilePath = importFile.toString();
4949
importCommand.importMode = ImportMode.UPSERT;
50+
importCommand.dataChunkSize = 100;
51+
importCommand.transactionSize = 10;
52+
importCommand.maxThreads = 4;
53+
importCommand.dataChunkQueueSize = 64;
5054
assertThrows(IllegalArgumentException.class, () -> importCommand.call());
5155
}
5256

data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/util/CommandLineInputUtilsTest.java

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package com.scalar.db.dataloader.cli.util;
22

33
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
45
import static org.junit.jupiter.api.Assertions.assertEquals;
56
import static org.junit.jupiter.api.Assertions.assertThrows;
67
import static org.junit.jupiter.api.Assertions.assertTrue;
8+
import static org.mockito.Mockito.mock;
79

810
import com.scalar.db.common.error.CoreError;
911
import java.util.Map;
1012
import org.junit.jupiter.api.Test;
13+
import picocli.CommandLine;
1114

1215
class CommandLineInputUtilsTest {
1316

@@ -97,4 +100,95 @@ void splitByDelimiter_nullDelimiter_shouldThrowException() {
97100
.getMessage()
98101
.contains(CoreError.DATA_LOADER_SPLIT_INPUT_DELIMITER_NULL.buildMessage()));
99102
}
103+
104+
@Test
105+
public void validatePositiveValue_positiveValue_shouldNotThrowException() {
106+
// Arrange
107+
CommandLine commandLine = mock(CommandLine.class);
108+
int positiveValue = 5;
109+
110+
// Act & Assert - No exception should be thrown
111+
assertDoesNotThrow(
112+
() ->
113+
CommandLineInputUtils.validatePositiveValue(
114+
commandLine, positiveValue, CoreError.DATA_LOADER_INVALID_DATA_CHUNK_SIZE));
115+
}
116+
117+
@Test
118+
public void validatePositiveValue_one_shouldNotThrowException() {
119+
// Arrange
120+
CommandLine commandLine = mock(CommandLine.class);
121+
int minimumPositiveValue = 1;
122+
123+
// Act & Assert - No exception should be thrown
124+
assertDoesNotThrow(
125+
() ->
126+
CommandLineInputUtils.validatePositiveValue(
127+
commandLine, minimumPositiveValue, CoreError.DATA_LOADER_INVALID_DATA_CHUNK_SIZE));
128+
}
129+
130+
@Test
131+
public void validatePositiveValue_zero_shouldThrowException() {
132+
// Arrange
133+
CommandLine commandLine = mock(CommandLine.class);
134+
int zeroValue = 0;
135+
CoreError error = CoreError.DATA_LOADER_INVALID_DATA_CHUNK_SIZE;
136+
137+
// Act & Assert
138+
CommandLine.ParameterException exception =
139+
assertThrows(
140+
CommandLine.ParameterException.class,
141+
() -> CommandLineInputUtils.validatePositiveValue(commandLine, zeroValue, error));
142+
143+
// Verify the exception message contains the error message
144+
assertTrue(exception.getMessage().contains(error.buildMessage()));
145+
}
146+
147+
@Test
148+
public void validatePositiveValue_negativeValue_shouldThrowException() {
149+
// Arrange
150+
CommandLine commandLine = mock(CommandLine.class);
151+
int negativeValue = -5;
152+
CoreError error = CoreError.DATA_LOADER_INVALID_TRANSACTION_SIZE;
153+
154+
// Act & Assert
155+
CommandLine.ParameterException exception =
156+
assertThrows(
157+
CommandLine.ParameterException.class,
158+
() -> CommandLineInputUtils.validatePositiveValue(commandLine, negativeValue, error));
159+
160+
// Verify the exception message contains the error message
161+
assertTrue(exception.getMessage().contains(error.buildMessage()));
162+
}
163+
164+
@Test
165+
public void validatePositiveValue_differentErrorTypes_shouldUseCorrectErrorMessage() {
166+
// Arrange
167+
CommandLine commandLine = mock(CommandLine.class);
168+
int negativeValue = -1;
169+
170+
// Act & Assert for DATA_LOADER_INVALID_MAX_THREADS
171+
CommandLine.ParameterException exception1 =
172+
assertThrows(
173+
CommandLine.ParameterException.class,
174+
() ->
175+
CommandLineInputUtils.validatePositiveValue(
176+
commandLine, negativeValue, CoreError.DATA_LOADER_INVALID_MAX_THREADS));
177+
assertTrue(
178+
exception1.getMessage().contains(CoreError.DATA_LOADER_INVALID_MAX_THREADS.buildMessage()));
179+
180+
// Act & Assert for DATA_LOADER_INVALID_DATA_CHUNK_QUEUE_SIZE
181+
CommandLine.ParameterException exception2 =
182+
assertThrows(
183+
CommandLine.ParameterException.class,
184+
() ->
185+
CommandLineInputUtils.validatePositiveValue(
186+
commandLine,
187+
negativeValue,
188+
CoreError.DATA_LOADER_INVALID_DATA_CHUNK_QUEUE_SIZE));
189+
assertTrue(
190+
exception2
191+
.getMessage()
192+
.contains(CoreError.DATA_LOADER_INVALID_DATA_CHUNK_QUEUE_SIZE.buildMessage()));
193+
}
100194
}

0 commit comments

Comments
 (0)