This is an automated email from the ASF dual-hosted git repository. jshao 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 626bc7943 [#5506] feat(CLI): Table formatted output (#5714) 626bc7943 is described below commit 626bc7943b56af431215ea3cd4aae9ce5cee6bef Author: Jimmy Lee <55496001+wau...@users.noreply.github.com> AuthorDate: Mon Dec 2 10:52:03 2024 +0800 [#5506] feat(CLI): Table formatted output (#5714) ### What changes were proposed in this pull request? Enhance the Gravitino CLI with formatted output. <img width="323" alt="383987880-78e48033-601e-422f-b5bb-20061536c6b2" src="https://github.com/user-attachments/assets/9655c081-1575-44c3-bcce-49ca2b49a259"> ### Why are the changes needed? Issue: #5506 Cause the original PR (https://github.com/apache/gravitino/pull/5606) cannot be reopened, I create a new PR. The purpose is to make Gravitino CLI output look more readable; currently, it supports only table and plain output formats. ### Does this PR introduce _any_ user-facing change? No. ### How was this patch tested? ```shell gcli metalake list gcli metalake list --output plain gcli metalake list --output table ``` --- clients/cli/build.gradle.kts | 11 +- .../apache/gravitino/cli/GravitinoCommandLine.java | 8 +- .../org/apache/gravitino/cli/GravitinoOptions.java | 3 + .../apache/gravitino/cli/TestableCommandLine.java | 13 +- .../gravitino/cli/commands/CatalogDetails.java | 15 +- .../org/apache/gravitino/cli/commands/Command.java | 30 ++++ .../gravitino/cli/commands/ListMetalakes.java | 21 +-- .../gravitino/cli/commands/MetalakeDetails.java | 14 +- .../apache/gravitino/cli/outputs/OutputFormat.java | 24 +++ .../apache/gravitino/cli/outputs/PlainFormat.java | 71 +++++++++ .../apache/gravitino/cli/outputs/TableFormat.java | 157 +++++++++++++++++++ .../apache/gravitino/cli/TestCatalogCommands.java | 3 +- .../apache/gravitino/cli/TestMetalakeCommands.java | 6 +- .../cli/integration/test/TableFormatOutputIT.java | 166 +++++++++++++++++++++ 14 files changed, 495 insertions(+), 47 deletions(-) diff --git a/clients/cli/build.gradle.kts b/clients/cli/build.gradle.kts index 9ce570ef8..ae45fc968 100644 --- a/clients/cli/build.gradle.kts +++ b/clients/cli/build.gradle.kts @@ -34,7 +34,16 @@ dependencies { testImplementation(libs.junit.jupiter.api) testImplementation(libs.junit.jupiter.params) testImplementation(libs.mockito.core) - + testImplementation(project(":core")) { + exclude("org.apache.logging.log4j") + } + testImplementation(project(":server")) { + exclude("org.apache.logging.log4j") + } + testImplementation(project(":server-common")) { + exclude("org.apache.logging.log4j") + } + testImplementation(project(":integration-test-common", "testArtifacts")) testRuntimeOnly(libs.junit.jupiter.engine) } 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 ca149672a..e7a36d016 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 @@ -153,15 +153,16 @@ public class GravitinoCommandLine extends TestableCommandLine { String url = getUrl(); FullName name = new FullName(line); String metalake = name.getMetalakeName(); + String outputFormat = line.getOptionValue(GravitinoOptions.OUTPUT); if (CommandActions.DETAILS.equals(command)) { if (line.hasOption(GravitinoOptions.AUDIT)) { newMetalakeAudit(url, ignore, metalake).handle(); } else { - newMetalakeDetails(url, ignore, metalake).handle(); + newMetalakeDetails(url, ignore, metalake, outputFormat).handle(); } } else if (CommandActions.LIST.equals(command)) { - newListMetalakes(url, ignore).handle(); + newListMetalakes(url, ignore, outputFormat).handle(); } else if (CommandActions.CREATE.equals(command)) { String comment = line.getOptionValue(GravitinoOptions.COMMENT); newCreateMetalake(url, ignore, metalake, comment).handle(); @@ -197,6 +198,7 @@ public class GravitinoCommandLine extends TestableCommandLine { String url = getUrl(); FullName name = new FullName(line); String metalake = name.getMetalakeName(); + String outputFormat = line.getOptionValue(GravitinoOptions.OUTPUT); if (CommandActions.LIST.equals(command)) { newListCatalogs(url, ignore, metalake).handle(); @@ -209,7 +211,7 @@ public class GravitinoCommandLine extends TestableCommandLine { if (line.hasOption(GravitinoOptions.AUDIT)) { newCatalogAudit(url, ignore, metalake, catalog).handle(); } else { - newCatalogDetails(url, ignore, metalake, catalog).handle(); + newCatalogDetails(url, ignore, metalake, catalog, outputFormat).handle(); } } else if (CommandActions.CREATE.equals(command)) { String comment = line.getOptionValue(GravitinoOptions.COMMENT); 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 863bc5d21..8cf5f0cc1 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 @@ -47,6 +47,7 @@ public class GravitinoOptions { public static final String INDEX = "index"; public static final String DISTRIBUTION = "distribution"; public static final String PARTITION = "partition"; + public static final String OUTPUT = "output"; /** * Builds and returns the CLI options for Gravitino. @@ -90,6 +91,8 @@ public class GravitinoOptions { // Force delete entities and rename metalake operations options.addOption(createSimpleOption("f", FORCE, "force operation")); + options.addOption(createArgOption(null, OUTPUT, "output format (plain/table)")); + return options; } 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 248f57cd6..57de13f0a 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 @@ -129,12 +129,13 @@ public class TestableCommandLine { return new MetalakeAudit(url, ignore, metalake); } - protected MetalakeDetails newMetalakeDetails(String url, boolean ignore, String metalake) { - return new MetalakeDetails(url, ignore, metalake); + protected MetalakeDetails newMetalakeDetails( + String url, boolean ignore, String metalake, String outputFormat) { + return new MetalakeDetails(url, ignore, metalake, outputFormat); } - protected ListMetalakes newListMetalakes(String url, boolean ignore) { - return new ListMetalakes(url, ignore); + protected ListMetalakes newListMetalakes(String url, boolean ignore, String outputFormat) { + return new ListMetalakes(url, ignore, outputFormat); } protected CreateMetalake newCreateMetalake( @@ -178,8 +179,8 @@ public class TestableCommandLine { } protected CatalogDetails newCatalogDetails( - String url, boolean ignore, String metalake, String catalog) { - return new CatalogDetails(url, ignore, metalake, catalog); + String url, boolean ignore, String metalake, String catalog, String outputFormat) { + return new CatalogDetails(url, ignore, metalake, catalog, outputFormat); } protected ListCatalogs newListCatalogs(String url, boolean ignore, String metalake) { diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CatalogDetails.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CatalogDetails.java index 41451daac..bebe536fa 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CatalogDetails.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CatalogDetails.java @@ -37,9 +37,11 @@ public class CatalogDetails extends Command { * @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 outputFormat The output format. */ - public CatalogDetails(String url, boolean ignoreVersions, String metalake, String catalog) { - super(url, ignoreVersions); + public CatalogDetails( + String url, boolean ignoreVersions, String metalake, String catalog, String outputFormat) { + super(url, ignoreVersions, outputFormat); this.metalake = metalake; this.catalog = catalog; } @@ -52,20 +54,13 @@ public class CatalogDetails extends Command { try { GravitinoClient client = buildClient(metalake); result = client.loadCatalog(catalog); + output(result); } catch (NoSuchMetalakeException err) { System.err.println(ErrorMessages.UNKNOWN_METALAKE); - return; } catch (NoSuchCatalogException err) { System.err.println(ErrorMessages.UNKNOWN_CATALOG); - return; } catch (Exception exp) { System.err.println(exp.getMessage()); - return; - } - - if (result != null) { - System.out.println( - result.name() + "," + result.type() + "," + result.provider() + "," + result.comment()); } } } 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 040bd7141..1753e5743 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 @@ -19,6 +19,8 @@ package org.apache.gravitino.cli.commands; +import org.apache.gravitino.cli.outputs.PlainFormat; +import org.apache.gravitino.cli.outputs.TableFormat; import org.apache.gravitino.client.GravitinoAdminClient; import org.apache.gravitino.client.GravitinoClient; import org.apache.gravitino.exceptions.NoSuchMetalakeException; @@ -27,6 +29,9 @@ import org.apache.gravitino.exceptions.NoSuchMetalakeException; public abstract class Command { private final String url; private final boolean ignoreVersions; + private final String outputFormat; + public static String OUTPUT_FORMAT_TABLE = "table"; + public static String OUTPUT_FORMAT_PLAIN = "plain"; /** * Command constructor. @@ -35,8 +40,13 @@ public abstract class Command { * @param ignoreVersions If true don't check the client/server versions match. */ public Command(String url, boolean ignoreVersions) { + this(url, ignoreVersions, null); + } + + public Command(String url, boolean ignoreVersions, String outputFormat) { this.url = url; this.ignoreVersions = ignoreVersions; + this.outputFormat = outputFormat; } /** All commands have a handle method to handle and run the required command. */ @@ -69,4 +79,24 @@ public abstract class Command { return GravitinoAdminClient.builder(url).build(); } } + + /** + * Outputs the entity to the console. + * + * @param entity The entity to output. + */ + protected <T> void output(T entity) { + if (outputFormat == null) { + PlainFormat.output(entity); + return; + } + + if (outputFormat.equals(OUTPUT_FORMAT_TABLE)) { + TableFormat.output(entity); + } else if (outputFormat.equals(OUTPUT_FORMAT_PLAIN)) { + PlainFormat.output(entity); + } else { + throw new IllegalArgumentException("Unsupported output format"); + } + } } diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListMetalakes.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListMetalakes.java index 26668157a..de7571568 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListMetalakes.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListMetalakes.java @@ -19,9 +19,6 @@ package org.apache.gravitino.cli.commands; -import com.google.common.base.Joiner; -import java.util.ArrayList; -import java.util.List; import org.apache.gravitino.Metalake; import org.apache.gravitino.client.GravitinoAdminClient; @@ -33,30 +30,22 @@ public class ListMetalakes extends Command { * * @param url The URL of the Gravitino server. * @param ignoreVersions If true don't check the client/server versions match. + * @param outputFormat The output format. */ - public ListMetalakes(String url, boolean ignoreVersions) { - super(url, ignoreVersions); + public ListMetalakes(String url, boolean ignoreVersions, String outputFormat) { + super(url, ignoreVersions, outputFormat); } /** Lists all metalakes. */ @Override public void handle() { - Metalake[] metalakes = new Metalake[0]; + Metalake[] metalakes; try { GravitinoAdminClient client = buildAdminClient(); metalakes = client.listMetalakes(); + output(metalakes); } catch (Exception exp) { System.err.println(exp.getMessage()); - return; } - - List<String> metalakeNames = new ArrayList<>(); - for (int i = 0; i < metalakes.length; i++) { - metalakeNames.add(metalakes[i].name()); - } - - String all = Joiner.on(System.lineSeparator()).join(metalakeNames); - - System.out.println(all.toString()); } } diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/MetalakeDetails.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/MetalakeDetails.java index c00c90c53..127b9a584 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/MetalakeDetails.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/MetalakeDetails.java @@ -19,6 +19,7 @@ package org.apache.gravitino.cli.commands; +import org.apache.gravitino.Metalake; import org.apache.gravitino.cli.ErrorMessages; import org.apache.gravitino.client.GravitinoClient; import org.apache.gravitino.exceptions.NoSuchMetalakeException; @@ -33,27 +34,24 @@ public class MetalakeDetails extends Command { * @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 outputFormat The output format. */ - public MetalakeDetails(String url, boolean ignoreVersions, String metalake) { - super(url, ignoreVersions); + public MetalakeDetails(String url, boolean ignoreVersions, String metalake, String outputFormat) { + super(url, ignoreVersions, outputFormat); this.metalake = metalake; } /** Displays the name and comment of a metalake. */ @Override public void handle() { - String comment = ""; try { GravitinoClient client = buildClient(metalake); - comment = client.loadMetalake(metalake).comment(); + Metalake metalakeEntity = client.loadMetalake(metalake); + output(metalakeEntity); } catch (NoSuchMetalakeException err) { System.err.println(ErrorMessages.UNKNOWN_METALAKE); - return; } catch (Exception exp) { System.err.println(exp.getMessage()); - return; } - - System.out.println(metalake + "," + comment); } } diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/OutputFormat.java b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/OutputFormat.java new file mode 100644 index 000000000..8e6ab3116 --- /dev/null +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/OutputFormat.java @@ -0,0 +1,24 @@ +/* + * 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.outputs; + +/** Output format interface for the CLI results. */ +public interface OutputFormat<T> { + void output(T object); +} diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java new file mode 100644 index 000000000..4674d3f88 --- /dev/null +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java @@ -0,0 +1,71 @@ +/* + * 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.outputs; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.apache.gravitino.Catalog; +import org.apache.gravitino.Metalake; + +/** Plain format to print a pretty string to standard out. */ +public class PlainFormat { + public static void output(Object object) { + if (object instanceof Metalake) { + new MetalakeStringFormat().output((Metalake) object); + } else if (object instanceof Metalake[]) { + new MetalakesStringFormat().output((Metalake[]) object); + } else if (object instanceof Catalog) { + new CatalogStringFormat().output((Catalog) object); + } else { + throw new IllegalArgumentException("Unsupported object type"); + } + } + + static final class MetalakeStringFormat implements OutputFormat<Metalake> { + @Override + public void output(Metalake metalake) { + System.out.println(metalake.name() + "," + metalake.comment()); + } + } + + static final class MetalakesStringFormat implements OutputFormat<Metalake[]> { + @Override + public void output(Metalake[] metalakes) { + List<String> metalakeNames = + Arrays.stream(metalakes).map(Metalake::name).collect(Collectors.toList()); + String all = String.join(System.lineSeparator(), metalakeNames); + System.out.println(all); + } + } + + static final class CatalogStringFormat implements OutputFormat<Catalog> { + @Override + public void output(Catalog catalog) { + System.out.println( + catalog.name() + + "," + + catalog.type() + + "," + + catalog.provider() + + "," + + catalog.comment()); + } + } +} diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/TableFormat.java b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/TableFormat.java new file mode 100644 index 000000000..a1975b9f3 --- /dev/null +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/TableFormat.java @@ -0,0 +1,157 @@ +/* + * 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.outputs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.apache.gravitino.Catalog; +import org.apache.gravitino.Metalake; + +/** Table format to print a pretty table to standard out. */ +public class TableFormat { + public static void output(Object object) { + if (object instanceof Metalake) { + new MetalakeTableFormat().output((Metalake) object); + } else if (object instanceof Metalake[]) { + new MetalakesTableFormat().output((Metalake[]) object); + } else if (object instanceof Catalog) { + new CatalogTableFormat().output((Catalog) object); + } else { + throw new IllegalArgumentException("Unsupported object type"); + } + } + + static final class MetalakeTableFormat implements OutputFormat<Metalake> { + @Override + public void output(Metalake metalake) { + List<String> headers = Arrays.asList("metalake", "comment"); + List<List<String>> rows = new ArrayList<>(); + rows.add(Arrays.asList(metalake.name(), metalake.comment())); + TableFormatImpl tableFormat = new TableFormatImpl(); + tableFormat.print(headers, rows); + } + } + + static final class MetalakesTableFormat implements OutputFormat<Metalake[]> { + @Override + public void output(Metalake[] metalakes) { + List<String> headers = Collections.singletonList("metalake"); + List<List<String>> rows = new ArrayList<>(); + for (int i = 0; i < metalakes.length; i++) { + rows.add(Arrays.asList(metalakes[i].name())); + } + TableFormatImpl tableFormat = new TableFormatImpl(); + tableFormat.print(headers, rows); + } + } + + static final class CatalogTableFormat implements OutputFormat<Catalog> { + @Override + public void output(Catalog catalog) { + List<String> headers = Arrays.asList("catalog", "type", "provider", "comment"); + List<List<String>> rows = new ArrayList<>(); + rows.add( + Arrays.asList( + catalog.name(), + catalog.type().toString(), + catalog.provider(), + catalog.comment() + "")); + TableFormatImpl tableFormat = new TableFormatImpl(); + tableFormat.print(headers, rows); + } + } + + static final class TableFormatImpl { + private int[] maxElementLengths; + private final String horizontalDelimiter = "-"; + private final String verticalDelimiter = "|"; + private final String crossDelimiter = "+"; + private final String indent = " "; + + public void debug() { + System.out.println(); + Arrays.stream(maxElementLengths).forEach(e -> System.out.print(e + " ")); + } + + public void print(List<String> headers, List<List<String>> rows) { + if (rows.size() > 0 && headers.size() != rows.get(0).size()) { + throw new IllegalArgumentException("Number of columns is not equal."); + } + maxElementLengths = new int[headers.size()]; + updateMaxLengthsFromList(headers); + updateMaxLengthsFromNestedList(rows); + + // print headers + printLine(); + System.out.println(); + for (int i = 0; i < headers.size(); ++i) { + System.out.printf( + verticalDelimiter + indent + "%-" + maxElementLengths[i] + "s" + indent, + headers.get(i)); + } + System.out.println(verticalDelimiter); + printLine(); + System.out.println(); + + // print rows + for (int i = 0; i < rows.size(); ++i) { + List<String> columns = rows.get(i); + for (int j = 0; j < columns.size(); ++j) { + System.out.printf( + verticalDelimiter + indent + "%-" + maxElementLengths[j] + "s" + indent, + columns.get(j)); + } + System.out.println(verticalDelimiter); + } + printLine(); + // add one more line + System.out.println(""); + } + + private void updateMaxLengthsFromList(List<String> elements) { + String s; + for (int i = 0; i < elements.size(); ++i) { + s = elements.get(i); + if (s.length() > maxElementLengths[i]) maxElementLengths[i] = s.length(); + } + } + + private void updateMaxLengthsFromNestedList(List<List<String>> elements) { + for (List<String> row : elements) { + String s; + for (int i = 0; i < row.size(); ++i) { + s = row.get(i); + if (s.length() > maxElementLengths[i]) maxElementLengths[i] = s.length(); + } + } + } + + private void printLine() { + System.out.print(crossDelimiter); + for (int i = 0; i < maxElementLengths.length; ++i) { + for (int j = 0; j < maxElementLengths[i] + indent.length() * 2; ++j) { + System.out.print(horizontalDelimiter); + } + System.out.print(crossDelimiter); + } + } + } +} diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/TestCatalogCommands.java b/clients/cli/src/test/java/org/apache/gravitino/cli/TestCatalogCommands.java index c7a24b7a3..c337a342c 100644 --- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestCatalogCommands.java +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestCatalogCommands.java @@ -81,7 +81,8 @@ class TestCatalogCommands { mockCommandLine, mockOptions, CommandEntities.CATALOG, CommandActions.DETAILS)); doReturn(mockDetails) .when(commandLine) - .newCatalogDetails(GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", "catalog"); + .newCatalogDetails( + GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", "catalog", null); commandLine.handleCommandLine(); verify(mockDetails).handle(); } 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 d602d56d9..2b94a80a9 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 @@ -59,7 +59,9 @@ class TestMetalakeCommands { spy( new GravitinoCommandLine( mockCommandLine, mockOptions, CommandEntities.METALAKE, CommandActions.LIST)); - doReturn(mockList).when(commandLine).newListMetalakes(GravitinoCommandLine.DEFAULT_URL, false); + doReturn(mockList) + .when(commandLine) + .newListMetalakes(GravitinoCommandLine.DEFAULT_URL, false, null); commandLine.handleCommandLine(); verify(mockList).handle(); } @@ -76,7 +78,7 @@ class TestMetalakeCommands { mockCommandLine, mockOptions, CommandEntities.METALAKE, CommandActions.DETAILS)); doReturn(mockDetails) .when(commandLine) - .newMetalakeDetails(GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo"); + .newMetalakeDetails(GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", null); commandLine.handleCommandLine(); verify(mockDetails).handle(); } diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/integration/test/TableFormatOutputIT.java b/clients/cli/src/test/java/org/apache/gravitino/cli/integration/test/TableFormatOutputIT.java new file mode 100644 index 000000000..55cab8c5b --- /dev/null +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/integration/test/TableFormatOutputIT.java @@ -0,0 +1,166 @@ +/* + * 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.integration.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import org.apache.gravitino.cli.GravitinoOptions; +import org.apache.gravitino.cli.Main; +import org.apache.gravitino.integration.test.util.BaseIT; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class TableFormatOutputIT extends BaseIT { + private String gravitinoUrl; + + @BeforeAll + public void startUp() { + gravitinoUrl = String.format("http://127.0.0.1:%d", getGravitinoServerPort()); + String[] create_metalake_args = { + "metalake", + "create", + commandArg(GravitinoOptions.METALAKE), + "my_metalake", + commandArg(GravitinoOptions.COMMENT), + "my metalake", + commandArg(GravitinoOptions.URL), + gravitinoUrl + }; + Main.main(create_metalake_args); + + String[] create_catalog_args = { + "catalog", + "create", + commandArg(GravitinoOptions.METALAKE), + "my_metalake", + commandArg(GravitinoOptions.NAME), + "postgres", + commandArg(GravitinoOptions.PROVIDER), + "postgres", + commandArg(GravitinoOptions.PROPERTIES), + "jdbc-url=jdbc:postgresql://postgresql-host/mydb,jdbc-user=user,jdbc-password=password,jdbc-database=db,jdbc-driver=org.postgresql.Driver", + commandArg(GravitinoOptions.URL), + gravitinoUrl + }; + Main.main(create_catalog_args); + } + + @Test + public void testMetalakeListCommand() { + // Create a byte array output stream to capture the output of the command + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outputStream)); + + String[] args = { + "metalake", + "list", + commandArg(GravitinoOptions.OUTPUT), + "table", + commandArg(GravitinoOptions.URL), + gravitinoUrl + }; + Main.main(args); + + // Restore the original System.out + System.setOut(originalOut); + // Get the output and verify it + String output = new String(outputStream.toByteArray(), StandardCharsets.UTF_8).trim(); + assertEquals( + "+-------------+\n" + + "| metalake |\n" + + "+-------------+\n" + + "| my_metalake |\n" + + "+-------------+", + output); + } + + @Test + public void testMetalakeDetailsCommand() { + // Create a byte array output stream to capture the output of the command + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outputStream)); + + String[] args = { + "metalake", + "details", + commandArg(GravitinoOptions.METALAKE), + "my_metalake", + commandArg(GravitinoOptions.OUTPUT), + "table", + commandArg(GravitinoOptions.URL), + gravitinoUrl + }; + Main.main(args); + + // Restore the original System.out + System.setOut(originalOut); + // Get the output and verify it + String output = new String(outputStream.toByteArray(), StandardCharsets.UTF_8).trim(); + assertEquals( + "+-------------+-------------+\n" + + "| metalake | comment |\n" + + "+-------------+-------------+\n" + + "| my_metalake | my metalake |\n" + + "+-------------+-------------+", + output); + } + + @Test + public void testCatalogDetailsCommand() { + // Create a byte array output stream to capture the output of the command + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PrintStream originalOut = System.out; + System.setOut(new PrintStream(outputStream)); + + String[] args = { + "catalog", + "details", + commandArg(GravitinoOptions.METALAKE), + "my_metalake", + commandArg(GravitinoOptions.NAME), + "postgres", + commandArg(GravitinoOptions.OUTPUT), + "table", + commandArg(GravitinoOptions.URL), + gravitinoUrl + }; + Main.main(args); + + // Restore the original System.out + System.setOut(originalOut); + // Get the output and verify it + String output = new String(outputStream.toByteArray(), StandardCharsets.UTF_8).trim(); + assertEquals( + "+----------+------------+-----------------+---------+\n" + + "| catalog | type | provider | comment |\n" + + "+----------+------------+-----------------+---------+\n" + + "| postgres | RELATIONAL | jdbc-postgresql | null |\n" + + "+----------+------------+-----------------+---------+", + output); + } + + private String commandArg(String arg) { + return String.format("--%s", arg); + } +}