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 539ac3634 [#5961] feat(CLI): Add details and list command to CLI for
model. (#6053)
539ac3634 is described below
commit 539ac3634bd142d63e8878408dd858ca7ccb5216
Author: Lord of Abyss <[email protected]>
AuthorDate: Thu Jan 2 07:02:10 2025 +0800
[#5961] feat(CLI): Add details and list command to CLI for model. (#6053)
### What changes were proposed in this pull request?
add get and list command to model.
- get: `gcli model get -m demo_metalake --name catalog.schema`, Displays
the name of the Model along with all versions.
- list:`gcli model list -m demo_metalake --name catalog.schema`, Display
all models in this schema.
### Why are the changes needed?
Fix: #5961
### Does this PR introduce _any_ user-facing change?
NO
### How was this patch tested?
ut
---
.../org/apache/gravitino/cli/CommandEntities.java | 2 +
.../org/apache/gravitino/cli/ErrorMessages.java | 1 +
.../java/org/apache/gravitino/cli/FullName.java | 9 +
.../apache/gravitino/cli/GravitinoCommandLine.java | 39 +++
.../apache/gravitino/cli/TestableCommandLine.java | 12 +
.../apache/gravitino/cli/commands/ListModel.java | 80 ++++++
.../gravitino/cli/commands/ModelDetails.java | 92 +++++++
.../org/apache/gravitino/cli/TestModelCommand.java | 270 +++++++++++++++++++++
8 files changed, 505 insertions(+)
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/CommandEntities.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/CommandEntities.java
index dc0332029..2dd50974e 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/CommandEntities.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/CommandEntities.java
@@ -37,6 +37,7 @@ public class CommandEntities {
public static final String TOPIC = "topic";
public static final String FILESET = "fileset";
public static final String ROLE = "role";
+ public static final String MODEL = "model";
private static final HashSet<String> VALID_ENTITIES = new HashSet<>();
@@ -52,6 +53,7 @@ public class CommandEntities {
VALID_ENTITIES.add(TOPIC);
VALID_ENTITIES.add(FILESET);
VALID_ENTITIES.add(ROLE);
+ VALID_ENTITIES.add(MODEL);
}
/**
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 757e7c2cb..4bd523ec2 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
@@ -28,6 +28,7 @@ public class ErrorMessages {
public static final String UNKNOWN_CATALOG = "Unknown catalog name.";
public static final String UNKNOWN_SCHEMA = "Unknown schema name.";
public static final String UNKNOWN_TABLE = "Unknown table name.";
+ public static final String UNKNOWN_MODEL = "Unknown model name.";
public static final String MALFORMED_NAME = "Malformed entity name.";
public static final String MISSING_NAME = "Missing --name option.";
public static final String MISSING_METALAKE = "Missing --metalake option.";
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 8af7322dc..c21d21af4 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
@@ -96,6 +96,15 @@ public class FullName {
return getNamePart(1);
}
+ /**
+ * Retrieves the model name from the second part of the full name option.
+ *
+ * @return The model name, or null if not found
+ */
+ public String getModelName() {
+ return getNamePart(2);
+ }
+
/**
* Retrieves the table name from the third part of the full name option.
*
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 7869dd97b..8cd335beb 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
@@ -152,6 +152,8 @@ public class GravitinoCommandLine extends
TestableCommandLine {
handleTagCommand();
} else if (entity.equals(CommandEntities.ROLE)) {
handleRoleCommand();
+ } else if (entity.equals(CommandEntities.MODEL)) {
+ handleModelCommand();
}
}
@@ -1150,6 +1152,43 @@ public class GravitinoCommandLine extends
TestableCommandLine {
}
}
+ private void handleModelCommand() {
+ String url = getUrl();
+ String auth = getAuth();
+ String userName = line.getOptionValue(GravitinoOptions.LOGIN);
+ FullName name = new FullName(line);
+ String metalake = name.getMetalakeName();
+ String catalog = name.getCatalogName();
+ String schema = name.getSchemaName();
+
+ Command.setAuthenticationMode(auth, userName);
+
+ List<String> missingEntities = Lists.newArrayList();
+ if (catalog == null) missingEntities.add(CommandEntities.CATALOG);
+ if (schema == null) missingEntities.add(CommandEntities.SCHEMA);
+
+ // Handle CommandActions.LIST action separately as it doesn't require the
`model`
+ if (CommandActions.LIST.equals(command)) {
+ checkEntities(missingEntities);
+ newListModel(url, ignore, metalake, catalog, schema).handle();
+ return;
+ }
+
+ String model = name.getModelName();
+ if (model == null) missingEntities.add(CommandEntities.MODEL);
+ checkEntities(missingEntities);
+
+ switch (command) {
+ case CommandActions.DETAILS:
+ newModelDetails(url, ignore, metalake, catalog, schema,
model).handle();
+ break;
+
+ default:
+ System.err.println(ErrorMessages.UNSUPPORTED_ACTION);
+ break;
+ }
+ }
+
/**
* Retrieves the Gravitinno URL from the command line options or the
GRAVITINO_URL environment
* variable or the Gravitio config file.
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
index f07244c00..3cfd84ad8 100644
---
a/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
@@ -66,6 +66,7 @@ import org.apache.gravitino.cli.commands.ListGroups;
import org.apache.gravitino.cli.commands.ListIndexes;
import org.apache.gravitino.cli.commands.ListMetalakeProperties;
import org.apache.gravitino.cli.commands.ListMetalakes;
+import org.apache.gravitino.cli.commands.ListModel;
import org.apache.gravitino.cli.commands.ListRoles;
import org.apache.gravitino.cli.commands.ListSchema;
import org.apache.gravitino.cli.commands.ListSchemaProperties;
@@ -79,6 +80,7 @@ import org.apache.gravitino.cli.commands.MetalakeAudit;
import org.apache.gravitino.cli.commands.MetalakeDetails;
import org.apache.gravitino.cli.commands.MetalakeDisable;
import org.apache.gravitino.cli.commands.MetalakeEnable;
+import org.apache.gravitino.cli.commands.ModelDetails;
import org.apache.gravitino.cli.commands.OwnerDetails;
import org.apache.gravitino.cli.commands.RemoveAllTags;
import org.apache.gravitino.cli.commands.RemoveCatalogProperty;
@@ -907,4 +909,14 @@ public class TestableCommandLine {
String url, boolean ignore, String metalake, String catalog) {
return new CatalogDisable(url, ignore, metalake, catalog);
}
+
+ protected ListModel newListModel(
+ String url, boolean ignore, String metalake, String catalog, String
schema) {
+ return new ListModel(url, ignore, metalake, catalog, schema);
+ }
+
+ protected ModelDetails newModelDetails(
+ String url, boolean ignore, String metalake, String catalog, String
schema, String model) {
+ return new ModelDetails(url, ignore, metalake, catalog, schema, model);
+ }
}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListModel.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListModel.java
new file mode 100644
index 000000000..1528e954b
--- /dev/null
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListModel.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.apache.gravitino.cli.commands;
+
+import com.google.common.base.Joiner;
+import java.util.Arrays;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.cli.ErrorMessages;
+import org.apache.gravitino.client.GravitinoClient;
+import org.apache.gravitino.exceptions.NoSuchCatalogException;
+import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchSchemaException;
+
+/** List the names of all models in a schema. */
+public class ListModel extends Command {
+ protected final String metalake;
+ protected final String catalog;
+ protected final String schema;
+
+ /**
+ * List the names of all models in a schema.
+ *
+ * @param url The URL of the Gravitino server.
+ * @param ignoreVersions If true don't check the client/server versions
match.
+ * @param metalake The name of the metalake.
+ * @param catalog The name of the catalog.
+ * @param schema The name of schema.
+ */
+ public ListModel(
+ String url, boolean ignoreVersions, String metalake, String catalog,
String schema) {
+ super(url, ignoreVersions);
+ this.metalake = metalake;
+ this.catalog = catalog;
+ this.schema = schema;
+ }
+
+ /** List the names of all models in a schema. */
+ @Override
+ public void handle() {
+ NameIdentifier[] models = new NameIdentifier[0];
+ Namespace name = Namespace.of(schema);
+
+ try {
+ GravitinoClient client = buildClient(metalake);
+ models = client.loadCatalog(catalog).asModelCatalog().listModels(name);
+ } catch (NoSuchMetalakeException noSuchMetalakeException) {
+ exitWithError(ErrorMessages.UNKNOWN_METALAKE);
+ } catch (NoSuchCatalogException noSuchCatalogException) {
+ exitWithError(ErrorMessages.UNKNOWN_CATALOG);
+ } catch (NoSuchSchemaException noSuchSchemaException) {
+ exitWithError(ErrorMessages.UNKNOWN_SCHEMA);
+ } catch (Exception err) {
+ exitWithError(err.getMessage());
+ }
+
+ String output =
+ models.length == 0
+ ? "No models exist."
+ : Joiner.on(",").join(Arrays.stream(models).map(model ->
model.name()).iterator());
+
+ System.out.println(output);
+ }
+}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ModelDetails.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ModelDetails.java
new file mode 100644
index 000000000..6c3aec08f
--- /dev/null
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ModelDetails.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.apache.gravitino.cli.commands;
+
+import java.util.Arrays;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.cli.ErrorMessages;
+import org.apache.gravitino.client.GravitinoClient;
+import org.apache.gravitino.exceptions.NoSuchCatalogException;
+import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchModelException;
+import org.apache.gravitino.exceptions.NoSuchSchemaException;
+import org.apache.gravitino.model.Model;
+import org.apache.gravitino.model.ModelCatalog;
+
+/** Displays the details of a model. */
+public class ModelDetails extends Command {
+ protected final String metalake;
+ protected final String catalog;
+ protected final String schema;
+ protected final String model;
+
+ /**
+ * Displays the details of a model.
+ *
+ * @param url The URL of the Gravitino server.
+ * @param ignoreVersions If true don't check the client/server versions
match.
+ * @param metalake The name of the metalake.
+ * @param catalog The name of the catalog.
+ * @param schema The name of schema.
+ * @param model The name of model.
+ */
+ public ModelDetails(
+ String url,
+ boolean ignoreVersions,
+ String metalake,
+ String catalog,
+ String schema,
+ String model) {
+ super(url, ignoreVersions);
+ this.metalake = metalake;
+ this.catalog = catalog;
+ this.schema = schema;
+ this.model = model;
+ }
+
+ /** Displays the details of a model. */
+ @Override
+ public void handle() {
+ NameIdentifier name = NameIdentifier.of(schema, model);
+ Model gModel = null;
+ int[] versions = new int[0];
+
+ try {
+ GravitinoClient client = buildClient(metalake);
+ ModelCatalog modelCatalog = client.loadCatalog(catalog).asModelCatalog();
+ gModel = modelCatalog.getModel(name);
+ versions = modelCatalog.listModelVersions(name);
+ } catch (NoSuchMetalakeException noSuchMetalakeException) {
+ exitWithError(ErrorMessages.UNKNOWN_METALAKE);
+ } catch (NoSuchCatalogException noSuchCatalogException) {
+ exitWithError(ErrorMessages.UNKNOWN_CATALOG);
+ } catch (NoSuchSchemaException noSuchSchemaException) {
+ exitWithError(ErrorMessages.UNKNOWN_SCHEMA);
+ } catch (NoSuchModelException noSuchModelException) {
+ exitWithError(ErrorMessages.UNKNOWN_MODEL);
+ } catch (Exception err) {
+ exitWithError(err.getMessage());
+ }
+ String basicInfo =
+ String.format("Model name %s, latest version: %s%n", gModel.name(),
gModel.latestVersion());
+ String versionInfo = Arrays.toString(versions);
+ System.out.printf(basicInfo + "versions: " + versionInfo);
+ }
+}
diff --git
a/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommand.java
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommand.java
new file mode 100644
index 000000000..d222655b6
--- /dev/null
+++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommand.java
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.apache.gravitino.cli;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.gravitino.cli.commands.ListModel;
+import org.apache.gravitino.cli.commands.ModelDetails;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.testcontainers.shaded.com.google.common.base.Joiner;
+
+public class TestModelCommand {
+ private final Joiner joiner = Joiner.on(", ").skipNulls();
+ private CommandLine mockCommandLine;
+ private Options mockOptions;
+
+ private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+ private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
+ private final PrintStream originalOut = System.out;
+ private final PrintStream originalErr = System.err;
+
+ @BeforeEach
+ void setUp() {
+ mockCommandLine = mock(CommandLine.class);
+ mockOptions = mock(Options.class);
+ System.setOut(new PrintStream(outContent));
+ System.setErr(new PrintStream(errContent));
+ }
+
+ @AfterEach
+ public void restoreStreams() {
+ System.setOut(originalOut);
+ System.setErr(originalErr);
+ }
+
+ @Test
+ void testListModelCommand() {
+ ListModel mockList = mock(ListModel.class);
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog.schema");
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.LIST));
+
+ doReturn(mockList)
+ .when(commandLine)
+ .newListModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"));
+ commandLine.handleCommandLine();
+ verify(mockList).handle();
+ }
+
+ @Test
+ void testListModelCommandWithoutCatalog() {
+ Main.useExit = false;
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(false);
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.LIST));
+
+ assertThrows(RuntimeException.class, commandLine::handleCommandLine);
+ verify(commandLine, never())
+ .newListModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ isNull(),
+ isNull());
+ String output = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
+ assertEquals(
+ ErrorMessages.MISSING_NAME
+ + "\n"
+ + "Missing required argument(s): "
+ + joiner.join(Arrays.asList(CommandEntities.CATALOG,
CommandEntities.SCHEMA)),
+ output);
+ }
+
+ @Test
+ void testListModelCommandWithoutSchema() {
+ Main.useExit = false;
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog");
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.LIST));
+
+ assertThrows(RuntimeException.class, commandLine::handleCommandLine);
+ verify(commandLine, never())
+ .newListModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ isNull());
+ String output = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
+ assertEquals(
+ ErrorMessages.MALFORMED_NAME
+ + "\n"
+ + "Missing required argument(s): "
+ + joiner.join(Collections.singletonList(CommandEntities.SCHEMA)),
+ output);
+ }
+
+ @Test
+ void testModelDetailsCommand() {
+ ModelDetails mockList = mock(ModelDetails.class);
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog.schema.model");
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.DETAILS));
+
+ doReturn(mockList)
+ .when(commandLine)
+ .newModelDetails(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"));
+ commandLine.handleCommandLine();
+ verify(mockList).handle();
+ }
+
+ @Test
+ void testModelDetailsCommandWithoutCatalog() {
+ Main.useExit = false;
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(false);
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.DETAILS));
+
+ assertThrows(RuntimeException.class, commandLine::handleCommandLine);
+
+ verify(commandLine, never())
+ .newModelDetails(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ isNull(),
+ isNull(),
+ isNull());
+ String output = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
+ assertEquals(
+ ErrorMessages.MISSING_NAME
+ + "\n"
+ + "Missing required argument(s): "
+ + joiner.join(
+ Arrays.asList(
+ CommandEntities.CATALOG, CommandEntities.SCHEMA,
CommandEntities.MODEL)),
+ output);
+ }
+
+ @Test
+ void testModelDetailsCommandWithoutSchema() {
+ Main.useExit = false;
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog");
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.DETAILS));
+
+ assertThrows(RuntimeException.class, commandLine::handleCommandLine);
+
+ verify(commandLine, never())
+ .newModelDetails(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ isNull(),
+ isNull());
+ String output = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
+ assertEquals(
+ ErrorMessages.MALFORMED_NAME
+ + "\n"
+ + "Missing required argument(s): "
+ + joiner.join(Arrays.asList(CommandEntities.SCHEMA,
CommandEntities.MODEL)),
+ output);
+ }
+
+ @Test
+ void testModelDetailsCommandWithoutModel() {
+ Main.useExit = false;
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog.schema");
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.DETAILS));
+
+ assertThrows(RuntimeException.class, commandLine::handleCommandLine);
+
+ verify(commandLine, never())
+ .newModelDetails(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ isNull());
+ String output = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
+ assertEquals(
+ ErrorMessages.MALFORMED_NAME
+ + "\n"
+ + "Missing required argument(s): "
+ + joiner.join(Collections.singletonList(CommandEntities.MODEL)),
+ output);
+ }
+}