Query File Test(qtest)

Query File Test is a JUnit-based integration test suite for Apache Hive. Developers write any SQL; the testing framework runs it and verifies the result and output.

Tutorial: How to run a specific test case

Preparation

You have to compile Hive’s source codes ahead of time.

$ mvn clean install -Dmaven.javadoc.skip=true -DskipTests -Pitests

Run a test case

Let’s try to run alter1.q.

$ mvn test -Pitests -pl itests/qtest -Dtest=TestMiniLlapLocalCliDriver -Dqfile=alter1.q

The test should successfully finish.

[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

Tutorial: How to add a new test case

Add a QFile

A QFile includes a set of SQL statements that you want to test. Typically, we should put a new file in ql/src/test/queries/clientpositive.

Let’s say you created the following file.

$ cat ql/src/test/queries/clientpositive/aaa.q
SELECT 1;

Generate a result file

You can generate the expected output with -Dtest.output.overwrite=true.

$ mvn test -Pitests -pl itests/qtest -Dtest=TestMiniLlapLocalCliDriver -Dtest.output.overwrite=true -Dqfile=aaa.q
...
$ cat ql/src/test/results/clientpositive/llap/aaa.q.out
PREHOOK: query: SELECT 1
PREHOOK: type: QUERY
PREHOOK: Input: _dummy_database@_dummy_table
#### A masked pattern was here ####
POSTHOOK: query: SELECT 1
POSTHOOK: type: QUERY
POSTHOOK: Input: _dummy_database@_dummy_table
#### A masked pattern was here ####
1

Verify the new result file

You can ensure the generated result file is correct by rerunning the test case without -Dtest.output.overwrite=true.

$ mvn test -Pitests -pl itests/qtest -Dtest=TestMiniLlapLocalCliDriver -Dqfile=aaa.q

Commandline options

Test options

Option Description Example
test The class name of the test driver -Dtest=TestMiniLlapLocalCliDriver
qfile The name(s) of Query Files -Dqfile=alter1.q, -Dqfile=alter1.q,alter2.q
qfile_regex The pattern to list Query Files -Dqfile_regex=alter[0-9]
test.output.overwrite Whether you want to (re)generate result files or not -Dtest.output.overwrite=true
test.metastore.db Which RDBMS to be used as a metastore backend See How to use PostgreSQL/MySQL/Oracle as a backend database for Hive Metastore

Test Iceberg, Accumulo, or Kudu

Most test drivers are available in the itest/qtest project. However, there are some exceptional ones.

Driver Project
TestAccumuloCliDriver itest/qtest-accumulo
TestIcebergCliDriver itest/qtest-iceberg
TestIcebergLlapLocalCliDriver itest/qtest-iceberg
TestIcebergLlapLocalCompactorCliDriver itest/qtest-iceberg
TestIcebergNegativeCliDriver itest/qtest-iceberg
TestKuduCliDriver itest/qtest-kudu
TestKuduNegativeCliDriver itest/qtest-kudu

When you use TestIcebergLlapLocalCliDriver, you have to specify -pl itest/qtest-iceberg.

$ mvn test -Pitests -pl itests/qtest-iceberg -Dtest=TestIcebergLlapLocalCliDriver -Dqfile_regex=iceberg_bucket_map_join_8

QTestOptionHandler: pre/post-processor

We extend JUnit by implementing QTestOptionHandlers, which are custom pre-processors and post-processors. This section explains a couple of typical processors.

Using test data

Adding --! qt:dataset:{table name}, QTestDatasetHandler automatically sets up a test table. You can find the table definitions here.

--! qt:dataset:src
SELECT * FROM src;

Mask non-deterministic outputs

Some test cases generate random results. QTestReplaceHandler masks such a non-deterministic part. You can use it with a special comment prefixed with --! qt:replace:.

For example, the result of CURRENT_DATE changes every day. Using the comment, the output will be non-deterministic-output #Masked#, which is stable across executions.

--! qt:replace:/(non-deterministic-output\s)[0-9]{4}-[0-9]{2}-[0-9]{2}/$1#Masked#/
SELECT 'non-deterministic-output', CURRENT_DATE();

Advanced

Locations of log files

The Query File Test framework outputs log files in the following paths.

Negative tests

Negative drivers allow us to make sure that a test case fails expectedly. For example, the query in strict_timestamp_to_numeric.q must fail based on Hive’s specifications. We can use TestNegativeLlapLocalCliDriver, TestIcebergNegativeCliDriver, and so on.

$ mvn -Pitests -pl itests/qtest test -Dtest=TestNegativeLlapLocalCliDriver -Dqfile=strict_timestamp_to_numeric.q

How to specify drivers

We define the default mapping of Query Files and test drivers using testconfiguration.properties and CliConfigs. For example, TestMiniLlapLocalCliDriver is the default driver for query files stored in ql/src/test/queries/clientpositive. The hive-precommit Jenkins job also follows the mapping.

You can override the mapping through testconfiguration.properties. For example, if you want to test ql/src/test/queries/clientpositive/aaa.q not by LLAP but by Tez, you must include the file name in minitez.query.files and generate the result file with -Dtest=TestMiniTezCliDriver.

In most cases, we should use TestMiniLlapLocalCliDriver for positive tests and TestNegativeLlapLocalCliDriver for negative tests.

How to use PostgreSQL/MySQL/Oracle as a backend database for Hive Metastore

To run a test with a specified DB, it is possible by adding the “-Dtest.metastore.db” parameter like in the following commands:

$ mvn test -Pitests -pl itests/qtest -Dtest=TestCliDriver -Dqfile=partition_params_postgres.q -Dtest.metastore.db=postgres
$ mvn test -Pitests -pl itests/qtest -Dtest=TestCliDriver -Dqfile=partition_params_postgres.q -Dtest.metastore.db=mssql
$ mvn test -Pitests -pl itests/qtest -Dtest=TestCliDriver -Dqfile=partition_params_postgres.q -Dtest.metastore.db=mysql
$ mvn test -Pitests -pl itests/qtest -Dtest=TestCliDriver -Dqfile=partition_params_postgres.q -Dtest.metastore.db=oracle -Ditest.jdbc.jars=/path/to/your/god/damn/oracle/jdbc/driver/ojdbc6.jar

Remote debug

Remote debugging with Query File Test is a potent tool for debugging Hive. With the following command, Query File Test listens to port 5005 and waits for a debugger to be attached.

$ mvn -Pitests -pl itests/qtest -Dmaven.surefire.debug test -Dtest=TestMiniLlapLocalCliDriver -Dqfile=alter1.q