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 bfb8568066 [#5960] fix(CLI): Add register and link commands to CLI for
model (#6066)
bfb8568066 is described below
commit bfb85680668b91d68f8190a8247156477f326039
Author: Lord of Abyss <[email protected]>
AuthorDate: Sat Jan 4 06:25:18 2025 +0800
[#5960] fix(CLI): Add register and link commands to CLI for model (#6066)
### What changes were proposed in this pull request?
Add register and link commands to CLI for model
- register a model:`model create`
- link a model:`model update <—uri uri> [--alias aliaA aliaB]`
meantime, add two options
- `—uri` :The URI of the model version artifact.
- `—alias` :The aliases of the model version.
The documentation will be updated after #6047 merge and I will create a
new issue.
### Why are the changes needed?
Fix: #5960
### Does this PR introduce _any_ user-facing change?
NO
### How was this patch tested?
#### register test
```bash
# register a model
gcli model create -m demo_metalake --name Hive_catalog.default.model
# register a model with comment
gcli model create -m demo_metalake --name Hive_catalog.default.model
--comment comment
# register a model with properties
gcli model create -m demo_metalake --name Hive_catalog.default.model
--properties key1=val1 key2=val2
# register a model with properties and comment
gcli model create -m demo_metalake --name Hive_catalog.default.model
--properties key1=val1 klinkey2=val2 --comment comment
```
#### link test
```bash
# link a model
gcli model update -m demo_metalake --name Hive_catalog.default.model --uri
file:///tmp/file
# link a model with alias
gcli model update -m demo_metalake --name Hive_catalog.default.model --uri
file:///tmp/file --alias aliasA aliasB
# link a model with all component
gcli model update -m demo_metalake --name Hive_catalog.default.model --uri
file:///tmp/file --alias aliasA aliasB --comment comment --properties
key1=val1 key2=val2
# link a model without uri
gcli model update -m demo_metalake --name Hive_catalog.default.model
```
---
.../org/apache/gravitino/cli/ErrorMessages.java | 3 +-
.../apache/gravitino/cli/GravitinoCommandLine.java | 34 +++
.../org/apache/gravitino/cli/GravitinoOptions.java | 6 +
.../apache/gravitino/cli/TestableCommandLine.java | 29 +++
.../apache/gravitino/cli/commands/LinkModel.java | 106 ++++++++
.../gravitino/cli/commands/RegisterModel.java | 103 ++++++++
.../apache/gravitino/cli/TestModelCommands.java | 284 +++++++++++++++++++++
7 files changed, 564 insertions(+), 1 deletion(-)
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 084b5c34c8..e90c525963 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
@@ -36,6 +36,7 @@ public class ErrorMessages {
public static final String MISSING_USER = "Missing --user option.";
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 METALAKE_EXISTS = "Metalake already exists.";
public static final String CATALOG_EXISTS = "Catalog already exists.";
public static final String SCHEMA_EXISTS = "Schema already exists.";
@@ -51,13 +52,13 @@ public class ErrorMessages {
public static final String COLUMN_EXISTS = "Column already exists.";
public static final String UNKNOWN_TOPIC = "Unknown topic.";
public static final String TOPIC_EXISTS = "Topic already exists.";
+ public static final String MODEL_EXISTS = "Model already exists.";
public static final String UNKNOWN_FILESET = "Unknown fileset.";
public static final String FILESET_EXISTS = "Fileset already exists.";
public static final String TAG_EMPTY = "Error: Must configure --tag option.";
public static final String UNKNOWN_ROLE = "Unknown role.";
public static final String ROLE_EXISTS = "Role already exists.";
public static final String TABLE_EXISTS = "Table already exists.";
- public static final String MODEL_EXISTS = "Model already exists.";
public static final String INVALID_SET_COMMAND =
"Unsupported combination of options either use --name, --user, --group
or --property and --value.";
public static final String INVALID_REMOVE_COMMAND =
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 c23fb8b7cd..3a9322d010 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
@@ -1192,6 +1192,40 @@ public class GravitinoCommandLine extends
TestableCommandLine {
}
break;
+ case CommandActions.CREATE:
+ String createComment = line.getOptionValue(GravitinoOptions.COMMENT);
+ String[] createProperties =
line.getOptionValues(GravitinoOptions.PROPERTIES);
+ Map<String, String> createPropertyMap = new
Properties().parse(createProperties);
+ newCreateModel(
+ url, ignore, metalake, catalog, schema, model, createComment,
createPropertyMap)
+ .handle();
+ break;
+
+ case CommandActions.UPDATE:
+ String[] alias = line.getOptionValues(GravitinoOptions.ALIAS);
+ String uri = line.getOptionValue(GravitinoOptions.URI);
+ if (uri == null) {
+ System.err.println(ErrorMessages.MISSING_URI);
+ Main.exit(-1);
+ }
+
+ String linkComment = line.getOptionValue(GravitinoOptions.COMMENT);
+ String[] linkProperties =
line.getOptionValues(CommandActions.PROPERTIES);
+ Map<String, String> linkPropertityMap = new
Properties().parse(linkProperties);
+ newLinkModel(
+ url,
+ ignore,
+ metalake,
+ catalog,
+ schema,
+ model,
+ uri,
+ alias,
+ linkComment,
+ linkPropertityMap)
+ .handle();
+ break;
+
default:
System.err.println(ErrorMessages.UNSUPPORTED_ACTION);
break;
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
index 657566036d..aaeb8f0184 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
@@ -62,6 +62,8 @@ public class GravitinoOptions {
public static final String ALL = "all";
public static final String ENABLE = "enable";
public static final String DISABLE = "disable";
+ public static final String ALIAS = "alias";
+ public static final String URI = "uri";
/**
* Builds and returns the CLI options for Gravitino.
@@ -109,6 +111,10 @@ public class GravitinoOptions {
options.addOption(createArgOption(COLUMNFILE, "CSV file describing
columns"));
options.addOption(createSimpleOption(null, ALL, "all operation for
--enable"));
+ // model options
+ options.addOption(createArgOption(null, URI, "model version artifact"));
+ options.addOption(createArgsOption(null, ALIAS, "model aliases"));
+
// Options that support multiple values
options.addOption(createArgsOption("p", PROPERTIES, "property name/value
pairs"));
options.addOption(createArgsOption("t", TAG, "tag name"));
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 6a46874917..8df9498d97 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
@@ -55,6 +55,7 @@ import org.apache.gravitino.cli.commands.FilesetDetails;
import org.apache.gravitino.cli.commands.GrantPrivilegesToRole;
import org.apache.gravitino.cli.commands.GroupAudit;
import org.apache.gravitino.cli.commands.GroupDetails;
+import org.apache.gravitino.cli.commands.LinkModel;
import org.apache.gravitino.cli.commands.ListAllTags;
import org.apache.gravitino.cli.commands.ListCatalogProperties;
import org.apache.gravitino.cli.commands.ListCatalogs;
@@ -83,6 +84,7 @@ import org.apache.gravitino.cli.commands.MetalakeEnable;
import org.apache.gravitino.cli.commands.ModelAudit;
import org.apache.gravitino.cli.commands.ModelDetails;
import org.apache.gravitino.cli.commands.OwnerDetails;
+import org.apache.gravitino.cli.commands.RegisterModel;
import org.apache.gravitino.cli.commands.RemoveAllTags;
import org.apache.gravitino.cli.commands.RemoveCatalogProperty;
import org.apache.gravitino.cli.commands.RemoveFilesetProperty;
@@ -925,4 +927,31 @@ public class TestableCommandLine {
String url, boolean ignore, String metalake, String catalog, String
schema, String model) {
return new ModelDetails(url, ignore, metalake, catalog, schema, model);
}
+
+ protected RegisterModel newCreateModel(
+ String url,
+ boolean ignore,
+ String metalake,
+ String catalog,
+ String schema,
+ String model,
+ String comment,
+ Map<String, String> properties) {
+ return new RegisterModel(url, ignore, metalake, catalog, schema, model,
comment, properties);
+ }
+
+ protected LinkModel newLinkModel(
+ String url,
+ boolean ignore,
+ String metalake,
+ String catalog,
+ String schema,
+ String model,
+ String uri,
+ String[] alias,
+ String comment,
+ Map<String, String> properties) {
+ return new LinkModel(
+ url, ignore, metalake, catalog, schema, model, uri, alias, comment,
properties);
+ }
}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/LinkModel.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/LinkModel.java
new file mode 100644
index 0000000000..6e8a4ffb76
--- /dev/null
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/LinkModel.java
@@ -0,0 +1,106 @@
+/*
+ * 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;
+
+/** Link a new model version to the registered model. */
+import java.util.Arrays;
+import java.util.Map;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.cli.ErrorMessages;
+import org.apache.gravitino.client.GravitinoClient;
+import
org.apache.gravitino.exceptions.ModelVersionAliasesAlreadyExistException;
+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.ModelCatalog;
+
+public class LinkModel extends Command {
+ protected final String metalake;
+ protected final String catalog;
+ protected final String schema;
+ protected final String model;
+ protected final String uri;
+ protected final String[] alias;
+ protected final String comment;
+ protected final Map<String, String> properties;
+
+ /**
+ * Link a new model version to the registered 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.
+ * @param uri The URI of the model version artifact.
+ * @param alias The aliases of the model version.
+ * @param comment The comment of the model version.
+ * @param properties The properties of the model version.
+ */
+ public LinkModel(
+ String url,
+ boolean ignoreVersions,
+ String metalake,
+ String catalog,
+ String schema,
+ String model,
+ String uri,
+ String[] alias,
+ String comment,
+ Map<String, String> properties) {
+ super(url, ignoreVersions);
+ this.metalake = metalake;
+ this.catalog = catalog;
+ this.schema = schema;
+ this.model = model;
+ this.uri = uri;
+ this.alias = alias;
+ this.comment = comment;
+ this.properties = properties;
+ }
+
+ /** Link a new model version to the registered model. */
+ @Override
+ public void handle() {
+ NameIdentifier name = NameIdentifier.of(schema, model);
+
+ try {
+ GravitinoClient client = buildClient(metalake);
+ ModelCatalog modelCatalog = client.loadCatalog(catalog).asModelCatalog();
+ modelCatalog.linkModelVersion(name, uri, alias, comment, properties);
+ } catch (NoSuchMetalakeException err) {
+ exitWithError(ErrorMessages.UNKNOWN_METALAKE);
+ } catch (NoSuchCatalogException err) {
+ exitWithError(ErrorMessages.UNKNOWN_CATALOG);
+ } catch (NoSuchSchemaException err) {
+ exitWithError(ErrorMessages.UNKNOWN_SCHEMA);
+ } catch (NoSuchModelException err) {
+ exitWithError(ErrorMessages.UNKNOWN_MODEL);
+ } catch (ModelVersionAliasesAlreadyExistException err) {
+ exitWithError(Arrays.toString(alias) + " already exist.");
+ } catch (Exception err) {
+ exitWithError(err.getMessage());
+ }
+
+ System.out.println(
+ "Linked model " + model + " to " + uri + " with aliases " +
Arrays.toString(alias));
+ }
+}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RegisterModel.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RegisterModel.java
new file mode 100644
index 0000000000..d50dbed50e
--- /dev/null
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RegisterModel.java
@@ -0,0 +1,103 @@
+/*
+ * 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.Map;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.cli.ErrorMessages;
+import org.apache.gravitino.cli.Main;
+import org.apache.gravitino.client.GravitinoClient;
+import org.apache.gravitino.exceptions.ModelAlreadyExistsException;
+import org.apache.gravitino.exceptions.NoSuchCatalogException;
+import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchSchemaException;
+import org.apache.gravitino.model.Model;
+import org.apache.gravitino.model.ModelCatalog;
+
+/** Register a model in the catalog */
+public class RegisterModel extends Command {
+
+ protected final String metalake;
+ protected final String catalog;
+ protected final String schema;
+ protected final String model;
+ protected final String comment;
+ protected final Map<String, String> properties;
+
+ /**
+ * Register a model in the catalog
+ *
+ * @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.
+ * @param comment The comment of the model version.
+ * @param properties The properties of the model version.
+ */
+ public RegisterModel(
+ String url,
+ boolean ignoreVersions,
+ String metalake,
+ String catalog,
+ String schema,
+ String model,
+ String comment,
+ Map<String, String> properties) {
+ super(url, ignoreVersions);
+ this.metalake = metalake;
+ this.catalog = catalog;
+ this.schema = schema;
+ this.model = model;
+ this.comment = comment;
+ this.properties = properties;
+ }
+
+ /** Register a model in the catalog */
+ @Override
+ public void handle() {
+ NameIdentifier name = NameIdentifier.of(schema, model);
+ Model registeredModel = null;
+
+ try {
+ GravitinoClient client = buildClient(metalake);
+ ModelCatalog modelCatalog = client.loadCatalog(catalog).asModelCatalog();
+ registeredModel = modelCatalog.registerModel(name, comment, properties);
+ } catch (NoSuchMetalakeException err) {
+ exitWithError(ErrorMessages.UNKNOWN_METALAKE);
+ } catch (NoSuchCatalogException err) {
+ exitWithError(ErrorMessages.UNKNOWN_CATALOG);
+ } catch (NoSuchSchemaException err) {
+ exitWithError(ErrorMessages.UNKNOWN_SCHEMA);
+ } catch (ModelAlreadyExistsException err) {
+ exitWithError(ErrorMessages.MODEL_EXISTS);
+ } catch (Exception err) {
+ exitWithError(err.getMessage());
+ }
+
+ if (registeredModel != null) {
+ System.out.println("Successful register " + registeredModel.name() +
".");
+ } else {
+ System.err.println("Failed to register model: " + model + ".");
+ Main.exit(-1);
+ }
+ }
+}
diff --git
a/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommands.java
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommands.java
index e486c41a9d..391201f292 100644
--- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommands.java
+++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommands.java
@@ -21,6 +21,7 @@ package org.apache.gravitino.cli;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doReturn;
@@ -35,11 +36,14 @@ import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Map;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
+import org.apache.gravitino.cli.commands.LinkModel;
import org.apache.gravitino.cli.commands.ListModel;
import org.apache.gravitino.cli.commands.ModelAudit;
import org.apache.gravitino.cli.commands.ModelDetails;
+import org.apache.gravitino.cli.commands.RegisterModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -289,4 +293,284 @@ public class TestModelCommands {
commandLine.handleCommandLine();
verify(mockAudit).handle();
}
+
+ @Test
+ void testRegisterModelCommand() {
+ RegisterModel mockCreate = mock(RegisterModel.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");
+
when(mockCommandLine.hasOption(GravitinoOptions.PROPERTIES)).thenReturn(false);
+
when(mockCommandLine.hasOption(GravitinoOptions.COMMENT)).thenReturn(false);
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.CREATE));
+
+ doReturn(mockCreate)
+ .when(commandLine)
+ .newCreateModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"),
+ isNull(),
+ argThat(Map::isEmpty));
+ commandLine.handleCommandLine();
+ verify(mockCreate).handle();
+ }
+
+ @Test
+ void testRegisterModelCommandWithComment() {
+ RegisterModel mockCreate = mock(RegisterModel.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");
+
when(mockCommandLine.hasOption(GravitinoOptions.PROPERTIES)).thenReturn(false);
+ when(mockCommandLine.hasOption(GravitinoOptions.COMMENT)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.COMMENT)).thenReturn("comment");
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.CREATE));
+
+ doReturn(mockCreate)
+ .when(commandLine)
+ .newCreateModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"),
+ eq("comment"),
+ argThat(Map::isEmpty));
+ commandLine.handleCommandLine();
+ verify(mockCreate).handle();
+ }
+
+ @Test
+ void testRegisterModelCommandWithProperties() {
+ RegisterModel mockCreate = mock(RegisterModel.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");
+
when(mockCommandLine.hasOption(GravitinoOptions.PROPERTIES)).thenReturn(true);
+ when(mockCommandLine.getOptionValues(GravitinoOptions.PROPERTIES))
+ .thenReturn(new String[] {"key1=val1", "key2" + "=val2"});
+
when(mockCommandLine.hasOption(GravitinoOptions.COMMENT)).thenReturn(false);
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.CREATE));
+
+ doReturn(mockCreate)
+ .when(commandLine)
+ .newCreateModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"),
+ isNull(),
+ argThat(
+ argument ->
+ argument.size() == 2
+ && argument.containsKey("key1")
+ && argument.get("key1").equals("val1")));
+ commandLine.handleCommandLine();
+ verify(mockCreate).handle();
+ }
+
+ @Test
+ void testRegisterModelCommandWithCommentAndProperties() {
+ RegisterModel mockCreate = mock(RegisterModel.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");
+
when(mockCommandLine.hasOption(GravitinoOptions.PROPERTIES)).thenReturn(true);
+ when(mockCommandLine.getOptionValues(GravitinoOptions.PROPERTIES))
+ .thenReturn(new String[] {"key1=val1", "key2" + "=val2"});
+ when(mockCommandLine.hasOption(GravitinoOptions.COMMENT)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.COMMENT)).thenReturn("comment");
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.CREATE));
+
+ doReturn(mockCreate)
+ .when(commandLine)
+ .newCreateModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"),
+ eq("comment"),
+ argThat(
+ argument ->
+ argument.size() == 2
+ && argument.containsKey("key1")
+ && argument.get("key1").equals("val1")));
+ commandLine.handleCommandLine();
+ verify(mockCreate).handle();
+ }
+
+ @Test
+ void testLinkModelCommandWithoutAlias() {
+ LinkModel linkModelMock = mock(LinkModel.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");
+ when(mockCommandLine.hasOption(GravitinoOptions.URI)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.URI)).thenReturn("file:///tmp/file");
+ when(mockCommandLine.hasOption(GravitinoOptions.ALIAS)).thenReturn(false);
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.UPDATE));
+
+ doReturn(linkModelMock)
+ .when(commandLine)
+ .newLinkModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"),
+ eq("file:///tmp/file"),
+ isNull(),
+ isNull(),
+ argThat(Map::isEmpty));
+ commandLine.handleCommandLine();
+ verify(linkModelMock).handle();
+ }
+
+ @Test
+ void testLinkModelCommandWithAlias() {
+ LinkModel linkModelMock = mock(LinkModel.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");
+ when(mockCommandLine.hasOption(GravitinoOptions.URI)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.URI)).thenReturn("file:///tmp/file");
+ when(mockCommandLine.hasOption(GravitinoOptions.ALIAS)).thenReturn(true);
+ when(mockCommandLine.getOptionValues(GravitinoOptions.ALIAS))
+ .thenReturn(new String[] {"aliasA", "aliasB"});
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.UPDATE));
+
+ doReturn(linkModelMock)
+ .when(commandLine)
+ .newLinkModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"),
+ eq("file:///tmp/file"),
+ argThat(
+ argument ->
+ argument.length == 2
+ && "aliasA".equals(argument[0])
+ && "aliasB".equals(argument[1])),
+ isNull(),
+ argThat(Map::isEmpty));
+ commandLine.handleCommandLine();
+ verify(linkModelMock).handle();
+ }
+
+ @Test
+ void testLinkModelCommandWithoutURI() {
+ 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.model");
+ when(mockCommandLine.hasOption(GravitinoOptions.URI)).thenReturn(false);
+ when(mockCommandLine.hasOption(GravitinoOptions.ALIAS)).thenReturn(false);
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.UPDATE));
+
+ assertThrows(RuntimeException.class, commandLine::handleCommandLine);
+ verify(commandLine, never())
+ .newLinkModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"),
+ isNull(),
+ isNull(),
+ isNull(),
+ argThat(Map::isEmpty));
+ String output = new String(errContent.toByteArray(),
StandardCharsets.UTF_8).trim();
+ assertEquals(ErrorMessages.MISSING_URI, output);
+ }
+
+ @Test
+ void testLinkModelCommandWithAllComponent() {
+ LinkModel linkModelMock = mock(LinkModel.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");
+ when(mockCommandLine.hasOption(GravitinoOptions.URI)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.URI)).thenReturn("file:///tmp/file");
+ when(mockCommandLine.hasOption(GravitinoOptions.ALIAS)).thenReturn(true);
+ when(mockCommandLine.getOptionValues(GravitinoOptions.ALIAS))
+ .thenReturn(new String[] {"aliasA", "aliasB"});
+ when(mockCommandLine.hasOption(GravitinoOptions.COMMENT)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.COMMENT)).thenReturn("comment");
+
when(mockCommandLine.hasOption(GravitinoOptions.PROPERTIES)).thenReturn(true);
+ when(mockCommandLine.getOptionValues(GravitinoOptions.PROPERTIES))
+ .thenReturn(new String[] {"key1=val1", "key2" + "=val2"});
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.UPDATE));
+
+ doReturn(linkModelMock)
+ .when(commandLine)
+ .newLinkModel(
+ eq(GravitinoCommandLine.DEFAULT_URL),
+ eq(false),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"),
+ eq("file:///tmp/file"),
+ argThat(
+ argument ->
+ argument.length == 2
+ && "aliasA".equals(argument[0])
+ && "aliasB".equals(argument[1])),
+ eq("comment"),
+ argThat(
+ argument ->
+ argument.size() == 2
+ && argument.containsKey("key1")
+ && argument.containsKey("key2")
+ && "val1".equals(argument.get("key1"))
+ && "val2".equals(argument.get("key2"))));
+ commandLine.handleCommandLine();
+ verify(linkModelMock).handle();
+ }
}