This is an automated email from the ASF dual-hosted git repository.
jmclean pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new c16f5955d6 [#6086] fix(CLI): Refactor the validation logic of Metalake
(#6091)
c16f5955d6 is described below
commit c16f5955d64208da5f9b09c5ebc33471f56bfaef
Author: Lord of Abyss <[email protected]>
AuthorDate: Mon Jan 6 06:09:53 2025 +0800
[#6086] fix(CLI): Refactor the validation logic of Metalake (#6091)
### What changes were proposed in this pull request?
Add `validate` method to Command, and refactor the validation code.
### Why are the changes needed?
Fix: #6086
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
#### UT
local ut
#### bash
```bash
gcli metalake set
# Missing --metalake option.
gcli metalake details
# Missing --metalake option.
gcli metalake set -m demo_metalake
# Missing --property and --value options.
gcli metalake set -m demo_metalake --property propertyA
# Missing --value option.
gcli metalake set -m demo_metalake --value valA
# Missing --property option.
gcli metalake details --audit
# Missing --metalake option.
gcli metalake remove -m demo_metalake
# Missing --property option.
gcli metalake update -m demo_metalake
# The command does nothing.
```
---------
Co-authored-by: roryqi <[email protected]>
Co-authored-by: Yuhui <[email protected]>
Co-authored-by: Qiming Teng <[email protected]>
---
.../org/apache/gravitino/cli/ErrorMessages.java | 2 +
.../java/org/apache/gravitino/cli/FullName.java | 1 +
.../apache/gravitino/cli/GravitinoCommandLine.java | 40 ++++++------
.../org/apache/gravitino/cli/commands/Command.java | 17 ++++-
.../cli/commands/RemoveMetalakeProperty.java | 6 ++
.../cli/commands/SetMetalakeProperty.java | 8 +++
.../org/apache/gravitino/cli/TestFulllName.java | 7 +--
.../apache/gravitino/cli/TestMetalakeCommands.java | 72 +++++++++++++++++++++-
8 files changed, 126 insertions(+), 27 deletions(-)
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
index e90c525963..7fd4e27221 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
@@ -37,6 +37,8 @@ public class ErrorMessages {
public static final String MISSING_ROLE = "Missing --role option.";
public static final String MISSING_TAG = "Missing --tag option.";
public static final String MISSING_URI = "Missing --uri option.";
+ public static final String MISSING_PROPERTY = "Missing --property option.";
+ public static final String MISSING_VALUE = "Missing --value option.";
public static final String METALAKE_EXISTS = "Metalake already exists.";
public static final String CATALOG_EXISTS = "Catalog already exists.";
public static final String SCHEMA_EXISTS = "Schema already exists.";
diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java
index a3b206dfdd..7a9481cb95 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java
@@ -74,6 +74,7 @@ public class FullName {
}
System.err.println(ErrorMessages.MISSING_METALAKE);
+ Main.exit(-1);
return null;
}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java
index 3a9322d010..f8347dfe1f 100644
---
a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java
@@ -30,7 +30,6 @@ import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
@@ -167,51 +166,49 @@ public class GravitinoCommandLine extends
TestableCommandLine {
String auth = getAuth();
String userName = line.getOptionValue(GravitinoOptions.LOGIN);
FullName name = new FullName(line);
- String metalake = name.getMetalakeName();
String outputFormat = line.getOptionValue(GravitinoOptions.OUTPUT);
Command.setAuthenticationMode(auth, userName);
+ if (CommandActions.LIST.equals(command)) {
+ newListMetalakes(url, ignore, outputFormat).validate().handle();
+ return;
+ }
+
+ String metalake = name.getMetalakeName();
+
switch (command) {
case CommandActions.DETAILS:
if (line.hasOption(GravitinoOptions.AUDIT)) {
- newMetalakeAudit(url, ignore, metalake).handle();
+ newMetalakeAudit(url, ignore, metalake).validate().handle();
} else {
- newMetalakeDetails(url, ignore, outputFormat, metalake).handle();
+ newMetalakeDetails(url, ignore, outputFormat,
metalake).validate().handle();
}
break;
- case CommandActions.LIST:
- newListMetalakes(url, ignore, outputFormat).handle();
- break;
-
case CommandActions.CREATE:
- if (Objects.isNull(metalake)) {
- System.err.println(CommandEntities.METALAKE + " is not defined");
- Main.exit(-1);
- }
String comment = line.getOptionValue(GravitinoOptions.COMMENT);
- newCreateMetalake(url, ignore, metalake, comment).handle();
+ newCreateMetalake(url, ignore, metalake, comment).validate().handle();
break;
case CommandActions.DELETE:
boolean force = line.hasOption(GravitinoOptions.FORCE);
- newDeleteMetalake(url, ignore, force, metalake).handle();
+ newDeleteMetalake(url, ignore, force, metalake).validate().handle();
break;
case CommandActions.SET:
String property = line.getOptionValue(GravitinoOptions.PROPERTY);
String value = line.getOptionValue(GravitinoOptions.VALUE);
- newSetMetalakeProperty(url, ignore, metalake, property,
value).handle();
+ newSetMetalakeProperty(url, ignore, metalake, property,
value).validate().handle();
break;
case CommandActions.REMOVE:
property = line.getOptionValue(GravitinoOptions.PROPERTY);
- newRemoveMetalakeProperty(url, ignore, metalake, property).handle();
+ newRemoveMetalakeProperty(url, ignore, metalake,
property).validate().handle();
break;
case CommandActions.PROPERTIES:
- newListMetalakeProperties(url, ignore, metalake).handle();
+ newListMetalakeProperties(url, ignore, metalake).validate().handle();
break;
case CommandActions.UPDATE:
@@ -221,21 +218,22 @@ public class GravitinoCommandLine extends
TestableCommandLine {
}
if (line.hasOption(GravitinoOptions.ENABLE)) {
boolean enableAllCatalogs = line.hasOption(GravitinoOptions.ALL);
- newMetalakeEnable(url, ignore, metalake, enableAllCatalogs).handle();
+ newMetalakeEnable(url, ignore, metalake,
enableAllCatalogs).validate().handle();
}
if (line.hasOption(GravitinoOptions.DISABLE)) {
- newMetalakeDisable(url, ignore, metalake).handle();
+ newMetalakeDisable(url, ignore, metalake).validate().handle();
}
if (line.hasOption(GravitinoOptions.COMMENT)) {
comment = line.getOptionValue(GravitinoOptions.COMMENT);
- newUpdateMetalakeComment(url, ignore, metalake, comment).handle();
+ newUpdateMetalakeComment(url, ignore, metalake,
comment).validate().handle();
}
if (line.hasOption(GravitinoOptions.RENAME)) {
String newName = line.getOptionValue(GravitinoOptions.RENAME);
force = line.hasOption(GravitinoOptions.FORCE);
- newUpdateMetalakeName(url, ignore, force, metalake,
newName).handle();
+ newUpdateMetalakeName(url, ignore, force, metalake,
newName).validate().handle();
}
+
break;
default:
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/Command.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/Command.java
index f91dae4042..cb11d7dfce 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/Command.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/Command.java
@@ -21,6 +21,7 @@ package org.apache.gravitino.cli.commands;
import static org.apache.gravitino.client.GravitinoClientBase.Builder;
+import com.google.common.base.Joiner;
import java.io.File;
import org.apache.gravitino.cli.GravitinoConfig;
import org.apache.gravitino.cli.KerberosData;
@@ -39,6 +40,7 @@ import
org.apache.gravitino.exceptions.NoSuchMetalakeException;
public abstract class Command {
public static final String OUTPUT_FORMAT_TABLE = "table";
public static final String OUTPUT_FORMAT_PLAIN = "plain";
+ public static final Joiner COMMA_JOINER = Joiner.on(", ").skipNulls();
protected static String authentication = null;
protected static String userName = null;
@@ -46,7 +48,6 @@ public abstract class Command {
private static final String SIMPLE_AUTH = "simple";
private static final String OAUTH_AUTH = "oauth";
private static final String KERBEROS_AUTH = "kerberos";
-
private final String url;
private final boolean ignoreVersions;
private final String outputFormat;
@@ -99,6 +100,16 @@ public abstract class Command {
/** All commands have a handle method to handle and run the required
command. */
public abstract void handle();
+
+ /**
+ * verify the arguments. All commands have a verify method to verify the
arguments.
+ *
+ * @return Returns itself via argument validation, otherwise exits.
+ */
+ public Command validate() {
+ return this;
+ }
+
/**
* Builds a {@link GravitinoClient} instance with the provided server URL
and metalake.
*
@@ -192,4 +203,8 @@ public abstract class Command {
throw new IllegalArgumentException("Unsupported output format");
}
}
+
+ protected String getMissingEntitiesInfo(String... entities) {
+ return "Missing required argument(s): " + COMMA_JOINER.join(entities);
+ }
}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RemoveMetalakeProperty.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RemoveMetalakeProperty.java
index 9642456f37..0664ddaad1 100644
---
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RemoveMetalakeProperty.java
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RemoveMetalakeProperty.java
@@ -60,4 +60,10 @@ public class RemoveMetalakeProperty extends Command {
System.out.println(property + " property removed.");
}
+
+ @Override
+ public Command validate() {
+ if (property == null) exitWithError(ErrorMessages.MISSING_PROPERTY);
+ return this;
+ }
}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/SetMetalakeProperty.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/SetMetalakeProperty.java
index 817beaec91..71e5b55898 100644
---
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/SetMetalakeProperty.java
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/SetMetalakeProperty.java
@@ -63,4 +63,12 @@ public class SetMetalakeProperty extends Command {
System.out.println(metalake + " property set.");
}
+
+ @Override
+ public Command validate() {
+ if (property == null && value == null) exitWithError("Missing --property
and --value options.");
+ if (property == null) exitWithError(ErrorMessages.MISSING_PROPERTY);
+ if (value == null) exitWithError(ErrorMessages.MISSING_VALUE);
+ return this;
+ }
}
diff --git
a/clients/cli/src/test/java/org/apache/gravitino/cli/TestFulllName.java
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestFulllName.java
index 48ee79cfcc..f13d6e0920 100644
--- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestFulllName.java
+++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestFulllName.java
@@ -47,6 +47,7 @@ public class TestFulllName {
@BeforeEach
public void setUp() {
+ Main.useExit = false;
options = new GravitinoOptions().options();
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
@@ -82,8 +83,7 @@ public class TestFulllName {
CommandLine commandLine = new DefaultParser().parse(options, args);
FullName fullName = new FullName(commandLine);
- String metalakeName = fullName.getMetalakeName();
- assertNull(metalakeName);
+ assertThrows(RuntimeException.class, fullName::getMetalakeName);
}
@Test
@@ -231,8 +231,7 @@ public class TestFulllName {
String[] args = {"table", "list", "-i", "--name", "Hive_catalog.default"};
CommandLine commandLine = new DefaultParser().parse(options, args);
FullName fullName = new FullName(commandLine);
- String metalakeName = fullName.getMetalakeName();
- assertNull(metalakeName);
+ assertThrows(RuntimeException.class, fullName::getMetalakeName);
String errOutput = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
assertEquals(errOutput, ErrorMessages.MISSING_METALAKE);
}
diff --git
a/clients/cli/src/test/java/org/apache/gravitino/cli/TestMetalakeCommands.java
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestMetalakeCommands.java
index 01eebb6dab..7df08b8ada 100644
---
a/clients/cli/src/test/java/org/apache/gravitino/cli/TestMetalakeCommands.java
+++
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestMetalakeCommands.java
@@ -19,6 +19,8 @@
package org.apache.gravitino.cli;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -29,6 +31,7 @@ import static org.mockito.Mockito.when;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.gravitino.cli.commands.CreateMetalake;
@@ -87,6 +90,7 @@ class TestMetalakeCommands {
doReturn(mockList)
.when(commandLine)
.newListMetalakes(GravitinoCommandLine.DEFAULT_URL, false, null);
+ doReturn(mockList).when(mockList).validate();
commandLine.handleCommandLine();
verify(mockList).handle();
}
@@ -104,6 +108,7 @@ class TestMetalakeCommands {
doReturn(mockDetails)
.when(commandLine)
.newMetalakeDetails(GravitinoCommandLine.DEFAULT_URL, false, null,
"metalake_demo");
+ doReturn(mockDetails).when(mockDetails).validate();
commandLine.handleCommandLine();
verify(mockDetails).handle();
}
@@ -121,6 +126,7 @@ class TestMetalakeCommands {
doReturn(mockAudit)
.when(commandLine)
.newMetalakeAudit(GravitinoCommandLine.DEFAULT_URL, false,
"metalake_demo");
+ doReturn(mockAudit).when(mockAudit).validate();
commandLine.handleCommandLine();
verify(mockAudit).handle();
}
@@ -139,6 +145,7 @@ class TestMetalakeCommands {
doReturn(mockCreate)
.when(commandLine)
.newCreateMetalake(GravitinoCommandLine.DEFAULT_URL, false,
"metalake_demo", "comment");
+ doReturn(mockCreate).when(mockCreate).validate();
commandLine.handleCommandLine();
verify(mockCreate).handle();
}
@@ -155,6 +162,7 @@ class TestMetalakeCommands {
doReturn(mockCreate)
.when(commandLine)
.newCreateMetalake(GravitinoCommandLine.DEFAULT_URL, false,
"metalake_demo", null);
+ doReturn(mockCreate).when(mockCreate).validate();
commandLine.handleCommandLine();
verify(mockCreate).handle();
}
@@ -171,6 +179,7 @@ class TestMetalakeCommands {
doReturn(mockDelete)
.when(commandLine)
.newDeleteMetalake(GravitinoCommandLine.DEFAULT_URL, false, false,
"metalake_demo");
+ doReturn(mockDelete).when(mockDelete).validate();
commandLine.handleCommandLine();
verify(mockDelete).handle();
}
@@ -188,6 +197,7 @@ class TestMetalakeCommands {
doReturn(mockDelete)
.when(commandLine)
.newDeleteMetalake(GravitinoCommandLine.DEFAULT_URL, false, true,
"metalake_demo");
+ doReturn(mockDelete).when(mockDelete).validate();
commandLine.handleCommandLine();
verify(mockDelete).handle();
}
@@ -209,10 +219,50 @@ class TestMetalakeCommands {
.when(commandLine)
.newSetMetalakeProperty(
GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo",
"property", "value");
+ doReturn(mockSetProperty).when(mockSetProperty).validate();
commandLine.handleCommandLine();
verify(mockSetProperty).handle();
}
+ @Test
+ void testSetMetalakePropertyCommandWithoutPropertyAndValue() {
+ Main.useExit = false;
+ SetMetalakeProperty metalakeProperty =
+ spy(
+ new SetMetalakeProperty(
+ GravitinoCommandLine.DEFAULT_URL, false, "demo_metalake",
null, null));
+
+ assertThrows(RuntimeException.class, metalakeProperty::validate);
+ String errOutput = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
+ assertEquals("Missing --property and --value options.", errOutput);
+ }
+
+ @Test
+ void testSetMetalakePropertyCommandWithoutProperty() {
+ Main.useExit = false;
+ SetMetalakeProperty metalakeProperty =
+ spy(
+ new SetMetalakeProperty(
+ GravitinoCommandLine.DEFAULT_URL, false, "demo_metalake",
null, "val1"));
+
+ assertThrows(RuntimeException.class, metalakeProperty::validate);
+ String errOutput = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
+ assertEquals(ErrorMessages.MISSING_PROPERTY, errOutput);
+ }
+
+ @Test
+ void testSetMetalakePropertyCommandWithoutValue() {
+ Main.useExit = false;
+ SetMetalakeProperty metalakeProperty =
+ spy(
+ new SetMetalakeProperty(
+ GravitinoCommandLine.DEFAULT_URL, false, "demo_metalake",
"property1", null));
+
+ assertThrows(RuntimeException.class, metalakeProperty::validate);
+ String errOutput = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
+ assertEquals(ErrorMessages.MISSING_VALUE, errOutput);
+ }
+
@Test
void testRemoveMetalakePropertyCommand() {
RemoveMetalakeProperty mockRemoveProperty =
mock(RemoveMetalakeProperty.class);
@@ -228,10 +278,24 @@ class TestMetalakeCommands {
.when(commandLine)
.newRemoveMetalakeProperty(
GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo",
"property");
+ doReturn(mockRemoveProperty).when(mockRemoveProperty).validate();
commandLine.handleCommandLine();
verify(mockRemoveProperty).handle();
}
+ @Test
+ void testRemoveMetalakePropertyCommandWithoutProperty() {
+ Main.useExit = false;
+ RemoveMetalakeProperty mockRemoveProperty =
+ spy(
+ new RemoveMetalakeProperty(
+ GravitinoCommandLine.DEFAULT_URL, false, "demo_metalake",
null));
+
+ assertThrows(RuntimeException.class, mockRemoveProperty::validate);
+ String errOutput = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
+ assertEquals(ErrorMessages.MISSING_PROPERTY, errOutput);
+ }
+
@Test
void testListMetalakePropertiesCommand() {
ListMetalakeProperties mockListProperties =
mock(ListMetalakeProperties.class);
@@ -244,6 +308,7 @@ class TestMetalakeCommands {
doReturn(mockListProperties)
.when(commandLine)
.newListMetalakeProperties(GravitinoCommandLine.DEFAULT_URL, false,
"metalake_demo");
+ doReturn(mockListProperties).when(mockListProperties).validate();
commandLine.handleCommandLine();
verify(mockListProperties).handle();
}
@@ -263,6 +328,7 @@ class TestMetalakeCommands {
.when(commandLine)
.newUpdateMetalakeComment(
GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", "new
comment");
+ doReturn(mockUpdateComment).when(mockUpdateComment).validate();
commandLine.handleCommandLine();
verify(mockUpdateComment).handle();
}
@@ -282,6 +348,7 @@ class TestMetalakeCommands {
.when(commandLine)
.newUpdateMetalakeName(
GravitinoCommandLine.DEFAULT_URL, false, false, "metalake_demo",
"new_name");
+ doReturn(mockUpdateName).when(mockUpdateName).validate();
commandLine.handleCommandLine();
verify(mockUpdateName).handle();
}
@@ -302,6 +369,7 @@ class TestMetalakeCommands {
.when(commandLine)
.newUpdateMetalakeName(
GravitinoCommandLine.DEFAULT_URL, false, true, "metalake_demo",
"new_name");
+ doReturn(mockUpdateName).when(mockUpdateName).validate();
commandLine.handleCommandLine();
verify(mockUpdateName).handle();
}
@@ -319,6 +387,7 @@ class TestMetalakeCommands {
doReturn(mockEnable)
.when(commandLine)
.newMetalakeEnable(GravitinoCommandLine.DEFAULT_URL, false,
"metalake_demo", false);
+ doReturn(mockEnable).when(mockEnable).validate();
commandLine.handleCommandLine();
verify(mockEnable).handle();
}
@@ -337,6 +406,7 @@ class TestMetalakeCommands {
doReturn(mockEnable)
.when(commandLine)
.newMetalakeEnable(GravitinoCommandLine.DEFAULT_URL, false,
"metalake_demo", true);
+ doReturn(mockEnable).when(mockEnable).validate();
commandLine.handleCommandLine();
verify(mockEnable).handle();
}
@@ -355,7 +425,7 @@ class TestMetalakeCommands {
doReturn(mockDisable)
.when(commandLine)
.newMetalakeDisable(GravitinoCommandLine.DEFAULT_URL, false,
"metalake_demo");
-
+ doReturn(mockDisable).when(mockDisable).validate();
commandLine.handleCommandLine();
verify(mockDisable).handle();
}