# 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. # # Client tests for Query Event Hooks import os import pytest import tempfile from tests.common.custom_cluster_test_suite import CustomClusterTestSuite class TestHooks(CustomClusterTestSuite): """ Tests for FE QueryEventHook invocations. """ DUMMY_HOOK = "org.apache.impala.testutil.DummyQueryEventHook" MINIDUMP_PATH = tempfile.mkdtemp() @pytest.mark.execute_serially @CustomClusterTestSuite.with_args( impala_log_dir=tempfile.mkdtemp(prefix="test_hooks_", dir=os.getenv("LOG_DIR")), impalad_args="--query_event_hook_classes={0} " "--minidump_path={1} -logbuflevel=-1" .format(DUMMY_HOOK, MINIDUMP_PATH), catalogd_args="--minidump_path={0}".format(MINIDUMP_PATH)) def test_query_event_hooks_execute(self, unique_database): """ Tests that the post query execution hook actually executes by using a dummy hook implementation. """ # Dummy hook should log something (See org.apache.impala.testutil.DummyQueryEventHook) self.assert_impalad_log_contains("INFO", "{0}.onImpalaStartup".format(self.DUMMY_HOOK), expected_count=-1) # Run a test query that triggers a lineage event. self.execute_query_expect_success( self.client, "select count(*) from functional.alltypes") # onQueryComplete() is invoked by the lineage logger. self.assert_impalad_log_contains("INFO", "{0}.onQueryComplete".format(self.DUMMY_HOOK), expected_count=-1) class TestHooksStartupFail(CustomClusterTestSuite): """ Tests for failed startup due to bad QueryEventHook startup or registration All test cases in this testsuite are expected to fail cluster startup and will swallow exceptions thrown during setup_method(). """ @classmethod def get_workload(cls): return 'functional-query' @classmethod def setup_class(cls): if cls.exploration_strategy() != 'exhaustive': pytest.skip('runs only in exhaustive') super(TestHooksStartupFail, cls).setup_class() FAILING_HOOK = "org.apache.impala.testutil.AlwaysErrorQueryEventHook" NONEXIST_HOOK = "captain.hook" LOG_DIR1 = tempfile.mkdtemp(prefix="test_hooks_startup_fail_", dir=os.getenv("LOG_DIR")) LOG_DIR2 = tempfile.mkdtemp(prefix="test_hooks_startup_fail_", dir=os.getenv("LOG_DIR")) MINIDUMP_PATH = tempfile.mkdtemp() @pytest.mark.execute_serially @CustomClusterTestSuite.with_args( cluster_size=1, impalad_timeout_s=5, impala_log_dir=LOG_DIR1, impalad_args="--query_event_hook_classes={0} " "--minidump_path={1}" .format(FAILING_HOOK, MINIDUMP_PATH), catalogd_args="--minidump_path={0}".format(MINIDUMP_PATH)) def test_hook_startup_fail(self): """ Tests that exception during QueryEventHook.onImpalaStart will prevent successful daemon startup. """ # Parse log file for expected exception. self.assert_impalad_log_contains("INFO", "Exception during onImpalaStartup from " "QueryEventHook class {0}" .format(self.FAILING_HOOK), expected_count=-1) @pytest.mark.execute_serially @CustomClusterTestSuite.with_args( cluster_size=1, impalad_timeout_s=5, impala_log_dir=LOG_DIR2, impalad_args="--query_event_hook_classes={0} " "--minidump_path={1}" .format(NONEXIST_HOOK, MINIDUMP_PATH), catalogd_args="--minidump_path={0}".format(MINIDUMP_PATH)) def test_hook_instantiation_fail(self): """ Tests that failure to instantiate a QueryEventHook will prevent successful daemon startup. """ # Parse log file for expected exception. self.assert_impalad_log_contains("INFO", "Unable to instantiate query event hook class {0}" .format(self.NONEXIST_HOOK), expected_count=-1) def setup_method(self, method): # Explicitly override CustomClusterTestSuite.setup_method() to # allow it to exception, since this test suite is for cases where # startup fails try: super(TestHooksStartupFail, self).setup_method(method) except Exception: self._stop_impala_cluster() def teardown_method(self, method): # Explicitly override CustomClusterTestSuite.teardown_method() to # allow it to exception, since it relies on setup_method() having # completed successfully try: super(TestHooksStartupFail, self).teardown_method(method) except Exception: self._stop_impala_cluster()