| # 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. |
| |
| from __future__ import absolute_import, division, print_function |
| import os |
| import ssl |
| import sys |
| import time |
| |
| import pytest |
| |
| # This import is the actual ImpalaShell class from impala_shell.py. |
| # We rename it to ImpalaShellClass here because we later import another |
| # class called ImpalaShell from tests/shell/util.py, and we don't want |
| # to mask it. |
| from impala_shell.impala_shell import ImpalaShell as ImpalaShellClass |
| from tests.common.custom_cluster_test_suite import CustomClusterTestSuite |
| from tests.common.environ import IS_REDHAT_DERIVATIVE |
| from tests.common.test_dimensions import create_client_protocol_dimension |
| from tests.common.test_vector import ImpalaTestVector |
| from tests.shell.util import ImpalaShell |
| |
| REQUIRED_MIN_OPENSSL_VERSION = 0x10001000 |
| # Python supports TLSv1.2 from 2.7.9 officially but on Red Hat/CentOS Python2.7.5 |
| # with newer python-libs (eg python-libs-2.7.5-77) supports TLSv1.2 already |
| if IS_REDHAT_DERIVATIVE: |
| REQUIRED_MIN_PYTHON_VERSION_FOR_TLSV12 = (2, 7, 5) |
| else: |
| REQUIRED_MIN_PYTHON_VERSION_FOR_TLSV12 = (2, 7, 9) |
| _openssl_version_number = getattr(ssl, "OPENSSL_VERSION_NUMBER", None) |
| if _openssl_version_number is None: |
| SKIP_SSL_MSG = "Legacy OpenSSL module detected" |
| elif _openssl_version_number < REQUIRED_MIN_OPENSSL_VERSION: |
| SKIP_SSL_MSG = "Only have OpenSSL version %X, but test requires %X" % ( |
| ssl.OPENSSL_VERSION_NUMBER, REQUIRED_MIN_OPENSSL_VERSION) |
| else: |
| SKIP_SSL_MSG = None |
| CERT_DIR = "%s/be/src/testutil" % os.environ['IMPALA_HOME'] |
| |
| SSL_ARGS = ("--ssl_client_ca_certificate=%s/server-cert.pem " |
| "--ssl_server_certificate=%s/server-cert.pem " |
| "--ssl_private_key=%s/server-key.pem " |
| "--hostname=localhost " # Required to match hostname in certificate |
| % (CERT_DIR, CERT_DIR, CERT_DIR)) |
| |
| # IMPALA-12114 was an issue that occurred when the number of idle polls exceeded a limit |
| # and lead to disconnection. This uses a very short poll period to make these tests |
| # do more polls and verify the fix for this issue. |
| IDLE_ARGS = " --idle_client_poll_period_s=1 -v=2" |
| |
| |
| class TestThriftSocket(CustomClusterTestSuite): |
| """ Check if thrift timeout errors are detected properly """ |
| |
| @classmethod |
| def setup_class(cls): |
| if sys.version_info < REQUIRED_MIN_PYTHON_VERSION_FOR_TLSV12: |
| pytest.skip("Python version does not support tls 1.2") |
| super(TestThriftSocket, cls).setup_class() |
| |
| @pytest.mark.execute_serially |
| @CustomClusterTestSuite.with_args( |
| impalad_args=IDLE_ARGS, cluster_size=1, disable_log_buffering=True) |
| def test_peek_timeout_no_ssl(self): |
| # Iterate over test vector within test function to avoid restarting cluster. |
| for protocol_dim in create_client_protocol_dimension(): |
| for vector in [ImpalaTestVector([protocol_dim])]: |
| shell_args = ["-Q", "idle_session_timeout=1800"] |
| # This uses a longer idle time to verify IMPALA-12114, see comment above. |
| self._run_idle_shell(vector, shell_args, 12) |
| self.assert_impalad_log_contains('INFO', |
| r'Socket read or peek timeout encountered.*THRIFT_EAGAIN \(timed out\)', |
| expected_count=-1) |
| |
| @pytest.mark.execute_serially |
| @CustomClusterTestSuite.with_args(statestored_args=SSL_ARGS, |
| catalogd_args=SSL_ARGS, |
| impalad_args=(SSL_ARGS + IDLE_ARGS), |
| cluster_size=1, |
| disable_log_buffering=True) |
| def test_peek_timeout_ssl(self): |
| # Iterate over test vector within test function to avoid restarting cluster. |
| for protocol_dim in create_client_protocol_dimension(): |
| for vector in [ImpalaTestVector([protocol_dim])]: |
| shell_args = ["-Q", "idle_session_timeout=1800", "--ssl"] |
| # This uses a longer idle time to verify IMPALA-12114, see comment above. |
| self._run_idle_shell(vector, shell_args, 12) |
| self.assert_impalad_log_contains('INFO', |
| r'Socket read or peek timeout encountered.*THRIFT_POLL \(timed out\)', |
| expected_count=-1) |
| |
| def _run_idle_shell(self, vector, args, idle_time): |
| p = ImpalaShell(vector, args) |
| p.send_cmd("USE functional") |
| # Running different statements before and after idle allows for more |
| # precise asserts that can distinguish output from before vs after. |
| p.send_cmd("SHOW DATABASES") |
| time.sleep(idle_time) |
| p.send_cmd("SHOW TABLES") |
| |
| result = p.get_result() |
| # Output from before the idle period |
| assert "functional_parquet" in result.stdout, result.stdout |
| # Output from after the idle period |
| assert "alltypesaggmultifilesnopart" in result.stdout, result.stdout |
| # Impala shell reconnects automatically, so we need to be sure that |
| # it didn't lose the connection. |
| assert ImpalaShellClass.CONNECTION_LOST_MESSAGE not in result.stderr, result.stderr |