| /* |
| * 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.service.cli.session; |
| |
| import org.apache.hadoop.hive.conf.HiveConf; |
| import org.apache.hadoop.hive.ql.QueryDisplay; |
| import org.apache.hadoop.hive.ql.QueryInfo; |
| import org.apache.hadoop.hive.ql.exec.Task; |
| import org.apache.hadoop.hive.ql.exec.TaskResult; |
| import org.apache.hadoop.hive.ql.log.PerfLogger; |
| import org.apache.hadoop.hive.ql.plan.api.StageType; |
| import org.apache.hadoop.hive.ql.session.SessionState; |
| import org.apache.hive.service.cli.OperationHandle; |
| import org.apache.hive.service.cli.SessionHandle; |
| import org.apache.hive.service.rpc.thrift.TProtocolVersion; |
| import org.apache.hive.tmpl.QueryProfileTmpl; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import static org.junit.Assert.assertEquals; |
| |
| import java.io.StringWriter; |
| import java.util.HashMap; |
| import java.util.List; |
| |
| /** |
| * Test QueryDisplay and its consumers like WebUI. |
| */ |
| public class TestQueryDisplay { |
| private HiveConf conf; |
| private SessionManager sessionManager; |
| |
| |
| @Before |
| public void setup() { |
| conf = new HiveConf(); |
| conf.set("hive.support.concurrency", "false"); |
| |
| sessionManager = new SessionManager(null, true); |
| sessionManager.init(conf); |
| sessionManager.start(); |
| } |
| |
| /** |
| * Test if query display captures information on current/historic SQL operations. |
| */ |
| @Test |
| public void testQueryDisplay() throws Exception { |
| HiveSession session = sessionManager |
| .createSession(new SessionHandle(TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V8), |
| TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V8, "testuser", "", "", |
| new HashMap<String, String>(), false, ""); |
| session.getSessionState().setIsHiveServerQuery(false); |
| SessionState.start(conf); |
| OperationHandle opHandle1 = session.executeStatement("show databases", null); |
| SessionState.start(conf); |
| OperationHandle opHandle2 = session.executeStatement("show tables", null); |
| |
| List<QueryInfo> liveSqlOperations, historicSqlOperations; |
| liveSqlOperations = sessionManager.getOperationManager().getLiveQueryInfos(); |
| historicSqlOperations = sessionManager.getOperationManager().getHistoricalQueryInfos(); |
| Assert.assertEquals(liveSqlOperations.size(), 2); |
| Assert.assertEquals(historicSqlOperations.size(), 0); |
| verifyDDL(liveSqlOperations.get(0), "show databases", opHandle1.getHandleIdentifier().toString(), false); |
| verifyDDL(liveSqlOperations.get(1), "show tables", opHandle2.getHandleIdentifier().toString(), false); |
| |
| session.closeOperation(opHandle1); |
| liveSqlOperations = sessionManager.getOperationManager().getLiveQueryInfos(); |
| historicSqlOperations = sessionManager.getOperationManager().getHistoricalQueryInfos(); |
| Assert.assertEquals(liveSqlOperations.size(), 1); |
| Assert.assertEquals(historicSqlOperations.size(), 1); |
| verifyDDL(historicSqlOperations.get(0), "show databases", opHandle1.getHandleIdentifier().toString(), true); |
| verifyDDL(liveSqlOperations.get(0), "show tables", opHandle2.getHandleIdentifier().toString(), false); |
| |
| session.closeOperation(opHandle2); |
| liveSqlOperations = sessionManager.getOperationManager().getLiveQueryInfos(); |
| historicSqlOperations = sessionManager.getOperationManager().getHistoricalQueryInfos(); |
| Assert.assertEquals(liveSqlOperations.size(), 0); |
| Assert.assertEquals(historicSqlOperations.size(), 2); |
| verifyDDL(historicSqlOperations.get(1), "show databases", opHandle1.getHandleIdentifier().toString(), true); |
| verifyDDL(historicSqlOperations.get(0), "show tables", opHandle2.getHandleIdentifier().toString(), true); |
| |
| session.close(); |
| } |
| |
| /** |
| * Test if webui captures information on current/historic SQL operations. |
| */ |
| @Test |
| public void testWebUI() throws Exception { |
| HiveSession session = sessionManager |
| .createSession(new SessionHandle(TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V8), |
| TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V8, "testuser", "", "", |
| new HashMap<String, String>(), false, ""); |
| |
| SessionState.start(conf); |
| OperationHandle opHandle1 = session.executeStatement("show databases", null); |
| SessionState.start(conf); |
| OperationHandle opHandle2 = session.executeStatement("show tables", null); |
| |
| verifyDDLHtml("show databases", opHandle1.getHandleIdentifier().toString()); |
| verifyDDLHtml("show tables", opHandle2.getHandleIdentifier().toString()); |
| |
| session.closeOperation(opHandle1); |
| session.closeOperation(opHandle2); |
| |
| verifyDDLHtml("show databases", opHandle1.getHandleIdentifier().toString()); |
| verifyDDLHtml("show tables", opHandle2.getHandleIdentifier().toString()); |
| |
| session.close(); |
| } |
| |
| /** |
| * Test for the HiveConf option HIVE_SERVER2_WEBUI_EXPLAIN_OUTPUT. |
| */ |
| @Test |
| public void checkWebuiExplainOutput() throws Exception { |
| |
| //check cases when HIVE_SERVER2_WEBUI_EXPLAIN_OUTPUT is set and not set |
| boolean[] webuiExplainConfValues = new boolean[]{true, false}; |
| |
| for (boolean confValue : webuiExplainConfValues) { |
| conf.setBoolVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_EXPLAIN_OUTPUT, confValue); |
| HiveSession session = sessionManager |
| .createSession(new SessionHandle(TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V8), |
| TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V8, "testuser", "", "", |
| new HashMap<String, String>(), false, ""); |
| SessionState.start(conf); |
| |
| OperationHandle opHandle = session.executeStatement("show tables", null); |
| session.closeOperation(opHandle); |
| //STAGE PLANS is something which will be shown as part of EXPLAIN query |
| verifyDDLHtml("STAGE PLANS", opHandle.getHandleIdentifier().toString(), confValue); |
| //Check that the following message is not shown when this option is set |
| verifyDDLHtml( |
| "Set configuration hive.server2.webui.explain.output to true to view future query plans", |
| opHandle.getHandleIdentifier().toString(), !confValue); |
| session.close(); |
| } |
| } |
| |
| /** |
| * Test for the HiveConf options HIVE_SERVER2_WEBUI_SHOW_GRAPH, |
| * HIVE_SERVER2_WEBUI_MAX_GRAPH_SIZE. |
| */ |
| @Test |
| public void checkWebuiShowGraph() throws Exception { |
| // WebUI-related boolean confs must be set before build, since the implementation of |
| // QueryProfileTmpl.jamon depends on them. |
| // They depend on HIVE_SERVER2_WEBUI_EXPLAIN_OUTPUT being set to true. |
| conf.setBoolVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_EXPLAIN_OUTPUT, true); |
| conf.setBoolVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_SHOW_GRAPH, true); |
| |
| HiveSession session = sessionManager |
| .createSession(new SessionHandle(TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V8), |
| TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V8, "testuser", "", "", |
| new HashMap<String, String>(), false, ""); |
| SessionState.start(conf); |
| |
| session.getSessionConf() |
| .setIntVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_MAX_GRAPH_SIZE, 0); |
| testGraphDDL(session, true); |
| session.getSessionConf() |
| .setIntVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_MAX_GRAPH_SIZE, 40); |
| testGraphDDL(session, false); |
| |
| session.close(); |
| resetConfToDefaults(); |
| } |
| |
| private void testGraphDDL(HiveSession session, boolean exceedMaxGraphSize) throws Exception { |
| OperationHandle opHandleGraph = session.executeStatement("show tables", null); |
| session.closeOperation(opHandleGraph); |
| |
| // Check for a query plan. If the graph size exceeds the max allowed, none should appear. |
| verifyDDLHtml("Query information not available.", |
| opHandleGraph.getHandleIdentifier().toString(), exceedMaxGraphSize); |
| verifyDDLHtml("STAGE DEPENDENCIES", |
| opHandleGraph.getHandleIdentifier().toString(), !exceedMaxGraphSize); |
| // Check that if plan Json is there, it is not empty |
| verifyDDLHtml("jsonPlan = {}", opHandleGraph.getHandleIdentifier().toString(), false); |
| } |
| |
| /** |
| * Test for the HiveConf option HIVE_SERVER2_WEBUI_SHOW_STATS, which is available for MapReduce |
| * jobs only. |
| */ |
| @Test |
| public void checkWebUIShowStats() throws Exception { |
| // WebUI-related boolean confs must be set before build. HIVE_SERVER2_WEBUI_SHOW_STATS depends |
| // on HIVE_SERVER2_WEBUI_EXPLAIN_OUTPUT and HIVE_SERVER2_WEBUI_SHOW_GRAPH being set to true. |
| conf.setVar(HiveConf.ConfVars.HIVE_EXECUTION_ENGINE, "mr"); |
| conf.setBoolVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_EXPLAIN_OUTPUT, true); |
| conf.setBoolVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_SHOW_GRAPH, true); |
| conf.setIntVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_MAX_GRAPH_SIZE, 40); |
| conf.setBoolVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_SHOW_STATS, true); |
| |
| HiveSession session = sessionManager |
| .createSession(new SessionHandle(TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V8), |
| TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V8, "testuser", "", "", |
| new HashMap<String, String>(), false, ""); |
| SessionState.start(conf); |
| |
| OperationHandle opHandleSetup = |
| session.executeStatement("CREATE TABLE statsTable (i int)", null); |
| session.closeOperation(opHandleSetup); |
| OperationHandle opHandleMrQuery = |
| session.executeStatement("INSERT INTO statsTable VALUES (0)", null); |
| session.closeOperation(opHandleMrQuery); |
| |
| // INSERT queries include a MapReduce task. |
| verifyDDLHtml("Counters", opHandleMrQuery.getHandleIdentifier().toString(), true); |
| |
| session.close(); |
| resetConfToDefaults(); |
| } |
| |
| private void resetConfToDefaults() { |
| conf.setBoolVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_EXPLAIN_OUTPUT, false); |
| conf.setBoolVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_SHOW_GRAPH, false); |
| conf.setBoolVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_SHOW_STATS, false); |
| conf.setIntVar(HiveConf.ConfVars.HIVE_SERVER2_WEBUI_MAX_GRAPH_SIZE, 25); |
| } |
| |
| private void verifyDDL(QueryInfo queryInfo, String stmt, String handle, boolean finished) { |
| |
| Assert.assertEquals(queryInfo.getUserName(), "testuser"); |
| Assert.assertEquals(queryInfo.getExecutionEngine(), "mr"); |
| Assert.assertEquals(queryInfo.getOperationId(), handle); |
| Assert.assertTrue(queryInfo.getBeginTime() > 0 && queryInfo.getBeginTime() <= System.currentTimeMillis()); |
| |
| if (finished) { |
| Assert.assertTrue( |
| queryInfo.getEndTime() > 0 && queryInfo.getEndTime() >= queryInfo.getBeginTime() |
| && queryInfo.getEndTime() <= System.currentTimeMillis()); |
| Assert.assertTrue(queryInfo.getRuntime() > 0); |
| } else { |
| Assert.assertNull(queryInfo.getEndTime()); |
| //For runtime, query may have finished. |
| } |
| |
| QueryDisplay qDisplay1 = queryInfo.getQueryDisplay(); |
| Assert.assertNotNull(qDisplay1); |
| Assert.assertEquals(qDisplay1.getQueryString(), stmt); |
| Assert.assertNotNull(qDisplay1.getExplainPlan()); |
| Assert.assertNull(qDisplay1.getErrorMessage()); |
| |
| Assert.assertTrue(qDisplay1.getHmsTimings(QueryDisplay.Phase.COMPILATION).size() > 0); |
| Assert.assertTrue(qDisplay1.getHmsTimings(QueryDisplay.Phase.EXECUTION).size() > 0); |
| |
| Assert.assertTrue(qDisplay1.getPerfLogStarts(QueryDisplay.Phase.COMPILATION).size() > 0); |
| Assert.assertTrue(qDisplay1.getPerfLogEnds(QueryDisplay.Phase.COMPILATION).size() > 0); |
| |
| Assert.assertTrue(qDisplay1.getPerfLogStarts(QueryDisplay.Phase.COMPILATION).size() > 0); |
| Assert.assertTrue(qDisplay1.getPerfLogEnds(QueryDisplay.Phase.COMPILATION).size() > 0); |
| |
| Assert.assertTrue(qDisplay1.getPerfLogStarts(QueryDisplay.Phase.COMPILATION).containsKey(PerfLogger.COMPILE)); |
| Assert.assertFalse(qDisplay1.getPerfLogStarts(QueryDisplay.Phase.EXECUTION).containsKey(PerfLogger.COMPILE)); |
| Assert.assertTrue(qDisplay1.getPerfLogStarts(QueryDisplay.Phase.EXECUTION).containsKey(PerfLogger.DRIVER_EXECUTE)); |
| Assert.assertFalse(qDisplay1.getPerfLogStarts(QueryDisplay.Phase.COMPILATION) |
| .containsKey(PerfLogger.DRIVER_EXECUTE)); |
| |
| Assert.assertEquals(qDisplay1.getTaskDisplays().size(), 1); |
| QueryDisplay.TaskDisplay tInfo1 = qDisplay1.getTaskDisplays().get(0); |
| Assert.assertEquals(tInfo1.getTaskId(), "Stage-0"); |
| Assert.assertEquals(tInfo1.getTaskType(), StageType.DDL); |
| Assert.assertTrue(tInfo1.getBeginTime() > 0 && tInfo1.getBeginTime() <= System.currentTimeMillis()); |
| Assert.assertTrue(tInfo1.getEndTime() > 0 && tInfo1.getEndTime() >= tInfo1.getBeginTime() |
| && tInfo1.getEndTime() <= System.currentTimeMillis()); |
| Assert.assertEquals(tInfo1.getStatus(), "Success, ReturnVal 0"); |
| } |
| |
| /** |
| * Sanity check if basic information is delivered in this html. Let's not go too crazy and |
| * assert each element, to make it easier to add UI improvements. |
| */ |
| private void verifyDDLHtml(String stmt, String opHandle) throws Exception { |
| verifyDDLHtml(stmt, opHandle, true); |
| } |
| |
| private void verifyDDLHtml(String stmt, String opHandle, boolean assertCondition) throws Exception { |
| StringWriter sw = new StringWriter(); |
| QueryInfo queryInfo = sessionManager.getOperationManager().getQueryInfo(opHandle); |
| HiveConf hiveConf = sessionManager.getOperationManager().getHiveConf(); |
| new QueryProfileTmpl().render(sw, queryInfo, hiveConf); |
| String html = sw.toString(); |
| Assert.assertEquals(assertCondition, html.contains(stmt)); |
| |
| Assert.assertTrue(html.contains("testuser")); |
| } |
| |
| static class MyTask extends Task<Integer> { |
| |
| public MyTask() { |
| id = "x"; |
| } |
| |
| /** |
| * |
| */ |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public String getName() { |
| return "my"; |
| |
| } |
| |
| @Override |
| public int execute() { |
| return 0; |
| } |
| |
| @Override |
| public StageType getType() { |
| return StageType.ATLAS_DUMP; |
| |
| } |
| |
| } |
| |
| @Test |
| public void testJSONSerialization() throws Exception { |
| QueryDisplay qd = new QueryDisplay(); |
| qd.setErrorMessage("asd"); |
| qd.setTaskResult("a", new TaskResult()); |
| qd.setExplainPlan("explainPlan"); |
| qd.setQueryStr("qstr"); |
| Task<?> tTask = new MyTask(); |
| qd.updateTaskStatus(tTask); |
| tTask.setStarted(); |
| qd.updateTaskStatus(tTask); |
| tTask.setDone(); |
| qd.updateTaskStatus(tTask); |
| |
| Long ee = qd.getTaskDisplays().get(0).getElapsedTime(); |
| System.out.println(ee); |
| String json = QueryDisplay.OBJECT_MAPPER.writeValueAsString(qd); |
| QueryDisplay n = QueryDisplay.OBJECT_MAPPER.readValue(json, QueryDisplay.class); |
| |
| assertEquals(qd.getQueryString(), n.getQueryString()); |
| assertEquals(qd.getExplainPlan(), n.getExplainPlan()); |
| assertEquals(qd.getErrorMessage(), n.getErrorMessage()); |
| assertEquals(qd.getTaskDisplays().size(), n.getTaskDisplays().size()); |
| assertEquals(qd.getTaskDisplays().get(0).taskState, n.getTaskDisplays().get(0).taskState); |
| |
| } |
| |
| } |