Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions parquet-cli/src/test/java/org/apache/parquet/cli/CapturingLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
* 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.parquet.cli;

import org.slf4j.helpers.MarkerIgnoringBase;
import org.slf4j.helpers.MessageFormatter;

// CapturingLogger is a wrapper around the slf4j logger to capture CLI ourput to use with tests.
final class CapturingLogger extends MarkerIgnoringBase implements org.slf4j.Logger {
private final StringBuilder buf = new StringBuilder();

@Override
public String getName() {
return "CliTestLogger";
}

private void append(String msg) {
if (msg != null && !msg.isEmpty()) {
buf.append(msg).append('\n');
}
}

private void log(String fmt, Object... args) {
String message = MessageFormatter.arrayFormat(fmt, args).getMessage();
append(message);
}

String dump() {
return buf.toString();
}

// Since the CLI logic can call any console method, this is some needed delegator code to
// ensure all methods are coverted and that the test harness does not miss anything.
// Unfortunately slf4j API does not make this easy to do in a generic way, so we
// have to manually add each method.

@Override
public boolean isTraceEnabled() {
return true;
}

@Override
public boolean isDebugEnabled() {
return true;
}

@Override
public boolean isInfoEnabled() {
return true;
}

@Override
public boolean isWarnEnabled() {
return true;
}

@Override
public boolean isErrorEnabled() {
return true;
}

@Override
public void trace(String msg) {
append(msg);
}

@Override
public void trace(String format, Object arg) {
log(format, arg);
}

@Override
public void trace(String format, Object arg1, Object arg2) {
log(format, arg1, arg2);
}

@Override
public void trace(String format, Object... arguments) {
log(format, arguments);
}

@Override
public void trace(String msg, Throwable t) {
append(msg);
}

@Override
public void debug(String msg) {
append(msg);
}

@Override
public void debug(String format, Object arg) {
log(format, arg);
}

@Override
public void debug(String format, Object arg1, Object arg2) {
log(format, arg1, arg2);
}

@Override
public void debug(String format, Object... arguments) {
log(format, arguments);
}

@Override
public void debug(String msg, Throwable t) {
append(msg);
}

@Override
public void info(String msg) {
append(msg);
}

@Override
public void info(String format, Object arg) {
log(format, arg);
}

@Override
public void info(String format, Object arg1, Object arg2) {
log(format, arg1, arg2);
}

@Override
public void info(String format, Object... arguments) {
log(format, arguments);
}

@Override
public void info(String msg, Throwable t) {
append(msg);
}

@Override
public void warn(String msg) {
append(msg);
}

@Override
public void warn(String format, Object arg) {
log(format, arg);
}

@Override
public void warn(String format, Object arg1, Object arg2) {
log(format, arg1, arg2);
}

@Override
public void warn(String format, Object... arguments) {
log(format, arguments);
}

@Override
public void warn(String msg, Throwable t) {
append(msg);
}

@Override
public void error(String msg) {
append(msg);
}

@Override
public void error(String format, Object arg) {
log(format, arg);
}

@Override
public void error(String format, Object arg1, Object arg2) {
log(format, arg1, arg2);
}

@Override
public void error(String format, Object... arguments) {
log(format, arguments);
}

@Override
public void error(String msg, Throwable t) {
append(msg);
}
}
34 changes: 34 additions & 0 deletions parquet-cli/src/test/java/org/apache/parquet/cli/CliHarness.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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.parquet.cli;

import org.apache.hadoop.conf.Configuration;
import org.slf4j.Logger;

public final class CliHarness {
public CliResult run(String[] args) throws Exception {
CapturingLogger logger = new CapturingLogger();
Main main = new Main((Logger) logger);
main.setConf(new Configuration());
int code = main.run(args);

CliResult result = new CliResult(code, logger.dump());
return result;
}
}
71 changes: 71 additions & 0 deletions parquet-cli/src/test/java/org/apache/parquet/cli/CliResult.java
Original file line number Diff line number Diff line change
@@ -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.parquet.cli;

import static org.junit.Assert.*;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

public final class CliResult {
public final int exitCode;
public final String text;

CliResult(int exitCode, String text) {
this.exitCode = exitCode;
this.text = text;
}

public CliResult ok() {
assertEquals("exit", 0, exitCode);
return this;
}

public CliResult fails(int code) {
assertEquals("exit", code, exitCode);
return this;
}

public CliResult outputContains(String... parts) {
for (String p : parts) assertTrue("missing: " + p, text.contains(p));
return this;
}

public CliResult outputNotContains(String... parts) {
for (String p : parts) assertFalse("should not contain: " + p, text.contains(p));
return this;
}

public CliResult lineCount(int expected) {
long cnt = 0;
for (String line : text.split("\n")) {
if (!line.trim().isEmpty()) {
cnt++;
}
}
assertEquals(expected, cnt);
return this;
}

public CliResult matchOutputFromFile(String filePath) throws Exception {
String expected = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
return outputContains(expected);
}
}
64 changes: 64 additions & 0 deletions parquet-cli/src/test/java/org/apache/parquet/cli/CliTestBase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* 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.parquet.cli;

import org.apache.parquet.cli.commands.ParquetFileTest;

/**
* Base class for CLI integration tests with an API for testing command output.
*
* Developer Usage Examples:
*
* // Basic command execution and assertion
* cli("schema file.parquet")
* .ok()
* .outputContains("int32_field", "int64_field");
*
* // Test help output
* cli("help size-stats")
* .ok()
* .matchOutputFromFile("expected-help.txt");
*
* // Test error conditions
* cli("invalid-command")
* .fails(1)
* .outputContains("Unknown command");
*
* // Test command with multiple arguments
* cli("size-stats parquetFile.getAbsolutePath()")
* .ok()
* .lineCount(8);
*
*/
public abstract class CliTestBase extends ParquetFileTest {
private final CliHarness harness = new CliHarness();

protected CliResult cli(Object... args) throws Exception {
String[] a = new String[args.length];
for (int i = 0; i < args.length; i++) {
a[i] = String.valueOf(args[i]);
}
return harness.run(a);
}

protected CliResult cli(String commandLine) throws Exception {
String[] args = commandLine.split("\\s+");
return cli((Object[]) args);
}
}
Loading
Loading