org.apache.hive.beeline.util.QFileClient Maven / Gradle / Ivy
/**
* 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.hive.beeline.util;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
import org.apache.hive.beeline.BeeLine;
/**
* QTestClient.
*
*/
public class QFileClient {
private String username;
private String password;
private String jdbcUrl;
private String jdbcDriver;
private final File hiveRootDirectory;
private File qFileDirectory;
private File outputDirectory;
private File expectedDirectory;
private final File scratchDirectory;
private final File warehouseDirectory;
private File testDataDirectory;
private File testScriptDirectory;
private String qFileName;
private String testname;
private File qFile;
private File outputFile;
private File expectedFile;
private PrintStream beelineOutputStream;
private BeeLine beeLine;
private RegexFilterSet filterSet;
private boolean hasErrors = false;
private static Log LOG = LogFactory
.getLog(QFileClient.class.getName());
public QFileClient(HiveConf hiveConf, String hiveRootDirectory, String qFileDirectory, String outputDirectory,
String expectedDirectory) {
this.hiveRootDirectory = new File(hiveRootDirectory);
this.qFileDirectory = new File(qFileDirectory);
this.outputDirectory = new File(outputDirectory);
this.expectedDirectory = new File(expectedDirectory);
this.scratchDirectory = new File(hiveConf.getVar(ConfVars.SCRATCHDIR));
this.warehouseDirectory = new File(hiveConf.getVar(ConfVars.METASTOREWAREHOUSE));
}
private class RegexFilterSet {
private final Map regexFilters = new LinkedHashMap();
public RegexFilterSet addFilter(String regex, String replacement) {
regexFilters.put(Pattern.compile(regex), replacement);
return this;
}
public String filter(String input) {
for (Pattern pattern : regexFilters.keySet()) {
input = pattern.matcher(input).replaceAll(regexFilters.get(pattern));
}
return input;
}
}
void initFilterSet() {
// Extract the leading four digits from the unix time value.
// Use this as a prefix in order to increase the selectivity
// of the unix time stamp replacement regex.
String currentTimePrefix = Long.toString(System.currentTimeMillis()).substring(0, 4);
String userName = System.getProperty("user.name");
String timePattern = "(Mon|Tue|Wed|Thu|Fri|Sat|Sun) "
+ "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) "
+ "\\d{2} \\d{2}:\\d{2}:\\d{2} \\w+ 20\\d{2}";
String unixTimePattern = "\\D" + currentTimePrefix + "\\d{6}\\D";
String unixTimeMillisPattern = "\\D" + currentTimePrefix + "\\d{9}\\D";
String operatorPattern = "\"(CONDITION|COPY|DEPENDENCY_COLLECTION|DDL"
+ "|EXPLAIN|FETCH|FIL|FS|FUNCTION|GBY|HASHTABLEDUMMY|HASTTABLESINK|JOIN"
+ "|LATERALVIEWFORWARD|LIM|LVJ|MAP|MAPJOIN|MAPRED|MAPREDLOCAL|MOVE|OP|RS"
+ "|SCR|SEL|STATS|TS|UDTF|UNION)_\\d+\"";
filterSet = new RegexFilterSet()
.addFilter(scratchDirectory.toString() + "[\\w\\-/]+", "!!{hive.exec.scratchdir}!!")
.addFilter(warehouseDirectory.toString(), "!!{hive.metastore.warehouse.dir}!!")
.addFilter(expectedDirectory.toString(), "!!{expectedDirectory}!!")
.addFilter(outputDirectory.toString(), "!!{outputDirectory}!!")
.addFilter(qFileDirectory.toString(), "!!{qFileDirectory}!!")
.addFilter(hiveRootDirectory.toString(), "!!{hive.root}!!")
.addFilter("file:/\\w\\S+", "file:/!!ELIDED!!")
.addFilter("pfile:/\\w\\S+", "pfile:/!!ELIDED!!")
.addFilter("hdfs:/\\w\\S+", "hdfs:/!!ELIDED!!")
.addFilter("last_modified_by=\\w+", "last_modified_by=!!ELIDED!!")
.addFilter(timePattern, "!!TIMESTAMP!!")
.addFilter("(\\D)" + currentTimePrefix + "\\d{6}(\\D)", "$1!!UNIXTIME!!$2")
.addFilter("(\\D)" + currentTimePrefix + "\\d{9}(\\D)", "$1!!UNIXTIMEMILLIS!!$2")
.addFilter(userName, "!!{user.name}!!")
.addFilter(operatorPattern, "\"$1_!!ELIDED!!\"")
;
};
public QFileClient setUsername(String username) {
this.username = username;
return this;
}
public QFileClient setPassword(String password) {
this.password = password;
return this;
}
public QFileClient setJdbcUrl(String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
return this;
}
public QFileClient setJdbcDriver(String jdbcDriver) {
this.jdbcDriver = jdbcDriver;
return this;
}
public QFileClient setQFileName(String qFileName) {
this.qFileName = qFileName;
this.qFile = new File(qFileDirectory, qFileName);
this.testname = StringUtils.substringBefore(qFileName, ".");
expectedFile = new File(expectedDirectory, qFileName + ".out");
outputFile = new File(outputDirectory, qFileName + ".out");
return this;
}
public QFileClient setQFileDirectory(String qFileDirectory) {
this.qFileDirectory = new File(qFileDirectory);
return this;
}
public QFileClient setOutputDirectory(String outputDirectory) {
this.outputDirectory = new File(outputDirectory);
return this;
}
public QFileClient setExpectedDirectory(String expectedDirectory) {
this.expectedDirectory = new File(expectedDirectory);
return this;
}
public QFileClient setTestDataDirectory(String testDataDirectory) {
this.testDataDirectory = new File(testDataDirectory);
return this;
}
public QFileClient setTestScriptDirectory(String testScriptDirectory) {
this.testScriptDirectory = new File(testScriptDirectory);
return this;
}
public boolean hasErrors() {
return hasErrors;
}
private void initBeeLine() throws Exception {
beeLine = new BeeLine();
beelineOutputStream = new PrintStream(new File(outputDirectory, qFileName + ".beeline"));
beeLine.setOutputStream(beelineOutputStream);
beeLine.setErrorStream(beelineOutputStream);
beeLine.runCommands(new String[] {
"!set verbose true",
"!set shownestederrs true",
"!set showwarnings true",
"!set showelapsedtime false",
"!set maxwidth -1",
"!connect " + jdbcUrl + " " + username + " " + password + " " + jdbcDriver,
});
}
private void setUp() {
beeLine.runCommands(new String[] {
"USE default;",
"SHOW TABLES;",
"DROP DATABASE IF EXISTS `" + testname + "` CASCADE;",
"CREATE DATABASE `" + testname + "`;",
"USE `" + testname + "`;",
"set test.data.dir=" + testDataDirectory + ";",
"set test.script.dir=" + testScriptDirectory + ";",
"!run " + testScriptDirectory + "/q_test_init.sql",
});
}
private void tearDown() {
beeLine.runCommands(new String[] {
"!set outputformat table",
"USE default;",
"DROP DATABASE IF EXISTS `" + testname + "` CASCADE;",
});
}
private void runQFileTest() throws Exception {
hasErrors = false;
beeLine.runCommands(new String[] {
"!set outputformat csv",
"!record " + outputDirectory + "/" + qFileName + ".raw",
});
if (1 != beeLine.runCommands(new String[] { "!run " + qFileDirectory + "/" + qFileName })) {
hasErrors = true;
}
beeLine.runCommands(new String[] { "!record" });
}
private void filterResults() throws IOException {
initFilterSet();
String rawOutput = FileUtils.readFileToString(new File(outputDirectory, qFileName + ".raw"));
FileUtils.writeStringToFile(outputFile, filterSet.filter(rawOutput));
}
public void cleanup() {
if (beeLine != null) {
beeLine.runCommands(new String[] {
"!quit"
});
}
if (beelineOutputStream != null) {
beelineOutputStream.close();
}
if (hasErrors) {
String oldFileName = outputDirectory + "/" + qFileName + ".raw";
String newFileName = oldFileName + ".error";
try {
FileUtils.moveFile(new File(oldFileName), new File(newFileName));
} catch (IOException e) {
System.out.println("Failed to move '" + oldFileName + "' to '" + newFileName);
}
}
}
public void run() throws Exception {
try {
initBeeLine();
setUp();
runQFileTest();
tearDown();
filterResults();
} finally {
cleanup();
}
}
/**
* Does the test have a file with expected results to compare the log against.
* False probably indicates that this is a new test and the caller should
* copy the log to the expected results directory.
* @return
*/
public boolean hasExpectedResults() {
return expectedFile.exists();
}
public boolean compareResults() throws IOException {
if (!expectedFile.exists()) {
LOG.error("Expected results file does not exist: " + expectedFile);
return false;
}
return FileUtils.contentEquals(expectedFile, outputFile);
}
public void overwriteResults() {
try {
if (expectedFile.exists()) {
FileUtils.forceDelete(expectedFile);
}
FileUtils.copyFileToDirectory(outputFile, expectedDirectory, true);
} catch (IOException e) {
LOG.error("Failed to overwrite results!", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy