From 1835e746fff775729bd8144b109d8e22bd670eb4 Mon Sep 17 00:00:00 2001 From: Fernando Giorgetti Date: Tue, 10 Apr 2018 17:37:05 -0300 Subject: [PATCH] DISPATCH-154 - Added new tests to validate unresolvable hostname --- tests/CMakeLists.txt | 1 + tests/system_tests_bad_configuration.py | 150 ++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 tests/system_tests_bad_configuration.py diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 939b51f365..2de2aea295 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -109,6 +109,7 @@ foreach(py_test_module system_tests_disallow_link_resumable_link_route system_tests_exchange_bindings system_tests_cmdline_parsing + system_tests_bad_configuration ${SYSTEM_TESTS_HTTP} ) diff --git a/tests/system_tests_bad_configuration.py b/tests/system_tests_bad_configuration.py new file mode 100644 index 0000000000..2af509a2c8 --- /dev/null +++ b/tests/system_tests_bad_configuration.py @@ -0,0 +1,150 @@ +# +# 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. +# + +""" +Ensure router continues to work when configuration has some configurations, +that might cause problems, or caused issues in the past. +For example, unresolvable host names. +""" + +from threading import Timer +import re +from subprocess import PIPE, STDOUT +from system_test import TestCase, Qdrouterd, TIMEOUT, Process + +class RouterTestBadConfiguration(TestCase): + + """ + This test case sets up a router using configurations that are not + well defined, but are not supposed to cause a crash to the router + process. + """ + @classmethod + def setUpClass(cls): + """ + Set up router instance configuration to be used for testing. + :return: + """ + super(RouterTestBadConfiguration, cls).setUpClass() + cls.name = "test-router" + cls.config = Qdrouterd.Config([ + ('router', {'mode': 'standalone', 'id': 'QDR.A'}), + # Define a connector that uses an unresolvable hostname + ('connector', + {'name': 'UnresolvableConn', + 'host': 'unresolvable.host.name', + 'port': 'amqp'}), + ('listener', + {'port': cls.tester.get_port()}), + ]) + + try: + cls.router = cls.tester.qdrouterd(cls.name, cls.config, wait=False) + except OSError: + pass + + def __init__(self, test_method): + TestCase.__init__(self, test_method) + self.error_caught = False + self.timer_delay = 1 + self.max_attempts = 3 + self.attempts_made = 0 + self.schedule_timer() + + def schedule_timer(self): + """ + Schedules a timer triggers wait_for_unresolvable_host after + timer_delay has been elapsed. + :return: + """ + Timer(self.timer_delay, self.wait_for_unresolvable_host).start() + + @classmethod + def tearDownClass(cls): + super(RouterTestBadConfiguration, cls).tearDownClass() + + def address(self): + """ + Returns the address that can be used along with qdmanage + to query the running instance of the dispatch router. + :return: + """ + return self.router.addresses[0] + + def waiting_for_error(self): + """ + Returns True if max_attempts not yet reached and error is still not found. + :return: bool + """ + return not self.error_caught and self.attempts_made < self.max_attempts + + def wait_for_unresolvable_host(self): + """ + Wait for error to show up in the logs based on pre-defined max_attempts + and timer_delay. If error is not caught within max_attempts * timer_delay + then it stops scheduling new attempts. + :return: + """ + with open('../setUpClass/test-router.log', 'r') as router_log: + log_lines = router_log.read().split("\n") + regex = ".*(getaddrinfo|proton:io Name or service not known).*" + errors_caught = [line for line in log_lines if re.match(regex, line)] + + self.error_caught = len(errors_caught) > 0 + + # If condition not yet satisfied and not exhausted max attempts, + # re-schedule the verification. + if self.waiting_for_error(): + self.attempts_made += 1 + self.schedule_timer() + + def setUp(self): + """ + Causes tests to wait till timer has found the expected error or + after it times out. + :return: + """ + # Wait till error is found or timed out waiting for it. + while self.waiting_for_error(): + pass + + def test_unresolvable_host_caught(self): + """ + Validate if the error message stating host is unresolvable is printed + to the router log. + It expects that the error can be caught in the logs. + :return: + """ + self.assertEqual(True, self.error_caught) + + def test_qdmanage_query(self): + """ + Attempts to query the router after the error (or timeout) has occurred. + It expects a successful query response to be returned by the router. + :return: + """ + p = self.popen( + ['qdmanage', '-b', self.address(), 'query', '--type=router', '--timeout', str(TIMEOUT)], + stdin=PIPE, stdout=PIPE, stderr=STDOUT, expect=Process.EXIT_OK) + out = p.communicate()[0] + try: + p.teardown() + except Exception, e: + raise Exception("%s\n%s" % (e, out)) + return out