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.
You have to compile Hive's source codes ahead of time.
$ mvn clean install -Dmaven.javadoc.skip=true -DskipTests -Pitests
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
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;
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
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
| 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 |
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
We extend JUnit by implementing QTestOptionHandlers, which are custom pre-processors and post-processors. This section explains a couple of typical processors.
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;
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();
The Query File Test framework outputs log files in the following paths.
itests/{qtest, qtest-accumulo, qtest-iceberg, qtest-kudu}/target/surefire-reportsfind . -name hive.logNegative 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
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.
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 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
Following are a few rules of thumb that should be followed when adding new test cases in Hive that require the introduction of new query file(s). Of course, these rules should not be applied if they invalidate the purpose of your test to begin with. These are generally helpful in keeping the test queries concise, minimizing the redundancies where possible, and ensuring that cascading failures due to a single test failure do not occur.
src.SELECT query, keep it as simple as possible, and minimize the number of queries to keep overall test time down; avoid repeating scenarios which are already covered by existing tests.SELECT statement, make sure you use the ORDER BY clause to minimize the chances of spurious diffs due to output order differences leading to test failures.