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..0d63f5d 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 @@ -17,10 +17,11 @@ */ package org.apache.hadoop.hive.cli.control; -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 +33,7 @@ import java.io.File; import java.io.IOException; +import java.sql.SQLException; import java.util.HashMap; public class CoreBeeLineDriver extends CliAdapter { @@ -104,7 +106,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 +116,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,28 +139,41 @@ 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)); - long endTime = System.currentTimeMillis(); - System.err.println(">>> EXECUTED " + qFile.getName() + ":" + (endTime - startTime) / 1000 - + "s"); + beeLineClient.execute(qFile); + + long queryEndTime = System.currentTimeMillis(); + System.err.println(">>> EXECUTED " + qFile.getName() + ": " + (queryEndTime - startTime) + + "ms"); qFile.filterOutput(); long filterEndTime = System.currentTimeMillis(); - System.err.println(">>> FILTERED " + qFile.getName() + ":" + (filterEndTime - endTime) / 1000 - + "s"); + System.err.println(">>> FILTERED " + qFile.getName() + ": " + (filterEndTime - queryEndTime) + + "ms"); if (!overwrite) { - if (qFile.compareResults()) { + QTestProcessExecResult result = qFile.compareResults(); + + long compareEndTime = System.currentTimeMillis(); + System.err.println(">>> COMPARED " + qFile.getName() + ": " + + (compareEndTime - filterEndTime) + "ms"); + 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..27e96fd 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,15 @@ 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; @@ -37,15 +39,25 @@ * input and output files, and provides methods for filtering the output of the runs. */ public final class QFile { - private static final Logger LOG = LoggerFactory.getLogger(QFile.class.getName()); + private static final String DEBUG_HINT = + "The following files can help you identifying the problem:\n" + + " - Query file: %1\n" + + " - Raw output file: %2\n" + + " - Filtered output file: %3\n" + + " - Expected output file: %4\n" + + " - Client log file: %5\n" + + " - Client log files before the test: %6\n" + + " - Client log files after the test: %7\n" + + " - Hiveserver2 log file: %8\n"; private String name; private File inputFile; private File rawOutputFile; private File outputFile; - private File expcetedOutputFile; + private File expectedOutputFile; private File logFile; - private File infraLogFile; + private File beforeExecuteLogFile; + private File afterExecuteLogFile; private static RegexFilterSet staticFilterSet = getStaticFilterSet(); private RegexFilterSet specificFilterSet; @@ -68,15 +80,24 @@ public File getOutputFile() { } public File getExpectedOutputFile() { - return expcetedOutputFile; + return expectedOutputFile; } public File getLogFile() { return logFile; } - public File getInfraLogFile() { - return infraLogFile; + public File getBeforeExecuteLogFile() { + return beforeExecuteLogFile; + } + + public File getAfterExecuteLogFile() { + return afterExecuteLogFile; + } + + public String getDebugHint() { + return String.format(DEBUG_HINT, inputFile, rawOutputFile, outputFile, expectedOutputFile, + logFile, beforeExecuteLogFile, afterExecuteLogFile, "./itests/qtest/target/tmp/hive.log"); } public void filterOutput() throws IOException { @@ -85,22 +106,18 @@ public void filterOutput() throws IOException { FileUtils.writeStringToFile(outputFile, filteredOutput); } - public boolean compareResults() throws IOException, InterruptedException { - if (!expcetedOutputFile.exists()) { - LOG.error("Expected results file does not exist: " + expcetedOutputFile); - return false; + public QTestProcessExecResult compareResults() throws IOException, InterruptedException { + if (!expectedOutputFile.exists()) { + throw new IOException("Expected results file does not exist: " + expectedOutputFile); } return executeDiff(); } public void overwriteResults() throws IOException { - if (expcetedOutputFile.exists()) { - FileUtils.forceDelete(expcetedOutputFile); - } - FileUtils.copyFile(outputFile, expcetedOutputFile); + FileUtils.copyFile(outputFile, expectedOutputFile); } - private boolean executeDiff() throws IOException, InterruptedException { + private QTestProcessExecResult executeDiff() throws IOException, InterruptedException { List diffCommandArgs = new ArrayList(); diffCommandArgs.add("diff"); @@ -121,7 +138,7 @@ private boolean executeDiff() throws IOException, InterruptedException { } // Add files to compare to the arguments list - diffCommandArgs.add(getQuotedString(expcetedOutputFile)); + diffCommandArgs.add(getQuotedString(expectedOutputFile)); diffCommandArgs.add(getQuotedString(outputFile)); System.out.println("Running: " + org.apache.commons.lang.StringUtils.join(diffCommandArgs, @@ -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, "UTF-8"); + 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) { @@ -255,9 +276,10 @@ public QFile getQFile(String name) throws IOException { result.inputFile = new File(queryDirectory, name + ".q"); result.rawOutputFile = new File(logDirectory, name + ".q.out.raw"); result.outputFile = new File(logDirectory, name + ".q.out"); - result.expcetedOutputFile = new File(resultsDirectory, name + ".q.out"); + result.expectedOutputFile = 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.beforeExecute.log"); + result.afterExecuteLogFile = new File(logDirectory, name + ".q.afterExecute.log"); // 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..760fde6 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,7 @@ import java.io.File; import java.io.IOException; import java.io.PrintStream; +import java.sql.SQLException; /** * QFile test client using BeeLine. It can be used to submit a list of command strings, or a QFile. @@ -50,24 +51,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 +75,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() {