From: Dyre Tjeldvoll Date: October 24 2012 10:52am Subject: bzr push into mysql-5.5-cluster-7.2 branch (Dyre.Tjeldvoll:4095 to 4096) List-Archive: http://lists.mysql.com/commits/145110 Message-Id: <20121024105202.21534.19748.4096@khepri17.no.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4096 Dyre Tjeldvoll 2012-10-24 Rework python unit tests, remove stack dump when host_info binary cannot be found and add a config-parsing command to request_handler modified: storage/ndb/mcc/clusterhost.py storage/ndb/mcc/config_parser.py storage/ndb/mcc/remote_clusterhost.py storage/ndb/mcc/request_handler.py storage/ndb/mcc/tst/tst_main.py storage/ndb/mcc/tst/xmlrunner2.py 4095 Dyre Tjeldvoll 2012-10-10 Fixing indentation errors modified: storage/ndb/mcc/request_handler.py === modified file 'storage/ndb/mcc/clusterhost.py' --- a/storage/ndb/mcc/clusterhost.py 2012-10-09 08:36:12 +0000 +++ b/storage/ndb/mcc/clusterhost.py 2012-10-24 10:51:28 +0000 @@ -81,11 +81,12 @@ class HostInfo(object): def rep(self): """A Python dict representation of the hostInfoRep structure which can be directly converted to Json.""" reply = None - try: - reply = self._run_host_info() - except: - _logger.exception('Running host_info failed. Falling back to system tools:') - reply = self._get_hostInfo() +# try: +# reply = self._run_host_info() +# except: +# _logger.exception('Running host_info failed. Falling back to system tools:') + + reply = self._get_hostInfo() local = platform.system() remote = self.uname @@ -161,6 +162,14 @@ hostInfo_map = { 'SunOS' : SolarisHostIn class ABClusterHost(object): """Base class providing common interface.""" __meta_class__ = abc.ABCMeta + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.drop() + return False + def __init__(self): self._hostInfo = None === modified file 'storage/ndb/mcc/config_parser.py' --- a/storage/ndb/mcc/config_parser.py 2012-09-20 12:19:53 +0000 +++ b/storage/ndb/mcc/config_parser.py 2012-10-24 10:51:28 +0000 @@ -17,6 +17,47 @@ import StringIO import ConfigParser +def parse_cluster_config_ini(path): + with open(path) as ini: + return parse_cluster_conifg_ini_(ini) + +def parse_cluster_conifg_ini_(ini): + c = [] + s = None + for l in map(str.rstrip, ini): + if l == '' or l.startswith('#'): + continue + if l.startswith('['): + s = { 'name': l[1:-1], 'options': {} } + c.append(s) + continue + (k,v) = l.split('=', 1) + s['options'][k] = v + return c + +def write_cluster_config_ini(c): + return '\n'.join([ '[{0}]\n{1}\n'.format(s['name'], '\n'.join(['{0}={1}'.format(k, s['options'][k]) for k in s['options'].keys()])) for s in c ]) + +def parse_cluster_config_ini_x(path): + c = {} + with open(path) as ini: + key = None + opts = {} + for l in map(str.rstrip, ini): + if l == '' or l.startswith('#'): + continue + if l.startswith('['): + if key is not None: + c[key] = opts + key = l + continue + (k,v) = l.split('=', 1) + opts[k] = v + if k == 'NodeId': + key = (key, v) + return c + +# Below is deprecated def parse_config_ini(path): ini = open(path) buf = StringIO.StringIO() @@ -41,6 +82,7 @@ def parse_config_ini(path): buf.close() return cp + def get_option_value_set(cp, option): return set([cp.get(s, option) for s in filter(lambda s: cp.has_option(s, option), cp.sections())]) === modified file 'storage/ndb/mcc/remote_clusterhost.py' --- a/storage/ndb/mcc/remote_clusterhost.py 2012-10-09 11:14:15 +0000 +++ b/storage/ndb/mcc/remote_clusterhost.py 2012-10-24 10:51:28 +0000 @@ -46,11 +46,11 @@ class RemoteClusterHost(ABClusterHost): """Implements the ABClusterHost interface for remote hosts. Wraps a paramiko.SSHClient and uses this to perform tasks on the remote host.""" - def __init__(self, host, user, pwd): + def __init__(self, host, username=None, password=None): super(type(self), self).__init__() self.host = host - self.user = user - self.pwd = pwd + self.user = username + self.pwd = password self.__client = None self.__sftp = None === modified file 'storage/ndb/mcc/request_handler.py' --- a/storage/ndb/mcc/request_handler.py 2012-10-10 07:25:52 +0000 +++ b/storage/ndb/mcc/request_handler.py 2012-10-24 10:51:28 +0000 @@ -46,6 +46,8 @@ import random import stat import util +import config_parser + from clusterhost import produce_ABClusterHost _logger = logging.getLogger(__name__) @@ -358,6 +360,25 @@ def handle_runMgmdCommandReq(req, body): return make_rep(req, { 'reply_type': status.reply_type, 'reply_properties':sd}) + +def handle_getConfigIni(req, body): + (user, pwd) = get_cred(body) + cf = body['configFile'] + assert (cf.has_key('path') and cf.has_key('name') and cf.has_key('hostName')) + + with produce_ABClusterHost(sf['hostName'], user, pwd) as ch: + sp = ch.path_module.join(sf['path'], sf['name']) + assert (ch.file_exists(sp)), 'File ' + sp + " does not exist on host " + ch.host + with ch.open(sp) as ini: + return make_rep(req, {'config': config_parser.parse_cluster_config_ini_(ini)}) + +def handle_getNdbConfig(req, body): + (user, pwd) = get_cred(body) + + with produce_ABClusterHost(body['hostName'], user, pwd) as ch: + ndb_config = ch.path_module.join(body['installpath'], 'ndb_config') + return make_rep(req, { 'ndb_config': json.dumps(util.xml_to_python(ch.exec_cmdv([ndb_config, '--configinfo', '--xml']))) }) + def log_thread_name(): """Utility for dumping thread id in the log.""" === modified file 'storage/ndb/mcc/tst/tst_main.py' --- a/storage/ndb/mcc/tst/tst_main.py 2012-10-05 12:49:17 +0000 +++ b/storage/ndb/mcc/tst/tst_main.py 2012-10-24 10:51:28 +0000 @@ -40,6 +40,8 @@ import stat import os.path import tempfile import os +import platform +import logging import request_handler import config_parser @@ -47,66 +49,49 @@ import clumodel import util from util import mock_msg, is_set -from clusterhost import ABClusterHost, produce_ABClusterHost, LocalClusterHost +from clusterhost import ABClusterHost, LocalClusterHost, produce_ABClusterHost +from remote_clusterhost import RemoteClusterHost + +from paramiko import SSHClient, WarningPolicy + +def defdatadir(): + return os.path.join(os.path.expanduser('~'), 'MySQL_Cluster', 'data') # Default tst configuration. Can be overridden in config.json -_cfg = { 'debuglevel': None, 'username': None, 'password': None, 'host_list': [{'name': 'localhost'}] } -_cfg_loaded = False +_cfg = { 'debuglevel': 'DEBUG' } def cfg(): - global _cfg_loaded - if _cfg_loaded: return _cfg - try: - cfgfile = open('config.json') - fcfg = json.load(cfgfile) - except: - traceback.print_exc() - else: - for k in fcfg.keys(): - _cfg[k] = fcfg[k] - finally: - _cfg_loaded = True - - print '_cfg='+str(_cfg) - return _cfg - -def host_names(): - return [ hd['name'] for hd in cfg()['host_list'] ] - request_handler.configdir = '..' def_datadir = os.path.join(os.path.expanduser('~'), 'MySQL_Cluster', 'data') -SUNOS_HOST = {'name' : 'fimafeng08.no.oracle.com', - 'memory' : 4096, - 'hostInfoRep': { 'host': { 'name' : 'fimafeng08.no.oracle.com' }, - 'hostRes' : {'ram' : 4096, 'cores' : 4, 'uname' : 'SunOS', - 'datadir': util.get_val(cfg(), 'datadir', def_datadir), - 'installdir': None }}} - -LINUX_HOST = {'name': 'fimafeng09.no.oracle.com', - 'memory': 7991, - 'hostInfoRep': { 'host': { 'name' : 'fimafeng09.no.oracle.com' }, - 'hostRes' : {'ram' : 7991, 'cores' : 4, 'uname': 'Linux', - 'datadir': util.get_val(cfg(), 'datadir', def_datadir), - 'installdir': None }}} - -WINDOWS_HOST = {'name' : 'tyr04.no.oracle.com', - 'memory': 8190, - 'hostInfoRep': { 'host': { 'name' : 'tyr04.no.oracle.com' }, - 'hostRes' : {'ram' : 8190, 'cores' : 8, 'uname': 'CYGWIN' }}} -def mock_produce_ABClusterHost(hostname='localhost'): - return produce_ABClusterHost(hostname=hostname) +def mock_ABClusterHost(hle): + return produce_ABClusterHost(hostname=hle['hostInfoRep']['host']['name'], user=util.get_val(hle, 'username'), pwd=util.get_val(hle, 'password')) def host_is_unreachable(hostname, port=22): return util.try_connect(hostname, port, False, retdict={ socket.EAI_NONAME : True}) +def is_local_sshd_available(): + c = SSHClient() + c.set_missing_host_key_policy(WarningPolicy()) + try: + c.connect('localhost') + except: + return False + else: + return True + finally: + c.close() + def mock_msg_as_json(cmd, body): return json.dumps(mock_msg(cmd,body)) +def json_normalize(x): + return json.loads(json.dumps(x)) + class Test00Utils(utmod.TestCase): def test_version_tuple(self): print [ int(filter(str.isdigit, vn)) for vn in ('2', '7', '2+')] @@ -123,8 +108,13 @@ class Test00Utils(utmod.TestCase): self.assertTrue(host_is_unreachable('some_non_existent_host_name')) def test_host_is_unreachable(self): - for h in host_names(): - self.assertFalse(host_is_unreachable(h)) + self.assertFalse(host_is_unreachable('localhost')) + + def test_to_json(self): + obj = [ "sleep" "300" ] + json_string = json.dumps(obj) + jobj = json.loads(json_string) + self.assertEqual(obj, jobj) class Test0ConfigIni(utmod.TestCase): def setUp(self): @@ -142,31 +132,150 @@ class Test0ConfigIni(utmod.TestCase): def test_get_configvalues(self): print config_parser.get_configvalues(self.cp) print config_parser.get_processes(self.cp) + + def test_parse(self): + logging.debug('ex_ini as json:\n'+json.dumps(config_parser.parse_cluster_config_ini('example_config.ini'))) + + def test_parsex(self): + logging.debug('ex_ini as json:\n'+str(config_parser.parse_cluster_config_ini_x('example_config.ini'))) + + def test_write(self): + logging.debug('ex_ini write back:\n'+config_parser.write_cluster_config_ini(config_parser.parse_cluster_config_ini('example_config.ini'))) + + @utmod.skipIf(,'') + def test_ndb_config(self): + print 'ndb config as json: ', json.dumps(util.xml_to_python(self.cluster.ndb_config_xml())) - @utmod.skip('hangs...') - def test_create_cluster_from_config_ini(self): - print clumodel.create_cluster_from_config_ini('example_config.ini') - -class Test1Json(utmod.TestCase): + +class Test3Ports(utmod.TestCase): + def testPortNotAvailable(self): + self.assertFalse(util.is_port_available('localhost', 22)) + + def testPortAvailable(self): + self.assertTrue(util.is_port_available('localhost', 23)) + + def testFindPort(self): + self.assertEqual(util.first_available_port('localhost', 22, 23), 23) + + def testNotFindPort(self): + self.assertRaises(util.NoPortAvailableException, + util.first_available_port, 'localhost', 22, 22) + +class _TestABClusterHost: + def setUp(self): + pass + + def tearDown(self): + self.ch.drop() + + def test_fg_exec(self): + self.assertEqual(self.ch.exec_blocking(['echo', 'foo']).strip(), 'foo') + + def test_fileops(self): + self.assertTrue(self.ch.file_exists('/tmp')) + self.ch.mkdir_p('/tmp/foo/bar//') + f = None + try: + f = self.ch.open('/tmp/foo/bar/baz', 'w+') + f.write('Some text here...\n') + f.seek(0) + self.assertEqual(f.read(), 'Some text here...\n') + finally: + if f is not None: + f.close() + self.ch.rm_r('/tmp/foo') + + def test_stat_dir_2(self): + if not hasattr(self.ch, 'sftp'): + return + self.assertTrue(stat.S_ISDIR(self.ch.sftp.stat('/tmp').st_mode)) + + @utmod.skip('Cannot create files with attributes') + def test_list_dir_no_x(self): + nox_mode = self.self.ch.sftp.stat('/tmp/nox').st_mode + notmine_mode = self.self.ch.sftp.stat('/tmp/not_mine').st_mode + + self.assertTrue(stat.S_ISDIR(nox_mode)) + self.assertTrue(is_set(stat.S_IMODE(nox_mode), stat.S_IXGRP)) + + self.assertTrue(stat.S_ISDIR(notmine_mode)) + self.assertTrue(is_set(stat.S_IMODE(notmine_mode), stat.S_IXOTH)) + + print "listdir(nox)="+str(self.self.ch.list_dir('/tmp/nox')) + print "listdir(notmine)="+str(self.self.ch.list_dir('/tmp/not_mine')) + + def test_mkdir_p(self): + self.ch.mkdir_p('/tmp/some_dir/') + self.ch.rm_r('/tmp/some_dir/') + + def test_hostInfo(self): + hir = json_normalize(self.ch.hostInfo.rep) + self.assertGreater(hir['hostRes']['ram'], 1024) + self.assertGreater(hir['hostRes']['cores'], 1) + + +class Test4LocalClusterHost(utmod.TestCase, _TestABClusterHost): + def setUp(self): + _TestABClusterHost.setUp(self) + self.ch = LocalClusterHost('localhost') + + def tearDown(self): + _TestABClusterHost.tearDown(self) + +@stripped(not is_local_sshd_available(), 'No suitable local sshd') +class Test5RemoteClusterHost(utmod.TestCase, _TestABClusterHost): + def setUp(self): + _TestABClusterHost.setUp(self) + self.ch = RemoteClusterHost(socket.gethostname()) + + def tearDown(self): + _TestABClusterHost.tearDown(self) + + def test_copy_file(self): + with tempfile.NamedTemporaryFile() as ex: + ex.write("Some text here\nSome more text on another line\n") + + if not hasattr(self.ch, 'sftp'): + return + ex.seek(0) + self.ch.sftp.put(ex.name, '/tmp/example.txt') + self.ch.sftp.get('/tmp/example.txt', 'remote_example.txt') + with open('remote_example.txt') as rex: + self.assertEqual(ex.read(), rex.read()) + + def test_mkdir(self): + with tempfile.NamedTemporaryFile() as ex: + ex.write("Some text here\nSome more text on another line\n") + ex.seek(0) + if not hasattr(self.ch, 'sftp'): + return + self.ch.sftp.mkdir('/tmp/some_new_dir/') + try: + self.ch.sftp.put(ex.name, '/tmp/some_new_dir/example.txt') + self.ch.sftp.remove('/tmp/some_new_dir/example.txt') + finally: + self.ch.sftp.rmdir('/tmp/some_new_dir/') + + def test_stat_dir(self): + if not hasattr(self.ch, 'sftp'): + return + self.assertEqual(stat.S_IFMT(self.ch.sftp.stat('/tmp').st_mode), stat.S_IFDIR) + + +class Test6RequestHandler(utmod.TestCase): def setUp(self): self.ssh = {'user': None, 'pwd': None } def tearDown(self): pass - def test_to_json(self): - obj = [ "sleep" "300" ] - json_string = json.dumps(obj) - jobj = json.loads(json_string) - self.assertEqual(obj, jobj) - + def test_hostInfoReq(self): json_str = mock_msg_as_json('hostInfoReq', {'ssh': self.ssh, 'hostName': 'localhost'}) print 'hostInfoReq: '+json_str print request_handler.handle_req(json.loads(json_str)) - @utmod.skipIf(not cfg().has_key('local_installdir'), 'local_installdir not set') def test_createFileReq(self): json_str = mock_msg_as_json('createFileReq', {'ssh': self.ssh, 'file': {'hostName': 'localhost', 'path': tempfile.gettempdir(), 'name': 'foobar'}, @@ -181,7 +290,7 @@ class Test1Json(utmod.TestCase): pass - @utmod.skipIf(not cfg().has_key('local_installdir'), 'local_installdir not set') + @utmod.skip('Too heavy - need to mock the execution') def test_startClusterReq(self): json_str = mock_msg_as_json('startClusterReq', {'ssh': self.ssh, @@ -192,160 +301,39 @@ class Test1Json(utmod.TestCase): print json_str print request_handler.handle_req(json.loads(json_str)) - - -@stripped(not cfg().has_key('linux_host') or host_is_unreachable(cfg()['linux_host']['name']), 'Skipping because no reachable linux host') -class Test5SSH(utmod.TestCase): - def setUp(self): - self.chost = mock_produce_ABClusterHost(cfg()['linux_host']['name']) - self.flst = [] - example = open('example.txt', 'w') - example.write("Some text here\nSome more text on another line\n") - example.close() - - def tearDown(self): - self.chost.drop(self.flst) - - def test_fg_exec(self): - self.assertEqual(self.chost.exec_blocking(['uname']).strip(), 'Linux') - - def test_copy_file(self): - self.chost.sftp.put('example.txt', '/tmp/example.txt') - self.flst.append('/tmp/example.txt') - self.chost.sftp.get('/tmp/example.txt', 'remote_example.txt') - example = open('example.txt') - remote_example = open('remote_example.txt') - try: - self.assertEqual(example.read(), remote_example.read()) - finally: - example.close() - remote_example.close() - os.remove('remote_example.txt') - - def test_mkdir(self): - self.chost.sftp.mkdir('/tmp/some_new_dir/') - try: - self.chost.sftp.put('example.txt', '/tmp/some_new_dir/example.txt') - self.chost.sftp.remove('/tmp/some_new_dir/example.txt') - finally: - self.chost.sftp.rmdir('/tmp/some_new_dir/') - - def test_stat_dir(self): - self.assertEqual(stat.S_IFMT(self.chost.sftp.stat('/tmp').st_mode), stat.S_IFDIR) - - @utmod.skipIf(not cfg().has_key('windows_host') or host_is_unreachable(cfg()['windows_host']['name']), 'Skipping, no windows host') - def test_stat_dir_win(self): - whost = mock_produce_ABClusterHost(WINDOWS_HOST['name']) - self.assertTrue(stat.S_ISDIR(whost.sftp.stat('/tmp').st_mode)) - - @utmod.skip('Cannot create files with files with attributes') - def test_list_dir_no_x(self): - nox_mode = self.chost.sftp.stat('/tmp/nox').st_mode - notmine_mode = self.chost.sftp.stat('/tmp/not_mine').st_mode - - self.assertTrue(stat.S_ISDIR(nox_mode)) - self.assertTrue(is_set(stat.S_IMODE(nox_mode), stat.S_IXGRP)) - - self.assertTrue(stat.S_ISDIR(notmine_mode)) - self.assertTrue(is_set(stat.S_IMODE(notmine_mode), stat.S_IXOTH)) - print "listdir(nox)="+str(self.chost.list_dir('/tmp/nox')) - print "listdir(notmine)="+str(self.chost.list_dir('/tmp/not_mine')) - def test_mkdir_p(self): - self.chost.mkdir_p('/tmp/some_dir/') - self.flst.append('/tmp/some_dir/') - -@stripped(not cfg().has_key('linux_host') or host_is_unreachable(cfg()['linux_host']['name']), 'Skipping because linux host is unavailable') -class Test3Ports(utmod.TestCase): - def testPortNotAvailable(self): - self.assertFalse(util.is_port_available(cfg()['linux_host']['name'], 22)) - - def testPortAvailable(self): - self.assertTrue(util.is_port_available(cfg()['linux_host']['name'], 23)) - - def testFindPort(self): - self.assertEqual(util.first_available_port(cfg()['linux_host']['name'], 22, 23), 23) - - def testNotFindPort(self): - self.assertRaises(util.NoPortAvailableException, - util.first_available_port, cfg()['linux_host']['name'], 22, 22) - -class Test4ABClusterHost(utmod.TestCase): +class Test7ConfiguratorServer(utmod.TestCase): def setUp(self): - self.ch = None - self.chlst = map(mock_produce_ABClusterHost, host_names()) - + # TODO Start server + #self.cluster = clumodel.create_cluster_from_config_ini('example_config.ini') + pass + def tearDown(self): - if self.ch != None: - self.ch.drop() - map(ABClusterHost.drop, self.chlst) - - def test_hostInfo(self): - print [ch.hostInfo for ch in self.chlst] - def test_fileops(self): - for ch in self.chlst: - print "Testing file ops on host ", ch.host - self.assertTrue(ch.file_exists('/tmp')) - ch.mkdir_p('/tmp/foo/bar//') - f = None - try: - f = ch.open('/tmp/foo/bar/baz', 'w+') - f.write('Some text here...\n') - f.seek(0) - self.assertEqual(f.read(), 'Some text here...\n') - finally: - if f: - f.close() - ch.rm_r('/tmp/foo') - - @utmod.skipIf(not cfg().has_key('linux_host'), 'No linux_host') - def test_hostInfoRep_lin(self): - self.maxDiff = None - self.ch = mock_produce_ABClusterHost(cfg()['linux_host']['name']) - self.assertEqual(self.ch.hostInfo.rep, cfg()['linux_host']['hostInfoRep']) - - @utmod.skipIf(not cfg().has_key('sunos_host'), 'No sunos_host') - def test_hostInfoRep_sol(self): - self.ch = mock_produce_ABClusterHost(cfg()['sunos_host']['name']) - self.assertEqual(self.ch.hostInfo.rep, cfg()['sunos_host']['hostInfoRep']) - - @utmod.skipIf(not cfg().has_key('windows_host'), 'No windows_host') - def test_hostInfoRep_win(self): - self.ch = mock_produce_ABClusterHost(cfg()['windows_host']['name']) - self.assertEqual(self.ch.hostInfo.rep, cfg()['windows_host']['hostInfoRep']) - - def test_hostInfoRep_localhost(self): - self.ch = mock_produce_ABClusterHost('localhost') - self.assertTrue(isinstance(self.ch, LocalClusterHost)) - print self.ch.hostInfo.rep - -@stripped('Hangs') -class Test6Cluster(utmod.TestCase): - def setUp(self): - self.cluster = clumodel.create_cluster_from_config_ini('example_config.ini') - def tearDown(self): - self.cluster.drop() - time.sleep(5.0) # To allow the cluster to really disappear + #self.cluster.drop() + #time.sleep(5.0) # To allow the cluster to really disappear + # TODO Shutdown server + pass + @utmod.skip('Deprecated') def test_deploy_config(self): map(request_handler.handle_req, self.cluster.get_deploy_config_msgs()) - @utmod.skip('Covered by later case') + @utmod.skip('Deprecated') def test_start_mgmds(self): self.cluster.deploy_config('example_config.ini', '/example_config.ini') self.cluster.start_nodes(clumodel.MgmdNode) time.sleep(1.0) # So the mgmds know about each other before calling tearDown - @utmod.skip('Covered by later case') + @utmod.skip('Deprecated') def test_start_ndbds(self): self.cluster.deploy_config('example_config.ini', '/example_config.ini') self.cluster.start_nodes(clumodel.MgmdNode) self.cluster.start_nodes(clumodel.NdbdNode) #time.sleep(2.0) - @utmod.skip('For now') + @utmod.skip('Deprecated') def test_start_mysqlds(self): self.cluster.deploy_config('example_config.ini', '/example_config.ini') self.cluster.start_nodes(clumodel.MgmdNode) @@ -353,7 +341,8 @@ class Test6Cluster(utmod.TestCase): time.sleep(30.0) self.cluster.start_nodes(clumodel.MysqldNode) time.sleep(30.0) - + + @utmod.skip('For now') def test_start_cluster(self): map(request_handler.handle_req, self.cluster.get_deploy_config_msgs()) request_handler.handle_req(self.cluster.get_start_msg()) @@ -361,12 +350,7 @@ class Test6Cluster(utmod.TestCase): # Just so that tearDown actually will clean things up for n in self.cluster.nodes: n.is_started = True - - def test_ndb_config(self): - print 'ndb config as json: ', json.dumps(util.xml_to_python(self.cluster.ndb_config_xml())) - - - + if __name__ == '__main__': if cfg()['debuglevel'] is not None: === modified file 'storage/ndb/mcc/tst/xmlrunner2.py' --- a/storage/ndb/mcc/tst/xmlrunner2.py 2012-09-20 12:19:53 +0000 +++ b/storage/ndb/mcc/tst/xmlrunner2.py 2012-10-24 10:51:28 +0000 @@ -81,7 +81,7 @@ class XMLTestResult(unittest.TextTestRes self._addOut('err') finally: super(type(self), self).stopTest(test) - print 'super().stopTest called' + #print 'super().stopTest called' self._tc['element'].set('time', str(time.time() - self._tc['stime'])) self._tb.end('testcase') @@ -96,9 +96,9 @@ class XMLTestResult(unittest.TextTestRes See stopTest for a method called after each test. """ - print 'Calling super().stopTestRun' + #print 'Calling super().stopTestRun' super(type(self), self).stopTestRun() - print 'After super().stopTestRun' + #print 'After super().stopTestRun' self._ts['element'].set('errors',str(len(self.errors))) # TODO - do we need to add unexpected successes here? self._ts['element'].set('failures',str(len(self.failures))) No bundle (reason: useless for push emails).