You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by gm...@apache.org on 2018/11/05 14:30:27 UTC
qpid-dispatch git commit: DISPATCH-1170 - Fix for system tests
execution on python3 only machines. This closes #414
Repository: qpid-dispatch
Updated Branches:
refs/heads/master 855011938 -> bdd2aa389
DISPATCH-1170 - Fix for system tests execution on python3 only machines. This closes #414
Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/bdd2aa38
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/bdd2aa38
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/bdd2aa38
Branch: refs/heads/master
Commit: bdd2aa389dc8d5fb035e203cf6270142daeb2604
Parents: 8550119
Author: Fernando Giorgetti <fg...@redhat.com>
Authored: Mon Nov 5 11:16:50 2018 -0200
Committer: Ganesh Murthy <gm...@redhat.com>
Committed: Mon Nov 5 09:29:57 2018 -0500
----------------------------------------------------------------------
CMakeLists.txt | 4 +-
tests/CMakeLists.txt | 8 +-
tests/system_tests_authz_service_plugin.py.in | 208 ++++++++++++++
tests/system_tests_handle_failover.py.in | 309 +++++++++++++++++++++
4 files changed, 523 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/bdd2aa38/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9dc7180..bfe2c4a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -48,10 +48,8 @@ include(FindPythonLibs)
if (PYTHON_VERSION_MAJOR STREQUAL 3)
set(PY_STRING "python3")
- set(PY_UNIT2_STRING "unit2-3")
elseif(PYTHON_VERSION_MAJOR STREQUAL 2)
set(PY_STRING "python")
- set(PY_UNIT2_STRING "unit2")
endif()
# Find python-unittest2
@@ -244,6 +242,8 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run.py.in ${CMAKE_CURRENT_BINARY_DIR}
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run.py.in ${CMAKE_CURRENT_BINARY_DIR}/tests/run.py)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/authservice.py.in ${CMAKE_CURRENT_SOURCE_DIR}/tests/authservice.py)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/failoverserver.py.in ${CMAKE_CURRENT_SOURCE_DIR}/tests/failoverserver.py)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/system_tests_authz_service_plugin.py.in ${CMAKE_CURRENT_SOURCE_DIR}/tests/system_tests_authz_service_plugin.py)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/system_tests_handle_failover.py.in ${CMAKE_CURRENT_SOURCE_DIR}/tests/system_tests_handle_failover.py)
execute_process(COMMAND ${RUN} --sh OUTPUT_FILE config.sh)
if (NOT UNITTEST2_MISSING)
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/bdd2aa38/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index fe99dec..1075c76 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -67,9 +67,9 @@ add_test(unit_tests_size_1 ${TEST_WRAP} -x unit_tests_size 1)
add_test(unit_tests ${TEST_WRAP} -x unit_tests ${CMAKE_CURRENT_SOURCE_DIR}/threads4.conf)
# Unit test python modules
-add_test(router_engine_test ${TEST_WRAP} -x ${PY_UNIT2_STRING} -v router_engine_test)
-add_test(management_test ${TEST_WRAP} -x ${PY_UNIT2_STRING} -v management)
-add_test(router_policy_test ${TEST_WRAP} -x ${PY_UNIT2_STRING} -v router_policy_test)
+add_test(router_engine_test ${TEST_WRAP} -x unit2 -v router_engine_test)
+add_test(management_test ${TEST_WRAP} -x unit2 -v management)
+add_test(router_policy_test ${TEST_WRAP} -x unit2 -v router_policy_test)
if(USE_LIBWEBSOCKETS)
set(SYSTEM_TESTS_HTTP system_tests_http)
@@ -125,7 +125,7 @@ foreach(py_test_module
system_tests_core_client
)
- add_test(${py_test_module} ${TEST_WRAP} -x ${PY_UNIT2_STRING} -v ${py_test_module})
+ add_test(${py_test_module} ${TEST_WRAP} -x unit2 -v ${py_test_module})
list(APPEND SYSTEM_TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${py_test_module}.py)
endforeach()
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/bdd2aa38/tests/system_tests_authz_service_plugin.py.in
----------------------------------------------------------------------
diff --git a/tests/system_tests_authz_service_plugin.py.in b/tests/system_tests_authz_service_plugin.py.in
new file mode 100644
index 0000000..a214df9
--- /dev/null
+++ b/tests/system_tests_authz_service_plugin.py.in
@@ -0,0 +1,208 @@
+#
+# 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 unicode_literals
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+import unittest2 as unittest
+import os, json
+from subprocess import PIPE, Popen, STDOUT
+from system_test import TestCase, Qdrouterd, main_module, DIR, TIMEOUT, Process, SkipIfNeeded
+from proton import Array, Data, Message, SASL, symbol, UNDESCRIBED
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+
+
+class AuthServicePluginAuthzTest(TestCase):
+ @classmethod
+ def addUser(cls, user, password):
+ # Create a sasl database.
+ p = Popen(['saslpasswd2', '-c', '-p', '-f', 'users.sasldb', user],
+ stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
+ result = p.communicate(password)
+ assert p.returncode == 0, "saslpasswd2 exit status %s, output:\n%s" % (p.returncode, result)
+
+ @classmethod
+ def createSaslFiles(cls):
+ cls.addUser('guest', 'guest')
+ cls.addUser('admin', 'admin')
+ # Create a SASL configuration file.
+ with open('tests-mech-SCRAM.conf', 'w') as sasl_conf:
+ sasl_conf.write("""
+mech_list: SCRAM-SHA-1 PLAIN
+""")
+ with open('proton-server.conf', 'w') as sasl_conf:
+ sasl_conf.write("""
+pwcheck_method: auxprop
+auxprop_plugin: sasldb
+sasldb_path: users.sasldb
+mech_list: SCRAM-SHA-1 PLAIN
+""")
+
+
+ @classmethod
+ def setUpClass(cls):
+ """
+ Tests the delegation of sasl auth to an external auth service.
+ """
+ super(AuthServicePluginAuthzTest, cls).setUpClass()
+
+ if not SASL.extended():
+ return
+
+ cls.createSaslFiles()
+
+ cls.auth_service_port = cls.tester.get_port()
+ cls.tester.popen(['/usr/bin/env', '${PY_STRING}', os.path.join(os.path.dirname(os.path.abspath(__file__)), 'authservice.py'), '-a', 'amqps://127.0.0.1:%d' % cls.auth_service_port, '-c', os.getcwd()], expect=Process.RUNNING)
+
+ policy_config_path = os.path.join(DIR, 'policy-authz')
+
+ cls.router_port = cls.tester.get_port()
+ cls.tester.qdrouterd('router', Qdrouterd.Config([
+ ('sslProfile', {'name':'myssl'}),
+ ('policy', {'maxConnections': 2, 'policyDir': policy_config_path, 'enableVhostPolicy': 'true'}),
+ # authService attribute has been deprecated. We are using it here to make sure that we are
+ # still backward compatible.
+ ('authServicePlugin', {'name':'myauth', 'sslProfile':'myssl', 'port': cls.auth_service_port, 'host': '127.0.0.1'}),
+ ('listener', {'host': '0.0.0.0', 'port': cls.router_port, 'role': 'normal', 'saslPlugin':'myauth', 'saslMechanisms':'SCRAM-SHA-1 PLAIN'}),
+ ('router', {'mode': 'standalone', 'id': 'router',
+ 'saslConfigName': 'tests-mech-SCRAM',
+ 'saslConfigPath': os.getcwd()})
+ ])).wait_ready()
+
+ @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test")
+ def test_authorized(self):
+ container = Container()
+ client = ConnectionHandler('foo', 1)
+ container.connect("guest:guest@127.0.0.1:%d" % self.router_port, handler=client)
+ container.run()
+ self.assertEqual(1, client.sent)
+ self.assertEqual(1, client.received)
+ self.assertEqual(0, len(client.errors))
+
+ @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test")
+ def test_unauthorized(self):
+ container = Container()
+ client = ConnectionHandler('bar', 1)
+ container.connect("guest:guest@127.0.0.1:%d" % self.router_port, handler=client)
+ container.run()
+ self.assertEqual(0, client.sent)
+ self.assertEqual(0, client.received)
+ self.assertEqual(2, len(client.errors))
+ self.assertEqual('amqp:unauthorized-access', client.errors[0])
+ self.assertEqual('amqp:unauthorized-access', client.errors[1])
+
+ @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test")
+ def test_wildcard(self):
+ container = Container()
+ client = ConnectionHandler('whatever', 1)
+ container.connect("admin:admin@127.0.0.1:%d" % self.router_port, handler=client)
+ container.run()
+ self.assertEqual(1, client.sent)
+ self.assertEqual(1, client.received)
+ self.assertEqual(0, len(client.errors))
+
+ @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test")
+ def test_dynamic_source_anonymous_sender(self):
+ container = Container()
+ client = DynamicSourceAnonymousSender()
+ container.connect("admin:admin@127.0.0.1:%d" % self.router_port, handler=client)
+ container.run()
+ self.assertEqual('hello', client.message)
+ self.assertEqual(0, len(client.errors))
+
+
+class AuthServicePluginAuthzDeprecatedTest(AuthServicePluginAuthzTest):
+ @classmethod
+ def setUpClass(cls):
+ """
+ Tests the delegation of sasl auth to an external auth service.
+ """
+ super(AuthServicePluginAuthzTest, cls).setUpClass()
+
+ if not SASL.extended():
+ return
+
+ cls.createSaslFiles()
+
+ cls.auth_service_port = cls.tester.get_port()
+ cls.tester.popen(['/usr/bin/env', '${PY_STRING}', os.path.join(os.path.dirname(os.path.abspath(__file__)), 'authservice.py'), '-a', 'amqps://127.0.0.1:%d' % cls.auth_service_port, '-c', os.getcwd()], expect=Process.RUNNING)
+
+ cls.router_port = cls.tester.get_port()
+ cls.tester.qdrouterd('router', Qdrouterd.Config([
+ ('sslProfile', {'name':'myssl'}),
+ # authService and authSslProfile attributea have been deprecated.
+ # We are using it here to make sure that we are backward compatible.
+ ('authServicePlugin', {'name':'myauth', 'authSslProfile':'myssl', 'authService': '127.0.0.1:%d' % cls.auth_service_port}),
+ ('listener', {'host': '0.0.0.0', 'port': cls.router_port, 'role': 'normal', 'saslPlugin':'myauth', 'saslMechanisms':'SCRAM-SHA-1 PLAIN'}),
+ ('router', {'mode': 'standalone', 'id': 'router',
+ 'saslConfigName': 'tests-mech-SCRAM',
+ 'saslConfigPath': os.getcwd()})
+ ])).wait_ready()
+class ConnectionHandler(MessagingHandler):
+ def __init__(self, address, count):
+ super(ConnectionHandler, self).__init__()
+ self.address = address
+ self.count = count
+ self.received = 0
+ self.sent = 0
+ self.errors = []
+
+ def on_message(self, event):
+ self.received += 1
+ if self.received == self.count:
+ event.connection.close()
+
+ def on_sendable(self, event):
+ if self.sent < self.count:
+ self.sent += 1
+ event.sender.send(Message(body='msg-%s' %self.sent))
+
+ def on_link_error(self, event):
+ self.errors.append(event.link.remote_condition.name)
+ event.connection.close()
+
+ def on_connection_opened(self, event):
+ event.container.create_receiver(event.connection, self.address)
+ event.container.create_sender(event.connection, self.address)
+
+class DynamicSourceAnonymousSender(MessagingHandler):
+ def __init__(self):
+ super(DynamicSourceAnonymousSender, self).__init__()
+ self.sender = None
+ self.message = None
+ self.errors = []
+
+ def on_message(self, event):
+ self.message = event.message.body;
+ event.connection.close()
+
+ def on_link_opened(self, event):
+ if event.receiver:
+ self.sender.send(Message(address=event.receiver.remote_source.address, body='hello'))
+
+ def on_connection_opened(self, event):
+ event.container.create_receiver(event.connection, None, dynamic=True)
+ self.sender = event.container.create_sender(event.connection, None)
+
+if __name__ == '__main__':
+ unittest.main(main_module())
+
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/bdd2aa38/tests/system_tests_handle_failover.py.in
----------------------------------------------------------------------
diff --git a/tests/system_tests_handle_failover.py.in b/tests/system_tests_handle_failover.py.in
new file mode 100644
index 0000000..83ac620
--- /dev/null
+++ b/tests/system_tests_handle_failover.py.in
@@ -0,0 +1,309 @@
+#
+# 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 unicode_literals
+from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+
+import os
+from threading import Timer
+import unittest2 as unittest
+import json, re
+from system_test import main_module, TIMEOUT
+from system_test import TestCase, Qdrouterd, Process, TIMEOUT
+from subprocess import PIPE, STDOUT
+
+
+class FailoverTest(TestCase):
+ inter_router_port = None
+
+ @classmethod
+ def router(cls, name, config):
+ config = Qdrouterd.Config(config)
+
+ cls.routers.append(cls.tester.qdrouterd(name, config, wait=True))
+
+ @classmethod
+ def setUpClass(cls):
+ super(FailoverTest, cls).setUpClass()
+
+ cls.routers = []
+
+ cls.inter_router_port = cls.tester.get_port()
+ cls.inter_router_port_1 = cls.tester.get_port()
+ cls.backup_port = cls.tester.get_port()
+ cls.backup_url = 'amqp://0.0.0.0:' + str(cls.backup_port)
+ cls.my_server_port = cls.tester.get_port()
+
+ cls.failover_list = 'amqp://third-host:5671, ' + cls.backup_url
+
+ #
+ # Router A tries to connect to Router B via its connectorToB. Router B responds with an open frame which will
+ # have the failover-server-list as one of its connection properties like the following -
+ # [0x13024d0]:0 <- @open(16) [container-id="Router.A", max-frame-size=16384, channel-max=32767,
+ # idle-time-out=8000, offered-capabilities=:"ANONYMOUS-RELAY",
+ # properties={:product="qpid-dispatch-router", :version="1.0.0",
+ # :"failover-server-list"=[{:"network-host"="some-host", :port="35000"},
+ # {:"network-host"="0.0.0.0", :port="25000"}]}]
+ #
+ # The suite of tests determine if the router receiving this open frame stores it properly and if the
+ # original connection goes down, check that the router is trying to make connections to the failover urls.
+ #
+ FailoverTest.router('B', [
+ ('router', {'mode': 'interior', 'id': 'B'}),
+ ('listener', {'host': '0.0.0.0', 'role': 'inter-router', 'port': cls.inter_router_port,
+ 'failoverUrls': cls.failover_list}),
+ ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port()}),
+ ]
+ )
+
+ FailoverTest.router('A',
+ [
+ ('router', {'mode': 'interior', 'id': 'A'}),
+ ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port()}),
+ ('connector', {'name': 'connectorToB', 'role': 'inter-router',
+ 'port': cls.inter_router_port, 'verifyHostname': 'no'}),
+ ]
+ )
+
+ FailoverTest.router('C', [
+ ('router', {'mode': 'interior', 'id': 'C'}),
+ ('listener', {'host': '0.0.0.0', 'role': 'inter-router', 'port': cls.backup_port}),
+ ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port()}),
+ ]
+ )
+
+ cls.routers[1].wait_router_connected('B')
+
+ def __init__(self, test_method):
+ TestCase.__init__(self, test_method)
+ self.success = False
+ self.timer_delay = 2
+ self.max_attempts = 10
+ self.attempts = 0
+
+ def address(self):
+ return self.routers[1].addresses[0]
+
+ def run_qdmanage(self, cmd, input=None, expect=Process.EXIT_OK, address=None):
+ p = self.popen(
+ ['qdmanage'] + cmd.split(' ') + ['--bus', address or self.address(), '--indent=-1', '--timeout', str(TIMEOUT)],
+ stdin=PIPE, stdout=PIPE, stderr=STDOUT, expect=expect,
+ universal_newlines=True)
+ out = p.communicate(input)[0]
+ try:
+ p.teardown()
+ except Exception as e:
+ raise Exception("%s\n%s" % (e, out))
+ return out
+
+ def run_qdstat(self, args, regexp=None, address=None):
+ p = self.popen(
+ ['qdstat', '--bus', str(address or self.router.addresses[0]), '--timeout', str(TIMEOUT) ] + args,
+ name='qdstat-'+self.id(), stdout=PIPE, expect=None,
+ universal_newlines=True)
+
+ out = p.communicate()[0]
+ assert p.returncode == 0, \
+ "qdstat exit status %s, output:\n%s" % (p.returncode, out)
+ if regexp: assert re.search(regexp, out, re.I), "Can't find '%s' in '%s'" % (regexp, out)
+ return out
+
+ def test_1_connector_has_failover_list(self):
+ """
+ This is the most simple and straightforward case. Router A connects to Router B. Router B sends
+ failover information to Router A.
+ We make a qdmanage connector query to Router A which checks if Router A is storing the failover information
+ received from Router B.The failover list must consist of the original connection info (from the connector)
+ followed by the two items sent by the Router B (stored in cls.failover_list)
+ The 'failoverUrls' is comma separated.
+ """
+ long_type = 'org.apache.qpid.dispatch.connector'
+ query_command = 'QUERY --type=' + long_type
+ output = json.loads(self.run_qdmanage(query_command))
+ expected = "amqp://127.0.0.1:" + str(FailoverTest.inter_router_port) + ", " + FailoverTest.failover_list
+
+ self.assertEqual(expected, output[0]['failoverUrls'])
+
+ def schedule_B_to_C_failover_test(self):
+ if self.attempts < self.max_attempts:
+ if not self.success:
+ Timer(self.timer_delay, self.check_C_connector).start()
+ self.attempts += 1
+
+ def check_C_connector(self):
+ long_type = 'org.apache.qpid.dispatch.connector'
+ query_command = 'QUERY --type=' + long_type
+ output = json.loads(self.run_qdmanage(query_command, address=self.routers[1].addresses[0]))
+
+ expected = FailoverTest.backup_url + ", " + "amqp://127.0.0.1:" + str(FailoverTest.inter_router_port) \
+ + ", " + "amqp://third-host:5671"
+
+ if output[0].get('failoverUrls') == expected:
+ self.success = True
+ else:
+ self.schedule_B_to_C_failover_test()
+
+ def can_terminate(self):
+ if self.attempts == self.max_attempts:
+ return True
+
+ if self.success:
+ return True
+
+ return False
+
+ def test_2_remove_router_B(self):
+ """
+ In this test, we are killing Router B. As a result, Router A should try to connect to Router C.
+ Router C does NOT have a failover list, so the open frame that Router C sends to Router A will not contain
+ the failover-server-list property..Hence the failoverUrls list will remain unchanged except that the order of
+ the URLs would be different.
+ """
+
+ # First make sure there are no inter-router connections on router C
+ outs = self.run_qdstat(['--connections'], address=self.routers[2].addresses[1])
+
+ inter_router = 'inter-router' in outs
+ self.assertFalse(inter_router)
+
+ # Kill the router B
+ FailoverTest.routers[0].teardown()
+
+ # Schedule a test to make sure that the failover url is available
+ # and Router C has an inter-router connection
+ self.schedule_B_to_C_failover_test()
+
+ while not self.can_terminate():
+ pass
+
+ self.assertTrue(self.success)
+
+
+ def schedule_C_to_B_failover_test(self):
+ if self.attempts < self.max_attempts:
+ if not self.success:
+ Timer(self.timer_delay, self.check_B_connector).start()
+ self.attempts += 1
+
+ def check_B_connector(self):
+ # Router A should now try to connect to Router B again since we killed Router C.
+ long_type = 'org.apache.qpid.dispatch.connector'
+ query_command = 'QUERY --type=' + long_type
+ output = json.loads(self.run_qdmanage(query_command, address=self.routers[1].addresses[0]))
+
+ # The order that the URLs appear in the failoverUrls is important. This is the order in which the router
+ # will attempt to make connections in case the existing connection goes down.
+
+ expected = "amqp://127.0.0.1:" + str(FailoverTest.inter_router_port) + ", " + \
+ FailoverTest.failover_list + \
+ ', amqp://127.0.0.1:%d' % FailoverTest.my_server_port
+
+ if output[0].get('failoverUrls') == expected:
+ self.success = True
+ else:
+ self.schedule_C_to_B_failover_test()
+
+ def test_3_reinstate_router_B(self):
+ """
+ In this test, we are restarting Router B and killing Router C. Router A should now try to connect back to
+ Router B since it maintains the original connection info to Router B from the connector config information.
+ Before starting Router B back again, we
+ have a small config change to Router B wherein we are adding a new failover url to the original list.
+ This new failover url
+ points to our own server which will accept connections. This server will actually be used in the next test
+ but this test maskes sure that the new server url also shows up in the failoverUrls list.
+ """
+ FailoverTest.router('B', [
+ ('router', {'mode': 'interior', 'id': 'B'}),
+ ('listener', {'host': '0.0.0.0', 'role': 'inter-router', 'port': FailoverTest.inter_router_port,
+ 'failoverUrls': FailoverTest.failover_list + ', amqp://127.0.0.1:%d' % FailoverTest.my_server_port}),
+ ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': FailoverTest.tester.get_port()}),
+ ])
+
+ FailoverTest.routers[3].wait_ready()
+
+ # Kill the router C.
+ # Now since Router B is up and running, router A should try to re-connect to Router B.
+ # This will prove that the router A is preserving the original connector information specified in its config.
+ FailoverTest.routers[2].teardown()
+
+ self.success = False
+ self.attempts = 0
+
+ # Schedule a test to make sure that the failover url is available
+ self.schedule_C_to_B_failover_test()
+
+ while not self.can_terminate():
+ pass
+
+ self.assertTrue(self.success)
+
+ def check_A_connector(self):
+ # Router A should now try to connect to Router B again since we killed Router C.
+ long_type = 'org.apache.qpid.dispatch.connector'
+ query_command = 'QUERY --type=' + long_type
+ output = json.loads(self.run_qdmanage(query_command, address=self.routers[1].addresses[0]))
+
+ # The order that the URLs appear in the failoverUrls is important. This is the order in which the router
+ # will attempt to make connections in case the existing connection goes down.
+ expected = 'amqp://127.0.0.1:%d' % FailoverTest.my_server_port + ", " + "amqp://127.0.0.1:" + str(FailoverTest.inter_router_port)
+
+ if output[0].get('failoverUrls') == expected:
+ self.success = True
+ else:
+ self.schedule_B_to_my_server_failover_test()
+
+ def schedule_B_to_my_server_failover_test(self):
+ if self.attempts < self.max_attempts:
+ if not self.success:
+ Timer(self.timer_delay, self.check_A_connector).start()
+ self.attempts += 1
+
+ def test_4_remove_router_B_connect_to_my_server(self):
+ """
+ This test kills Router B again and makes sure that Router A now connects to our custom server that
+ accepts connections. This custom server intentionally sends an empty list for failover-server-list
+ Router A must look at this empty list and wipe out all failover information except the original connector information
+ and the current connection info.
+ """
+
+
+ # Start MyServer
+ proc = FailoverTest.tester.popen(
+ ['/usr/bin/env', '${PY_STRING}', os.path.join(os.path.dirname(os.path.abspath(__file__)), 'failoverserver.py'), '-a',
+ 'amqp://127.0.0.1:%d' % FailoverTest.my_server_port], expect=Process.RUNNING)
+
+ # Kill the router B again
+ FailoverTest.routers[3].teardown()
+
+ self.success = False
+ self.attempts = 0
+
+ self.schedule_B_to_my_server_failover_test()
+
+ while not self.can_terminate():
+ pass
+
+ self.assertTrue(self.success)
+
+
+if __name__ == '__main__':
+ unittest.main(main_module())
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org