def _do_setup(self, cfg, node_count=5):
     # give defaults to teardown vars
     self._node_ctrl = None
     print 'creating', str(self.__class__.__name__)
     # set up our nodes (suite-internal interface)
     self._node_ctrl = WrappedNodeController(SubprocessNodeController())
     temp_dir = self._node_ctrl.get_data_dir()
     file_name = os.path.join(temp_dir, "config.js")
     with open(file_name, 'w') as config:
         config.write(json.dumps(cfg))
     self._nodes = [
         NodeArguments('v%s' % i,
                       8800 + i,
                       9000 + i,
                       config_files=[file_name],
                       ledger_type=cfg["LedgerType"])
         for i in range(node_count)
     ]
     # set up our urls (external interface)
     self.urls = ['http://localhost:%s' % x.http_port for x in self._nodes]
     # Make genesis block
     print 'creating genesis block...'
     self._nodes[0].genesis = True
     self._node_ctrl.create_genesis_block(self._nodes[0])
     # Launch network (node zero will trigger bootstrapping)
     print 'launching network...'
     for x in self._nodes:
         self._node_ctrl.start(x)
Esempio n. 2
0
def get_node_controller(state, args):
    # Get base controller:
    manage_type = state['Manage']

    node_controller_types = {
        'docker': DockerNodeController,
        'subprocess': SubprocessNodeController,
        'subprocess-legacy': SubprocessLegacyNodeController,
        'docker-legacy': DockerLegacyNodeController,
        'daemon-legacy': DaemonLegacyNodeController,
    }

    try:
        node_controller_type = node_controller_types[manage_type]
    except:
        # manage_type hasn't been added to node_controller_types
        if manage_type in ALL_MANAGE_TYPES:
            error_msg = '{} manamgement type not implemented'
        else:
            error_msg = 'Invalid management type: {}'
        raise CliException(error_msg.format(manage_type))

    node_controller = node_controller_type()

    # Optionally decorate with WrappedNodeController
    args_wrap = False if not hasattr(args, 'wrap') else args.wrap

    if 'Wrap' not in state.keys():
        # if wrap has not been set in state, set it
        state['Wrap'] = args_wrap
    else:
        # state already knows about a wrapper
        if args_wrap is not False and args_wrap != state['Wrap']:
            raise CliException("Already wrapped to %s." % state["Wrap"])

    if state['Wrap'] is not False:
        wrappable_types = SubprocessLegacyNodeController,
        if not isinstance(node_controller, wrappable_types):
            msg = '--wrap currently only implemented for {} management types'
            raise CliException(msg.format(wrappable_types))
        # either args or state have indicated a WrappedNodeController
        if 'ManageWrap' not in state.keys():
            state['ManageWrap'] = None
        node_controller = WrappedNodeController(
            node_controller,
            data_dir=state['Wrap'],
            clean_data_dir=state['ManageWrap'])
        if state['Wrap'] is None:
            state['Wrap'] = node_controller.get_data_dir()
            state['ManageWrap'] = True
        print('{} wrapped to {}'.format(args.cluster_command, state['Wrap']))

    # Return out construction:
    return node_controller
Esempio n. 3
0
def get_node_controller(state, args):
    # Get base controller:
    manage_type = state['Manage']

    node_controller_types = {
        'docker': DockerNodeController,
        'subprocess': SubprocessNodeController,
        'subprocess-legacy': SubprocessLegacyNodeController,
        'docker-legacy': DockerLegacyNodeController,
        'daemon-legacy': DaemonLegacyNodeController,
    }

    try:
        node_controller_type = node_controller_types[manage_type]
    except:
        # manage_type hasn't been added to node_controller_types
        if manage_type in ALL_MANAGE_TYPES:
            error_msg = '{} manamgement type not implemented'
        else:
            error_msg = 'Invalid management type: {}'
        raise CliException(error_msg.format(manage_type))

    node_controller = node_controller_type()

    # Optionally decorate with WrappedNodeController
    args_wrap = False if not hasattr(args, 'wrap') else args.wrap

    if 'Wrap' not in state.keys():
        # if wrap has not been set in state, set it
        state['Wrap'] = args_wrap
    else:
        # state already knows about a wrapper
        if args_wrap is not False and args_wrap != state['Wrap']:
            raise CliException("Already wrapped to %s." % state["Wrap"])

    if state['Wrap'] is not False:
        wrappable_types = SubprocessLegacyNodeController,
        if not isinstance(node_controller, wrappable_types):
            msg = '--wrap currently only implemented for {} management types'
            raise CliException(msg.format(wrappable_types))
        # either args or state have indicated a WrappedNodeController
        if 'ManageWrap' not in state.keys():
            state['ManageWrap'] = None
        node_controller = WrappedNodeController(
            node_controller, data_dir=state['Wrap'],
            clean_data_dir=state['ManageWrap'])
        if state['Wrap'] is None:
            state['Wrap'] = node_controller.get_data_dir()
            state['ManageWrap'] = True
        print('{} wrapped to {}'.format(args.cluster_command, state['Wrap']))

    # Return out construction:
    return node_controller
 def _do_setup(self, cfg, node_count=5):
     # give defaults to teardown vars
     self._node_ctrl = None
     print('creating', str(self.__class__.__name__))
     # set up our nodes (suite-internal interface)
     self._node_ctrl = WrappedNodeController(
         SubprocessLegacyNodeController())
     temp_dir = self._node_ctrl.get_data_dir()
     file_name = os.path.join(temp_dir, "config.js")
     with open(file_name, 'w') as config:
         config.write(json.dumps(cfg))
     self._nodes = [
         NodeArguments('v%s' % i, 8800 + i, 9000 + i,
                       config_files=[file_name],
                       ledger_type=cfg["LedgerType"])
         for i in range(node_count)]
     # set up our urls (external interface)
     self.urls = ['http://localhost:%s' % x.http_port for x in self._nodes]
     # Make genesis block
     print('creating genesis block...')
     self._nodes[0].genesis = True
     self._node_ctrl.create_genesis_block(self._nodes[0])
     # Launch network (node zero will trigger bootstrapping)
     print('launching network...')
     for x in self._nodes:
         self._node_ctrl.start(x)
Esempio n. 5
0
 def _do_setup(self):
     # give defaults to teardown vars
     self._node_ctrl = None
     print 'creating', str(self.__class__.__name__)
     # set up our nodes (suite-internal interface)
     self._nodes = [
         NodeArguments('v%s' % i, 8800 + i, 9000 + i) for i in range(2)
     ]
     # set up our urls (external interface)
     self.urls = ['http://localhost:%s' % x.http_port for x in self._nodes]
     # Make genesis block
     print 'creating genesis block...'
     self._nodes[0].genesis = True
     self._node_ctrl = WrappedNodeController(SubprocessNodeController())
     self._node_ctrl.create_genesis_block(self._nodes[0])
     # Launch network (node zero will trigger bootstrapping)
     print 'launching network...'
     for x in self._nodes:
         self._node_ctrl.start(x)
Esempio n. 6
0
def get_node_controller(state, args):
    # pylint: disable=redefined-variable-type

    # Get base controller:
    node_controller = None
    if state['Manage'] == 'subprocess':
        node_controller = SubprocessNodeController()
    elif state['Manage'] == 'docker':
        node_controller = DockerNodeController()
    elif state['Manage'] == 'daemon':
        node_controller = DaemonNodeController()
    else:
        raise CliException('invalid management type:'
                           ' {}'.format(state['Manage']))

    # Optionally decorate with WrappedNodeController
    args_wrap = False if not hasattr(args, 'wrap') else args.wrap
    if 'Wrap' not in state.keys():
        # if wrap has not been set in state, set it
        state['Wrap'] = args_wrap
    else:
        # state already knows about a wrapper
        if args_wrap is not False and args_wrap != state['Wrap']:
            raise CliException("Already wrapped to %s." % state["Wrap"])
    if state['Wrap'] is not False:
        if not isinstance(node_controller, SubprocessNodeController):
            raise CliException("--wrap currently only implemented for "
                               "'subprocess' management type")
        # either args or state have indicated a WrappedNodeController
        if 'ManageWrap' not in state.keys():
            state['ManageWrap'] = None
        node_controller = WrappedNodeController(
            node_controller,
            data_dir=state['Wrap'],
            clean_data_dir=state['ManageWrap'])
        if state['Wrap'] is None:
            state['Wrap'] = node_controller.get_data_dir()
            state['ManageWrap'] = True
        print('{} wrapped to {}'.format(args.cluster_command, state['Wrap']))

    # Return out construction:
    return node_controller
Esempio n. 7
0
def main():
    node_ctrl = None
    try:
        opts = configure(sys.argv[1:])
    except Exception as e:
        print(str(e), file=sys.stderr)
        sys.exit(1)

    try:
        count = opts['count']

        # log_config = NEED
        currency_home = opts['data_dir']
        http_port = int(opts['http_port'])
        gossip_port = int(opts['port'])
        try:
            ledger_type = opts["validator_config"]["LedgerType"]
        except KeyError:
            # None defaults to poet1
            ledger_type = None
        node_ctrl = WrappedNodeController(SubprocessNodeController(),
                                          data_dir=currency_home)
        nodes = []
        for idx in range(count):
            node = NodeArguments("validator-{:0>3}".format(idx),
                                 http_port=http_port + idx,
                                 gossip_port=gossip_port + idx,
                                 ledger_type=ledger_type)
            nodes.append(node)
        currency_home = node_ctrl.get_data_dir()
        if opts['log_config_dict']:
            file_name = 'launcher_cli_global_log_config.js'
            full_name = '{}/etc/{}'.format(currency_home, file_name)
            with open(full_name, 'w') as f:
                f.write(json.dumps(opts['log_config_dict'], indent=4))
            opts['validator_config']['LogConfigFile'] = full_name
        if opts['validator_config']:
            file_name = 'launcher_cli_global_validator_config.js'
            with open('{}/etc/{}'.format(currency_home, file_name), 'w') as f:
                f.write(json.dumps(opts['validator_config'], indent=4))
            for nd in nodes:
                nd.config_files.append(file_name)
        # set up our urls (external interface)
        urls = ['http://localhost:%s' % x.http_port for x in nodes]
        # Make genesis block
        print('creating genesis block...')
        nodes[0].genesis = True
        node_ctrl.create_genesis_block(nodes[0])
        # Launch network (node zero will trigger bootstrapping)
        batch_size = 8
        print('staged-launching network (batch_size: {})...'
              .format(batch_size))
        lower_bound = 0
        while lower_bound < count:
            upper_bound = lower_bound + min(count - lower_bound, batch_size)
            for idx in range(lower_bound, upper_bound):
                print("launching {}".format(nodes[idx].node_name))
                node_ctrl.start(nodes[idx])
            _poll_for_convergence(urls[lower_bound:upper_bound])
            lower_bound = upper_bound
        run_stats(urls[0])
    except KeyboardInterrupt:
        print("\nExiting")
    except ExitError as e:
        # this is an expected error/exit, don't print stack trace -
        # the code raising this exception is expected to have printed the error
        # details
        print("\nFailed!\nExiting: {}".format(e))
    except:
        traceback.print_exc()
        print("\nFailed!\nExiting: {}".format(sys.exc_info()[0]))

    finally:
        if node_ctrl is not None:
            # stop all nodes
            for node_name in node_ctrl.get_node_names():
                node_ctrl.stop(node_name)
            with Progress("terminating network") as p:
                to = TimeOut(16)
                while len(node_ctrl.get_node_names()) > 0:
                    if to.is_timed_out():
                        break
                    time.sleep(1)
                    p.step()
            # force kill anything left over
            for node_name in node_ctrl.get_node_names():
                print("%s still 'up'; sending kill..." % node_name)
                node_ctrl.kill(node_name)
            node_ctrl.archive('launcher')
            node_ctrl.clean()
class SawtoothTestSuite(unittest.TestCase):
    def _do_setup(self, cfg, node_count=5):
        # give defaults to teardown vars
        self._node_ctrl = None
        print('creating', str(self.__class__.__name__))
        # set up our nodes (suite-internal interface)
        self._node_ctrl = WrappedNodeController(
            SubprocessLegacyNodeController())
        temp_dir = self._node_ctrl.get_data_dir()
        file_name = os.path.join(temp_dir, "config.js")
        with open(file_name, 'w') as config:
            config.write(json.dumps(cfg))
        self._nodes = [
            NodeArguments('v%s' % i, 8800 + i, 9000 + i,
                          config_files=[file_name],
                          ledger_type=cfg["LedgerType"])
            for i in range(node_count)]
        # set up our urls (external interface)
        self.urls = ['http://localhost:%s' % x.http_port for x in self._nodes]
        # Make genesis block
        print('creating genesis block...')
        self._nodes[0].genesis = True
        self._node_ctrl.create_genesis_block(self._nodes[0])
        # Launch network (node zero will trigger bootstrapping)
        print('launching network...')
        for x in self._nodes:
            self._node_ctrl.start(x)


    def _do_teardown(self):
        print('destroying', str(self.__class__.__name__))
        if hasattr(self, '_node_ctrl') and self._node_ctrl is not None:
            # Shut down the network
            with Progress("terminating network") as p:
                for node_name in self._node_ctrl.get_node_names():
                    self._node_ctrl.stop(node_name)
                to = TimeOut(16)
                while len(self._node_ctrl.get_node_names()) > 0:
                    if to.is_timed_out():
                        break
                    time.sleep(1)
                    p.step()
            # force kill anything left over
            for node_name in self._node_ctrl.get_node_names():
                try:
                    print("%s still 'up'; sending kill..." % node_name)
                    self._node_ctrl.kill(node_name)
                except Exception as e:
                    print(e.message)
            self._node_ctrl.archive(self.__class__.__name__)
            self._node_ctrl.clean()
Esempio n. 9
0
    def extend_genesis_util(self, overrides):
        print()
        vnm = None
        try:
            self._node_ctrl = None
            print('creating', str(self.__class__.__name__))
            # set up our nodes (suite-internal interface)
            self._node_ctrl = WrappedNodeController(SubprocessNodeController())
            cfg = overrides
            temp_dir = self._node_ctrl.get_data_dir()
            file_name = os.path.join(temp_dir, "config.js")
            with open(file_name, 'w') as config:
                config.write(json.dumps(cfg))
            data_dir = os.path.join(temp_dir, "data")
            gblock_file = genesis_info_file_name(data_dir)

            self._nodes = [
                NodeArguments('v%s' % i, 8800 + i, 9000 + i,
                              config_files=[file_name],
                              ledger_type=overrides["LedgerType"])
                for i in range(2)]
            # set up our urls (external interface)
            self.urls = [
                'http://localhost:%s' % x.http_port for x in self._nodes]
            # Make genesis block
            print('creating genesis block...')
            self.assertFalse(os.path.exists(gblock_file))
            self._nodes[0].genesis = True
            self._node_ctrl.create_genesis_block(self._nodes[0])

            # Test genesis util
            self.assertTrue(os.path.exists(gblock_file))
            genesis_dat = None
            with open(gblock_file, 'r') as f:
                genesis_dat = json.load(f)
            self.assertTrue('GenesisId' in genesis_dat.keys())
            head = genesis_dat['GenesisId']
            # Verify genesis tool efficacy on a minimal network
            # Launch network (node zero will trigger bootstrapping)
            print('launching network...')
            for x in self._nodes:
                self._node_ctrl.start(x)

            # ...verify validator is extending tgt_block
            to = TimeOut(64)
            blk_lists = None
            prog_str = 'testing root extension (expect root: %s)' % head
            with Progress(prog_str) as p:
                print()
                while not to.is_timed_out() and blk_lists is None:
                    try:
                        blk_lists = get_blocklists(['http://localhost:8800'])
                        print('block_lists: %s' % blk_lists)
                        if len(blk_lists) < 1 or len(blk_lists[0]) < 2:
                            blk_lists = None
                    except MessageException as e:
                        pass
                    time.sleep(2)
                    p.step()
            self.assertIsNotNone(blk_lists)
            root = blk_lists[0][0]
            self.assertEqual(head, root)
            # ...verify general convergence
            to = TimeOut(32)
            with Progress('testing root convergence') as p:
                print()
                while (is_convergent(self.urls, tolerance=1, standard=1)
                       is False and not to.is_timed_out()):
                    time.sleep(2)
                    p.step()
            # ...verify convergence on the genesis block
            blk_lists = get_blocklists(['http://localhost:8800'])
            root = blk_lists[0][0]
            self.assertEqual(head, root)
            print('network converged on root: %s' % root)
        finally:
            print('destroying', str(self.__class__.__name__))
            if hasattr(self, '_node_ctrl') and self._node_ctrl is not None:
                # Shut down the network
                with Progress("terminating network") as p:
                    for node_name in self._node_ctrl.get_node_names():
                        self._node_ctrl.stop(node_name)
                    to = TimeOut(16)
                    while len(self._node_ctrl.get_node_names()) > 0:
                        if to.is_timed_out():
                            break
                        time.sleep(1)
                        p.step()
                # force kill anything left over
                for node_name in self._node_ctrl.get_node_names():
                    try:
                        print("%s still 'up'; sending kill..." % node_name)
                        self._node_ctrl.kill(node_name)
                    except Exception as e:
                        print(e.message)
                self._node_ctrl.archive(self.__class__.__name__)
                self._node_ctrl.clean()
class SawtoothTestSuite(unittest.TestCase):
    def _do_setup(self, cfg, node_count=5):
        # give defaults to teardown vars
        self._node_ctrl = None
        print 'creating', str(self.__class__.__name__)
        # set up our nodes (suite-internal interface)
        self._node_ctrl = WrappedNodeController(SubprocessNodeController())
        temp_dir = self._node_ctrl.get_data_dir()
        file_name = os.path.join(temp_dir, "config.js")
        with open(file_name, 'w') as config:
            config.write(json.dumps(cfg))
        self._nodes = [
            NodeArguments('v%s' % i,
                          8800 + i,
                          9000 + i,
                          config_files=[file_name],
                          ledger_type=cfg["LedgerType"])
            for i in range(node_count)
        ]
        # set up our urls (external interface)
        self.urls = ['http://localhost:%s' % x.http_port for x in self._nodes]
        # Make genesis block
        print 'creating genesis block...'
        self._nodes[0].genesis = True
        self._node_ctrl.create_genesis_block(self._nodes[0])
        # Launch network (node zero will trigger bootstrapping)
        print 'launching network...'
        for x in self._nodes:
            self._node_ctrl.start(x)

    def _do_teardown(self):
        print 'destroying', str(self.__class__.__name__)
        if hasattr(self, '_node_ctrl') and self._node_ctrl is not None:
            # Shut down the network
            with Progress("terminating network") as p:
                for node_name in self._node_ctrl.get_node_names():
                    self._node_ctrl.stop(node_name)
                to = TimeOut(16)
                while len(self._node_ctrl.get_node_names()) > 0:
                    if to.is_timed_out():
                        break
                    time.sleep(1)
                    p.step()
            # force kill anything left over
            for node_name in self._node_ctrl.get_node_names():
                try:
                    print "%s still 'up'; sending kill..." % node_name
                    self._node_ctrl.kill(node_name)
                except Exception as e:
                    print e.message
            self._node_ctrl.archive(self.__class__.__name__)
            self._node_ctrl.clean()

    def _poll_for_convergence(self, timeout=256, tolerance=2, standard=5):
        convergent = False
        with Progress('awaiting convergence') as p:
            to = TimeOut(timeout)
            while convergent is False:
                self.assertFalse(to.is_timed_out(),
                                 'timed out awaiting convergence')
                p.step()
                time.sleep(4)
                try:
                    convergent = is_convergent(self.urls,
                                               standard=standard,
                                               tolerance=tolerance)
                except MessageException:
                    pass
        sit_rep(self.urls, verbosity=1)
        return convergent
    def extend_genesis_util(self, overrides):
        print()
        vnm = None
        try:
            self._node_ctrl = None
            print('creating', str(self.__class__.__name__))
            # set up our nodes (suite-internal interface)
            self._node_ctrl = WrappedNodeController(
                SubprocessLegacyNodeController())
            cfg = overrides
            temp_dir = self._node_ctrl.get_data_dir()
            file_name = os.path.join(temp_dir, "config.js")
            with open(file_name, 'w') as config:
                config.write(json.dumps(cfg))
            data_dir = os.path.join(temp_dir, "data")
            gblock_file = genesis_info_file_name(data_dir)

            self._nodes = [
                NodeArguments('v%s' % i, 8800 + i, 9000 + i,
                              config_files=[file_name],
                              ledger_type=overrides["LedgerType"])
                for i in range(2)]
            # set up our urls (external interface)
            self.urls = [
                'http://localhost:%s' % x.http_port for x in self._nodes]
            # Make genesis block
            print('creating genesis block...')
            self.assertFalse(os.path.exists(gblock_file))
            self._nodes[0].genesis = True
            self._node_ctrl.create_genesis_block(self._nodes[0])

            # Test genesis util
            self.assertTrue(os.path.exists(gblock_file))
            genesis_dat = None
            with open(gblock_file, 'r') as f:
                genesis_dat = json.load(f)
            self.assertTrue('GenesisId' in genesis_dat.keys())
            head = genesis_dat['GenesisId']
            # Verify genesis tool efficacy on a minimal network
            # Launch network (node zero will trigger bootstrapping)
            print('launching network...')
            for x in self._nodes:
                self._node_ctrl.start(x)

            # ...verify validator is extending tgt_block
            to = TimeOut(64)
            blk_lists = None
            prog_str = 'testing root extension (expect root: %s)' % head
            with Progress(prog_str) as p:
                print()
                while not to.is_timed_out() and blk_lists is None:
                    try:
                        blk_lists = get_blocklists(['http://localhost:8800'])
                        print('block_lists: %s' % blk_lists)
                        if len(blk_lists) < 1 or len(blk_lists[0]) < 2:
                            blk_lists = None
                    except MessageException as e:
                        pass
                    time.sleep(2)
                    p.step()
            self.assertIsNotNone(blk_lists)
            root = blk_lists[0][0]
            self.assertEqual(head, root)
            # ...verify general convergence
            to = TimeOut(32)
            with Progress('testing root convergence') as p:
                print()
                while (is_convergent(self.urls, tolerance=1, standard=1)
                       is False and not to.is_timed_out()):
                    time.sleep(2)
                    p.step()
            # ...verify convergence on the genesis block
            blk_lists = get_blocklists(['http://localhost:8800'])
            root = blk_lists[0][0]
            self.assertEqual(head, root)
            print('network converged on root: %s' % root)
        finally:
            print('destroying', str(self.__class__.__name__))
            if hasattr(self, '_node_ctrl') and self._node_ctrl is not None:
                # Shut down the network
                with Progress("terminating network") as p:
                    for node_name in self._node_ctrl.get_node_names():
                        self._node_ctrl.stop(node_name)
                    to = TimeOut(16)
                    while len(self._node_ctrl.get_node_names()) > 0:
                        if to.is_timed_out():
                            break
                        time.sleep(1)
                        p.step()
                # force kill anything left over
                for node_name in self._node_ctrl.get_node_names():
                    try:
                        print("%s still 'up'; sending kill..." % node_name)
                        self._node_ctrl.kill(node_name)
                    except Exception as e:
                        print(e.message)
                self._node_ctrl.archive(self.__class__.__name__)
                self._node_ctrl.clean()
Esempio n. 12
0
class SawtoothVnmTestSuite(unittest.TestCase):
    def _do_teardown(self):
        print 'destroying', str(self.__class__.__name__)
        if hasattr(self, '_node_ctrl') and self._node_ctrl is not None:
            # Shut down the network
            with Progress("terminating network") as p:
                for node_name in self._node_ctrl.get_node_names():
                    self._node_ctrl.stop(node_name)
                to = TimeOut(16)
                while len(self._node_ctrl.get_node_names()) > 0:
                    if to.is_timed_out():
                        break
                    time.sleep(1)
                    p.step()
            # force kill anything left over
            for node_name in self._node_ctrl.get_node_names():
                try:
                    print "%s still 'up'; sending kill..." % node_name
                    self._node_ctrl.kill(node_name)
                except Exception as e:
                    print e.message
            self._node_ctrl.clean()

    def _do_setup(self):
        # give defaults to teardown vars
        self._node_ctrl = None
        print 'creating', str(self.__class__.__name__)
        # set up our nodes (suite-internal interface)
        self._nodes = [
            NodeArguments('v%s' % i, 8800 + i, 9000 + i) for i in range(2)
        ]
        # set up our urls (external interface)
        self.urls = ['http://localhost:%s' % x.http_port for x in self._nodes]
        # Make genesis block
        print 'creating genesis block...'
        self._nodes[0].genesis = True
        self._node_ctrl = WrappedNodeController(SubprocessNodeController())
        self._node_ctrl.create_genesis_block(self._nodes[0])
        # Launch network (node zero will trigger bootstrapping)
        print 'launching network...'
        for x in self._nodes:
            self._node_ctrl.start(x)

    def test_suite(self):
        success = False
        try:
            print
            self._do_setup()
            urls = self.urls
            suite = unittest.TestSuite()
            suite.addTest(TestConvergence('test_bootstrap', urls))
            runner = unittest.TextTestRunner()
            result = runner.run(suite)
            if len(result.failures) == 0 and len(result.errors) == 0:
                success = True
        except:
            traceback.print_exc()
            raise
        finally:
            self._do_teardown()
            if success is False:
                self.fail(self.__class__.__name__)