diff --git itests/util/src/main/java/org/apache/hadoop/hive/cli/control/CoreBeeLineDriver.java itests/util/src/main/java/org/apache/hadoop/hive/cli/control/CoreBeeLineDriver.java index acc02eb..7bb7be0 100644 --- itests/util/src/main/java/org/apache/hadoop/hive/cli/control/CoreBeeLineDriver.java +++ itests/util/src/main/java/org/apache/hadoop/hive/cli/control/CoreBeeLineDriver.java @@ -20,7 +20,9 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import com.google.common.base.Strings; import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.ql.QTestProcessExecResult; import org.apache.hadoop.hive.ql.hooks.PreExecutePrinter; import org.apache.hive.beeline.qfile.QFile; import org.apache.hive.beeline.qfile.QFile.QFileBuilder; @@ -32,6 +34,7 @@ import java.io.File; import java.io.IOException; +import java.sql.SQLException; import java.util.HashMap; public class CoreBeeLineDriver extends CliAdapter { @@ -104,7 +107,7 @@ public void beforeClass() throws Exception { } protected void runInfraScript(File script, File beeLineOutput, File log) - throws IOException { + throws IOException, SQLException { try (QFileBeeLineClient beeLineClient = clientBuilder.getClient(beeLineOutput)) { beeLineClient.execute( new String[]{ @@ -114,6 +117,9 @@ protected void runInfraScript(File script, File beeLineOutput, File log) "!run " + script, }, log); + } catch (Exception e) { + throw new SQLException("Error running infra script: " + script + + "\nCheck the following logs for details:\n - " + beeLineOutput + "\n - " + log, e); } } @@ -134,7 +140,8 @@ public void runTest(QFile qFile) throws Exception { try (QFileBeeLineClient beeLineClient = clientBuilder.getClient(qFile.getLogFile())) { long startTime = System.currentTimeMillis(); System.err.println(">>> STARTED " + qFile.getName()); - assertTrue("QFile execution failed, see logs for details", beeLineClient.execute(qFile)); + + beeLineClient.execute(qFile); long endTime = System.currentTimeMillis(); System.err.println(">>> EXECUTED " + qFile.getName() + ":" + (endTime - startTime) / 1000 @@ -146,16 +153,24 @@ public void runTest(QFile qFile) throws Exception { + "s"); if (!overwrite) { - if (qFile.compareResults()) { + QTestProcessExecResult result = qFile.compareResults(); + if (result.getReturnCode() == 0) { System.err.println(">>> PASSED " + qFile.getName()); } else { System.err.println(">>> FAILED " + qFile.getName()); - fail("Failed diff"); + String messageText = "Client result comparison failed with error code = " + + result.getReturnCode() + " while executing fname=" + qFile.getName() + "\n"; + String messageBody = Strings.isNullOrEmpty(result.getCapturedOutput()) ? + qFile.getDebugHint() : result.getCapturedOutput(); + fail(messageText + messageBody); } } else { qFile.overwriteResults(); System.err.println(">>> PASSED " + qFile.getName()); } + } catch (Exception e) { + throw new Exception("Exception running or analyzing the results of the query file: " + qFile + + "\n" + qFile.getDebugHint(), e); } } diff --git itests/util/src/main/java/org/apache/hive/beeline/qfile/QFile.java itests/util/src/main/java/org/apache/hive/beeline/qfile/QFile.java index 49d6d24..22c0a28 100644 --- itests/util/src/main/java/org/apache/hive/beeline/qfile/QFile.java +++ itests/util/src/main/java/org/apache/hive/beeline/qfile/QFile.java @@ -19,13 +19,17 @@ package org.apache.hive.beeline.qfile; import org.apache.commons.io.FileUtils; +import org.apache.hadoop.hive.ql.QTestProcessExecResult; import org.apache.hadoop.util.Shell; import org.apache.hive.common.util.StreamPrinter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -45,7 +49,8 @@ private File outputFile; private File expcetedOutputFile; private File logFile; - private File infraLogFile; + private File beforeExecuteLogFile; + private File afterExecuteLogFile; private static RegexFilterSet staticFilterSet = getStaticFilterSet(); private RegexFilterSet specificFilterSet; @@ -75,8 +80,24 @@ public File getLogFile() { return logFile; } - public File getInfraLogFile() { - return infraLogFile; + public File getBeforeExecuteLogFile() { + return beforeExecuteLogFile; + } + + public File getAfterExecuteLogFile() { + return afterExecuteLogFile; + } + + public String getDebugHint() { + return "The following files can help you identifying the problem:\n" + + " - Query file: " + inputFile + "\n" + + " - Raw output file: " + rawOutputFile + "\n" + + " - Filtered output file: " + outputFile + "\n" + + " - Expected output file: " + expcetedOutputFile + "\n" + + " - Client log file: " + logFile + "\n" + + " - Client log files before the test: " + beforeExecuteLogFile + "\n" + + " - Client log files after the test: " + afterExecuteLogFile + "\n" + + " - Hiveserver2 log file: ./itests/qtest/target/tmp/hive.log\n"; } public void filterOutput() throws IOException { @@ -85,22 +106,18 @@ public void filterOutput() throws IOException { FileUtils.writeStringToFile(outputFile, filteredOutput); } - public boolean compareResults() throws IOException, InterruptedException { + public QTestProcessExecResult compareResults() throws IOException, InterruptedException { if (!expcetedOutputFile.exists()) { - LOG.error("Expected results file does not exist: " + expcetedOutputFile); - return false; + throw new IOException("Expected results file does not exist: " + expcetedOutputFile); } return executeDiff(); } public void overwriteResults() throws IOException { - if (expcetedOutputFile.exists()) { - FileUtils.forceDelete(expcetedOutputFile); - } FileUtils.copyFile(outputFile, expcetedOutputFile); } - private boolean executeDiff() throws IOException, InterruptedException { + private QTestProcessExecResult executeDiff() throws IOException, InterruptedException { List diffCommandArgs = new ArrayList(); diffCommandArgs.add("diff"); @@ -129,8 +146,11 @@ private boolean executeDiff() throws IOException, InterruptedException { Process executor = Runtime.getRuntime().exec(diffCommandArgs.toArray( new String[diffCommandArgs.size()])); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + PrintStream out = new PrintStream(bos, true); + StreamPrinter errPrinter = new StreamPrinter(executor.getErrorStream(), null, System.err); - StreamPrinter outPrinter = new StreamPrinter(executor.getInputStream(), null, System.out); + StreamPrinter outPrinter = new StreamPrinter(executor.getInputStream(), null, System.out, out); outPrinter.start(); errPrinter.start(); @@ -142,7 +162,8 @@ private boolean executeDiff() throws IOException, InterruptedException { executor.waitFor(); - return (result == 0); + return QTestProcessExecResult.create(result, new String(bos.toByteArray(), + StandardCharsets.UTF_8)); } private static String getQuotedString(File file) { @@ -257,7 +278,8 @@ public QFile getQFile(String name) throws IOException { result.outputFile = new File(logDirectory, name + ".q.out"); result.expcetedOutputFile = new File(resultsDirectory, name + ".q.out"); result.logFile = new File(logDirectory, name + ".q.beeline"); - result.infraLogFile = new File(logDirectory, name + ".q.out.infra"); + result.beforeExecuteLogFile = new File(logDirectory, name + ".q.out.before"); + result.afterExecuteLogFile = new File(logDirectory, name + ".q.out.after"); // These are the filters which are specific for the given QTest. // Check staticFilterSet for common filters. result.specificFilterSet = new RegexFilterSet() diff --git itests/util/src/main/java/org/apache/hive/beeline/qfile/QFileBeeLineClient.java itests/util/src/main/java/org/apache/hive/beeline/qfile/QFileBeeLineClient.java index b6eac89..eb9daf5 100644 --- itests/util/src/main/java/org/apache/hive/beeline/qfile/QFileBeeLineClient.java +++ itests/util/src/main/java/org/apache/hive/beeline/qfile/QFileBeeLineClient.java @@ -23,6 +23,8 @@ import java.io.File; import java.io.IOException; import java.io.PrintStream; +import java.sql.SQLException; +import java.util.Arrays; /** * QFile test client using BeeLine. It can be used to submit a list of command strings, or a QFile. @@ -50,24 +52,23 @@ protected QFileBeeLineClient(String jdbcUrl, String jdbcDriver, String username, }); } - public boolean execute(String[] commands, File resultFile) { - boolean hasErrors = false; + public void execute(String[] commands, File resultFile) throws SQLException { beeLine.runCommands( new String[] { "!set outputformat csv", "!record " + resultFile.getAbsolutePath() }); - if (commands.length != beeLine.runCommands(commands)) { - hasErrors = true; + int lastSuccessfulCommand = beeLine.runCommands(commands); + if (commands.length != lastSuccessfulCommand) { + throw new SQLException("Error executing SQL command: " + commands[lastSuccessfulCommand]); } beeLine.runCommands(new String[] {"!record"}); - return !hasErrors; } - private void beforeExecute(QFile qFile) { - assert(execute( + private void beforeExecute(QFile qFile) throws SQLException { + execute( new String[] { "USE default;", "SHOW TABLES;", @@ -75,27 +76,26 @@ private void beforeExecute(QFile qFile) { "CREATE DATABASE `" + qFile.getName() + "`;", "USE `" + qFile.getName() + "`;" }, - qFile.getInfraLogFile())); + qFile.getBeforeExecuteLogFile()); } - private void afterExecute(QFile qFile) { - assert(execute( + private void afterExecute(QFile qFile) throws SQLException { + execute( new String[] { "USE default;", "DROP DATABASE IF EXISTS `" + qFile.getName() + "` CASCADE;", }, - qFile.getInfraLogFile())); + qFile.getAfterExecuteLogFile()); } - public boolean execute(QFile qFile) { + public void execute(QFile qFile) throws SQLException { beforeExecute(qFile); - boolean result = execute( + execute( new String[] { "!run " + qFile.getInputFile().getAbsolutePath() }, qFile.getRawOutputFile()); afterExecute(qFile); - return result; } public void close() {