def test_procedures(self): """Test the procedure interface from the service perspective. """ packet = self.proxy.event.wait_for_procedures( ["e8ca0abe-cfdf-4699-a07d-8cb481f4670b"]) result = _xmlrpc._decode(packet) self.assertTrue(str(result.error).find("was not found") >= 0)
def test_xmlrpc_execute(self): "Test XML-RPC encoding and decoding functions." cmd = _xmlrpc._CommandExecuteAndEncode(NewRemoteCommand()) result1 = CommandResult(None) result1.append_result(self.rset) packet = cmd() self.assertEqual( packet, [ _xmlrpc.FORMAT_VERSION, str(FABRIC_UUID), utils.TTL, '', # No error [ # One result set with one row { 'info': { 'names': ['foo'] }, 'rows': [ ("executed", ), ] } ] ]) result2 = _xmlrpc._decode(packet)
def check_xmlrpc_command_result(self, packet, is_syncronous=True, has_error=False, returns=None): """Check that a packet from a procedure execution is sane. This check that the first command result set, which contain result of execution, is sane. """ check = re.compile('\w{8}(-\w{4}){3}-\w{12}') result = _xmlrpc._decode(packet) self.assertEqual(bool(result.error), has_error, str(result)) # If the procedure did not have an error, first result set, # first row, first column contain UUID of procedure. Just # check that it looks like a UUID. if not has_error: self.assertNotEqual(check.match(result.results[0][0][0]), None) # If the call was synchronous and succeeded, check that there # is at least 2 result sets and that the second result set # contain more than zero jobs. if is_syncronous and not has_error: self.assertTrue(len(result.results) > 1, str(result)) self.assertNotEqual(result.results[1].rowcount, 0, "had %d result sets" % len(result.results)) if not has_error and returns is not None: self.assertTrue(len(result.results) > 1, str(result)) self.assertEqual(result.results[0].rowcount, 1, str(result)) self.assertEqual(result.results[0][0][3], returns)
def test_trigger(self): """Test the trigger interface from the service perspective. """ promoted = [None] def _another_my_event(param, ignored): """Decorator or Inner function. """ promoted[0] = param _events.Handler().register(_NEW_SERVER_PROMOTED, _another_my_event) packet = self.proxy.event.trigger( "_NEW_SERVER_PROMOTED", ["lock_a", "lock_b"], ["my.example.com", ""], ) result = _xmlrpc._decode(packet) self.assertTrue(len(result.results) > 0) self.assertEqual(result.results[0].rowcount, 2) jobs = [str(row[0]) for row in result.results[0]] try: self.proxy.event.wait_for_procedures(jobs) self.assertEqual(promoted[0], "my.example.com") except Exception as error: if str(error).find("was not found") == -1: raise _events.Handler().unregister(_NEW_SERVER_PROMOTED, _another_my_event)
def test_add_slave(self): """Test whether some servers are made slaves or not. """ # Prepare group and servers self.proxy.group.create("group", "Testing group...") address_0 = tests.utils.MySQLInstances().get_address(0) address_1 = tests.utils.MySQLInstances().get_address(1) address_2 = tests.utils.MySQLInstances().get_address(2) status_uuid = self.proxy.server.lookup_uuid(address_0) uuid_0 = status_uuid[2] status_uuid = self.proxy.server.lookup_uuid(address_1) uuid_1 = status_uuid[2] status_uuid = self.proxy.server.lookup_uuid(address_2) uuid_2 = status_uuid[2] status = self.proxy.group.add("group", address_0) self.check_xmlrpc_command_result(status, False) status = self.proxy.group.promote("group") self.check_xmlrpc_command_result(status, False) # Add servers and check that they are made slaves. self.proxy.group.add("group", address_1) self.proxy.group.add("group", address_2) status = self.proxy.group.lookup_servers("group") result = _xmlrpc._decode(status) for row in result.results[0]: info = dict(zip([c.name for c in result.results[0].columns], row)) self.assertEqual(info['weight'], 1.0) if info['address'] == address_0: self.assertEqual(info['status'], _server.MySQLServer.PRIMARY) self.assertEqual(info['mode'], _server.MySQLServer.READ_WRITE) else: self.assertEqual(info['status'], _server.MySQLServer.SECONDARY) self.assertEqual(info['mode'], _server.MySQLServer.READ_ONLY)
def check_xmlrpc_command_result(self, packet, has_error, error_message=None, is_syncronous=True): "Check that a packet from a procedure execution is sane." result = _xmlrpc._decode(packet) if has_error: message = "No error but error expected" else: message = "Error: %s" % result.error self.assertEqual(bool(result.error), has_error, message) # If the procedure had an error, check the error message provided # it was requested to do so, i.e error_message is not None. if has_error and error_message: self.assertEqual(result.error, error_message) # If the procedure did not have an error, first result set, # first row, first column contain UUID of procedure. Just # check that it looks like a UUID. if not has_error: self.assertNotEqual(self.uuid_cre.match(result.results[0][0][0]), None, str(result)) # If the call was synchronous and succeeded, check that there # is at least 2 result sets and that the second result set # contain more than zero jobs. if is_syncronous and not has_error: self.assertTrue(len(result.results) > 1, str(result)) self.assertNotEqual(result.results[1].rowcount, 0, "had %d result sets" % len(result.results))
def test_lookup_servers(self): """Test searching for servers by calling group.lookup_servers(). """ # Prepare group and servers self.proxy.group.create("group", "Testing group...") address_0 = tests.utils.MySQLInstances().get_address(0) address_1 = tests.utils.MySQLInstances().get_address(1) address_2 = tests.utils.MySQLInstances().get_address(2) status = self.proxy.group.add("group", address_0) self.check_xmlrpc_command_result(status, False) status = self.proxy.group.add("group", address_1) self.check_xmlrpc_command_result(status, False) status = self.proxy.group.add("group", address_2) self.check_xmlrpc_command_result(status, False) status_uuid = self.proxy.server.lookup_uuid(address_1) server_1 = _server.MySQLServer.fetch(status_uuid[2]) # Fetch all servers in a group and check the number of server. status = self.proxy.group.lookup_servers("group") result = _xmlrpc._decode(status) self.assertNotEqual(len(result.results), 0, str(result)) self.assertEqual(result.results[0].rowcount, 3, str(result)) # # It it not possible to specify only some of the optional # parameters. For that reason, this part of the test is # skipped as it requires to set the status without setting # the uuid parameter. # Note this is not possible though as the method has the #following signature: # lookup_servers(self, group_id, uuid=None, status=None, ...) # return # Fetch all running servers in a group. server = self.proxy.group.lookup_servers("group", _server.MySQLServer.SECONDARY) self.assertEqual(len(server[2]), 3) # Fetch all offline servers in a group. server_1.status = _server.MySQLServer.FAULTY server = self.proxy.group.lookup_servers("group", _server.MySQLServer.FAULTY) self.assertEqual(len(server[2]), 1) # Fetch all running servers in a group. server = self.proxy.group.lookup_servers("group", _server.MySQLServer.SECONDARY) self.assertEqual(len(server[2]), 2) # Fetch all servers in a group. server = self.proxy.group.lookup_servers("group") self.assertEqual(len(server[2]), 3) # Try to fetch servers with a non-existing status. server = self.proxy.group.lookup_servers("group", 10) self.assertEqual(server[0], False) self.assertNotEqual(server[1], "") self.assertEqual(server[2], True)
def test_xmlrpc_encoding(self): "Test the XML-RPC encoder and decoder." results = [ CommandResult(None), ] for result in results: self.assertEqual(str(result), str(_xmlrpc._decode(_xmlrpc._encode(result))))
def check_xmlrpc_get_uuid(self, packet, has_error): result = _xmlrpc._decode(packet) # If the procedure did not have an error, first result set, # first row, first column contain UUID of server. Just # check that it looks like a UUID. if not has_error: self.assertNotEqual(self.uuid_cre.match(result.results[0][0][0]), None) return result.results[0][0][0]
def test_statistics_group(self): """Test statistics on a group. """ address_1 = tests.utils.MySQLInstances().get_address(0) address_2 = tests.utils.MySQLInstances().get_address(1) # Check statistics on a non-existent group. packet = self.proxy.statistics.group("non-existent") result = _xmlrpc._decode(packet) self.assertEqual(len(result.results), 1) self.assertEqual(result.results[0].rowcount, 0) # Check statistics on group_id_1 after a promotion. self.proxy.group.create("group_id_1") self.proxy.group.add("group_id_1", address_1) self.proxy.group.promote("group_id_1") packet = self.proxy.statistics.group() self.check_xmlrpc_simple(packet, { 'group_id': 'group_id_1', 'call_count': 1, 'call_abort': 0, }, rowcount=1) # Check statistics on group_id_1 after a demotion. self.proxy.group.demote("group_id_1") res = self.proxy.statistics.group("group_id_1") self.check_xmlrpc_simple(res, { 'group_id': 'group_id_1', 'call_count': 1, 'call_abort': 1, }, rowcount=1) # Check statistics on group_id_2 after a promotion. self.proxy.group.create("group_id_2") self.proxy.group.add("group_id_2", address_2) self.proxy.group.promote("group_id_2") res = self.proxy.statistics.group("group_id_2") self.check_xmlrpc_simple(res, { 'group_id': 'group_id_2', 'call_count': 1, 'call_abort': 0, }, rowcount=1) # Check statistics on all groups with a common pattern. res = self.proxy.statistics.group("group_id") self.check_xmlrpc_simple(res, {}, rowcount=2) # Check statistics on all groups. res = self.proxy.statistics.group() self.check_xmlrpc_simple(res, {}, rowcount=2)
def check_xmlrpc_iter(self, packet, index=0, rowcount=None): """Iterate over a result set and do some basic integrity checking first. """ result = _xmlrpc._decode(packet) self.assertTrue(len(result.results) > index, str(result)) if rowcount is not None: self.assertEqual(result.results[index].rowcount, rowcount, str(result)) names = [c.name for c in result.results[index].columns] for row in result.results[index]: yield dict(zip(names, row))
def check_xmlrpc_result(self, packet, expected, index=0): """Compare the result set of a command result with an expected value. Order of rows in result sets are important and have to match. :param ResultSet expected: Expected result set. """ result = _xmlrpc._decode(packet) self.assertFalse(result.error, "Error: '%s'" % result.error) self.assertTrue(len(result.results) > index, str(result)) self.assertEqual(result.results[index].columns, expected.columns) for row, exp in zip(result.results[index], expected): self.assertEqual(row, exp)
def test_create_group_events(self): """Test creating a group by calling group.create(). """ # Look up groups. status = self.proxy.group.lookup_groups() result = _xmlrpc._decode(status) self.assertEqual(len(result.results), 1) self.assertEqual(result.results[0].rowcount, 0) # Insert a new group. status = self.proxy.group.create("group", "Testing group...") self.check_xmlrpc_command_result(status, False) # Try to insert a group twice. status = self.proxy.group.create("group", "Testing group...") self.check_xmlrpc_command_result(status, True) # Look up groups. status = self.proxy.group.lookup_groups() self.check_xmlrpc_simple( status, { "group_id": "group", "description": "Testing group...", "failure_detector": False, }) # Look up a group. status = self.proxy.group.lookup_groups("group") self.check_xmlrpc_simple( status, { "group_id": "group", "description": "Testing group...", "failure_detector": False, }) # Try to look up a group that does not exist. status = self.proxy.group.lookup_groups("group_1") self.check_xmlrpc_simple(status, {}, has_error=True) # Update a group. status = self.proxy.group.description("group", "Test Test Test") self.check_xmlrpc_command_result(status, False) # Try to update group that does not exist. status = self.proxy.group.description("group_1", "Test Test Test") self.check_xmlrpc_command_result(status, True)
def check_xmlrpc_command_success(self, packet, expect, has_error): result = _xmlrpc._decode(packet) self.assertEqual(bool(result.error), has_error, "Had error '%s'" % result.error) # Check that it returned the expected result (if one is # expected), which is in the first result set (containing # execution result), first row (there is just one for # procedures), and last column (containing the result). if expect is not None: self.assertEqual(result.results[0][0][3], expect) # If the call was successful, check that there is at least 2 # result sets and that the second result set contain more than # zero jobs. if not has_error: self.assertTrue(len(result.results) > 1, str(result)) self.assertNotEqual(result.results[1].rowcount, 0, "had %d result sets" % len(result.results))
def test_statistics_procedure(self): """Test statistics on procedures. """ # Check statistics on a non-existent procedure. res = self.proxy.statistics.procedure("non-existent") result = _xmlrpc._decode(res) self.assertEqual(len(result.results), 1) self.assertEqual(result.results[0].rowcount, 0) # Check statistics on procedures using the "statistics" pattern. self.proxy.statistics.group("group_id") res = self.proxy.statistics.procedure("statistics") self.check_xmlrpc_simple(res, { 'proc_name': 'statistics.group', 'call_count': 1, 'call_abort': 0, }, index=0) self.check_xmlrpc_simple(res, { 'proc_name': 'statistics.procedure', 'call_count': 2, 'call_abort': 0, }, index=1) # Check statistics on procedures that fail. self.proxy.test.execution_event() res = self.proxy.statistics.procedure("test.execution_event") self.check_xmlrpc_simple(res, { 'proc_name': 'test.execution_event', 'call_count': 1, 'call_abort': 1, }, rowcount=1) # Check statistics on procedures that are asynchronously executed and # fail. Note that an error is not reported because the procedure is # asynchronously executed. self.proxy.test.execution_event(False) res = self.proxy.statistics.procedure("test.execution_event") self.check_xmlrpc_simple(res, { 'proc_name': 'test.execution_event', 'call_count': 2, 'call_abort': 1, }, rowcount=1) # Check statistics on procecures executed so far, i.e. all procedures. res = self.proxy.statistics.procedure() self.check_xmlrpc_simple(res, { 'proc_name': 'statistics.group', 'call_count': 1, 'call_abort': 0, }, index=0, rowcount=3) self.check_xmlrpc_simple(res, { 'proc_name': 'statistics.procedure', 'call_count': 5, 'call_abort': 0, }, index=1, rowcount=3) self.check_xmlrpc_simple(res, { 'proc_name': 'test.execution_event', 'call_count': 2, 'call_abort': 1, }, index=2, rowcount=3)
def check_xmlrpc_simple(self, packet, checks, has_error=False, index=0, rowcount=None): """Perform assertion checks on a row of a result set. This will perform basic assertion checks on a command result returned by an XML-RPC server proxy. It will decode the result into a command result and pick a row from the first result set in the result (assuming there were no error) and do an equality comparison with the fields provided in the ``checks`` parameter. :param packet: The Python data structure from the XML-RPC server. :param checks: Dictionary of values to check. :param has_error: True if errors are expected for this packet, False otherwise. Default to False. :param index: Index of row to check. Default to the first row of the result set, if there is any. :param rowcount: Number of rows expected in the result set, or None if no check should be done. :return: Return a dictionary of the actual contents of the row, or an empty dictionary in the event of an error. """ result = _xmlrpc._decode(packet) self.assertEqual(bool(result.error), has_error, str(result)) if not has_error: # Some commands are successful but have no result sets # anyway (e.g., set_logging_level). if len(result.results) == 0: return {} if rowcount is not None: self.assertEqual(result.results[0].rowcount, rowcount, str(result)) if result.results[0].rowcount == 0: return {} # Check that there is enough rows in the first result set self.assertTrue(result.results[0].rowcount > index, str(result)) # Create a dictionary from this row. info = dict( zip([col.name for col in result.results[0].columns], result.results[0][index])) for key, value in checks.items(): self.assertTrue(key in info, str(result)) self.assertEqual( info[key], value, "[%s != %s]:\n%s" % (info[key], value, str(result))) # For convenience, allowing the simple result to be used # by callers. return info return {}