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 db8a14abe [#6177] improve(CLI): Refactor ownership commands in Gravitino CLI (#6188) db8a14abe is described below commit db8a14abef75fdc73d303b7bd417e6e69a355cba Author: Lord of Abyss <103809695+abyss-l...@users.noreply.github.com> AuthorDate: Mon Jan 13 05:52:30 2025 +0800 [#6177] improve(CLI): Refactor ownership commands in Gravitino CLI (#6188) ### What changes were proposed in this pull request? Refactor ownership commands in Gravitino CLI. ### Why are the changes needed? Fix: #6177 ### Does this PR introduce _any_ user-facing change? No ### How was this patch tested? local test. --- .../apache/gravitino/cli/GravitinoCommandLine.java | 41 +------ .../apache/gravitino/cli/OwnerCommandHandler.java | 128 +++++++++++++++++++++ .../apache/gravitino/cli/TestOwnerCommands.java | 79 +++++++++++++ 3 files changed, 208 insertions(+), 40 deletions(-) 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 675a96d36..9c9ce6810 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 @@ -127,7 +127,7 @@ public class GravitinoCommandLine extends TestableCommandLine { if (CommandActions.HELP.equals(command)) { handleHelpCommand(); } else if (line.hasOption(GravitinoOptions.OWNER)) { - handleOwnerCommand(); + new OwnerCommandHandler(this, line, command, ignore, entity).handle(); } else if (entity.equals(CommandEntities.COLUMN)) { handleColumnCommand(); } else if (entity.equals(CommandEntities.TABLE)) { @@ -554,45 +554,6 @@ public class GravitinoCommandLine extends TestableCommandLine { } } - /** - * Handles the command execution for Objects based on command type and the command line options. - */ - private void handleOwnerCommand() { - String url = getUrl(); - String auth = getAuth(); - String userName = line.getOptionValue(GravitinoOptions.LOGIN); - FullName name = new FullName(line); - String metalake = name.getMetalakeName(); - String entityName = line.getOptionValue(GravitinoOptions.NAME); - - Command.setAuthenticationMode(auth, userName); - - switch (command) { - case CommandActions.DETAILS: - newOwnerDetails(url, ignore, metalake, entityName, entity).handle(); - break; - - case CommandActions.SET: - { - String owner = line.getOptionValue(GravitinoOptions.USER); - String group = line.getOptionValue(GravitinoOptions.GROUP); - - if (owner != null && group == null) { - newSetOwner(url, ignore, metalake, entityName, entity, owner, false).handle(); - } else if (owner == null && group != null) { - newSetOwner(url, ignore, metalake, entityName, entity, group, true).handle(); - } else { - System.err.println(ErrorMessages.INVALID_SET_COMMAND); - } - break; - } - - default: - System.err.println(ErrorMessages.UNSUPPORTED_ACTION); - break; - } - } - /** * Handles the command execution for filesets based on command type and the command line options. */ diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/OwnerCommandHandler.java b/clients/cli/src/main/java/org/apache/gravitino/cli/OwnerCommandHandler.java new file mode 100644 index 000000000..7e41fb478 --- /dev/null +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/OwnerCommandHandler.java @@ -0,0 +1,128 @@ +/* + * 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 org.apache.commons.cli.CommandLine; +import org.apache.gravitino.cli.commands.Command; + +/** Handles the command execution for Owner based on command type and the command line options. */ +public class OwnerCommandHandler extends CommandHandler { + private final GravitinoCommandLine gravitinoCommandLine; + private final CommandLine line; + private final String command; + private final boolean ignore; + private final String url; + private final FullName name; + private final String metalake; + private final String entityName; + private final String owner; + private final String group; + private final String entity; + + /** + * Constructs a {@link OwnerCommandHandler} instance. + * + * @param gravitinoCommandLine The Gravitino command line instance. + * @param line The command line arguments. + * @param command The command to execute. + * @param ignore Ignore server version mismatch. + * @param entity The entity to execute the command on. + */ + public OwnerCommandHandler( + GravitinoCommandLine gravitinoCommandLine, + CommandLine line, + String command, + boolean ignore, + String entity) { + this.gravitinoCommandLine = gravitinoCommandLine; + this.line = line; + this.command = command; + this.ignore = ignore; + + this.url = getUrl(line); + this.owner = line.getOptionValue(GravitinoOptions.USER); + this.group = line.getOptionValue(GravitinoOptions.GROUP); + this.name = new FullName(line); + this.metalake = name.getMetalakeName(); + this.entityName = name.getName(); + this.entity = entity; + } + /** Handles the command execution logic based on the provided command. */ + @Override + protected void handle() { + String userName = line.getOptionValue(GravitinoOptions.LOGIN); + Command.setAuthenticationMode(getAuth(line), userName); + + if (entityName == null && !CommandEntities.METALAKE.equals(entity)) { + System.err.println(ErrorMessages.MISSING_NAME); + Main.exit(-1); + } + if (!executeCommand()) { + System.err.println(ErrorMessages.UNSUPPORTED_COMMAND); + Main.exit(-1); + } + } + + /** + * Executes the specific command based on the command type. + * + * @return true if the command is supported, false otherwise + */ + private boolean executeCommand() { + switch (command) { + case CommandActions.DETAILS: + handleDetailsCommand(); + return true; + + case CommandActions.SET: + handleSetCommand(); + return true; + + default: + return false; + } + } + + /** Handles the "DETAILS" command. */ + private void handleDetailsCommand() { + gravitinoCommandLine + .newOwnerDetails(url, ignore, metalake, entityName, entity) + .validate() + .handle(); + } + + /** Handles the "SET" command. */ + private void handleSetCommand() { + if (owner != null && group == null) { + gravitinoCommandLine + .newSetOwner(url, ignore, metalake, entityName, entity, owner, false) + .validate() + .handle(); + } else if (owner == null && group != null) { + gravitinoCommandLine + .newSetOwner(url, ignore, metalake, entityName, entity, group, true) + .validate() + .handle(); + } else { + System.err.println(ErrorMessages.INVALID_SET_COMMAND); + Main.exit(-1); + } + } +} diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/TestOwnerCommands.java b/clients/cli/src/test/java/org/apache/gravitino/cli/TestOwnerCommands.java index 0c2b2cf91..12f617380 100644 --- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestOwnerCommands.java +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestOwnerCommands.java @@ -19,16 +19,25 @@ 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 org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; import org.apache.gravitino.cli.commands.OwnerDetails; import org.apache.gravitino.cli.commands.SetOwner; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -36,10 +45,23 @@ class TestOwnerCommands { 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 @@ -67,6 +89,7 @@ class TestOwnerCommands { "catalog", "admin", false); + doReturn(mockSetOwner).when(mockSetOwner).validate(); commandLine.handleCommandLine(); verify(mockSetOwner).handle(); } @@ -96,6 +119,7 @@ class TestOwnerCommands { "catalog", "ITdept", true); + doReturn(mockSetOwner).when(mockSetOwner).validate(); commandLine.handleCommandLine(); verify(mockSetOwner).handle(); } @@ -116,7 +140,62 @@ class TestOwnerCommands { .when(commandLine) .newOwnerDetails( GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", "postgres", "catalog"); + doReturn(mockOwnerDetails).when(mockOwnerDetails).validate(); commandLine.handleCommandLine(); verify(mockOwnerDetails).handle(); } + + @Test + void testOwnerDetailsCommandWithoutName() { + 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); + when(mockCommandLine.hasOption(GravitinoOptions.OWNER)).thenReturn(true); + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.CATALOG, CommandActions.DETAILS)); + + assertThrows(RuntimeException.class, commandLine::handleCommandLine); + verify(commandLine, never()) + .newOwnerDetails( + eq(GravitinoCommandLine.DEFAULT_URL), + eq(false), + eq("metalake_demo"), + eq(null), + eq(CommandEntities.CATALOG)); + + String errOutput = new String(errContent.toByteArray(), StandardCharsets.UTF_8).trim(); + assertEquals(ErrorMessages.MISSING_NAME, errOutput); + } + + @Test + void testSetOwnerUserCommandWithoutUserAndGroup() { + 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("postgres"); + when(mockCommandLine.hasOption(GravitinoOptions.USER)).thenReturn(false); + when(mockCommandLine.hasOption(GravitinoOptions.GROUP)).thenReturn(false); + when(mockCommandLine.hasOption(GravitinoOptions.OWNER)).thenReturn(true); + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.CATALOG, CommandActions.SET)); + + assertThrows(RuntimeException.class, commandLine::handleCommandLine); + verify(commandLine, never()) + .newSetOwner( + eq(GravitinoCommandLine.DEFAULT_URL), + eq(false), + eq("metalake_demo"), + eq("postgres"), + eq(CommandEntities.CATALOG), + isNull(), + eq(false)); + String errOutput = new String(errContent.toByteArray(), StandardCharsets.UTF_8).trim(); + assertEquals(ErrorMessages.INVALID_SET_COMMAND, errOutput); + } }