def test_genesis(): for profile in ['frontier']: # fixme olympics config = dict(eth=dict()) # Set config values based on profile selection merge_dict(config, PROFILES[profile]) # Load genesis config update_config_from_genesis_json(config, config['eth']['genesis']) konfig.update_config_with_defaults( config, {'eth': { 'block': blocks.default_config }}) print config['eth'].keys() bc = config['eth']['block'] print bc.keys() env = Env(DB(), bc) genesis = blocks.genesis(env) print 'genesis.hash', genesis.hash.encode('hex') print 'expected', config['eth']['genesis_hash'] assert genesis.hash == config['eth']['genesis_hash'].decode('hex')
def test_genesis_config(): "test setting genesis alloc using the config" alloc = { '1' * 40: { 'wei': 1 }, # wei '2' * 40: { 'balance': 2 }, # balance '3' * 20: { 'balance': 3 }, # 20 bytes } config = dict(eth=dict(genesis=dict(alloc=alloc))) konfig.update_config_with_defaults( config, {'eth': { 'block': blocks.default_config }}) # Load genesis config update_config_from_genesis_json(config, config['eth']['genesis']) bc = config['eth']['block'] pprint(bc) env = Env(DB(), bc) genesis = blocks.genesis(env) for address, value_dict in alloc.items(): value = value_dict.values()[0] assert genesis.get_balance(address) == value
def test_update_config(): conf = config.get_default_config([BaseApp] + base_services) conf_copy = copy.deepcopy(conf) conf2 = config.update_config_with_defaults(conf, dict(p2p=dict(new_key=1))) assert conf is conf2 assert conf == conf2 assert conf_copy != conf
def test_update_config(): conf = config.get_default_config([BaseApp] + base_services) conf_copy = copy.deepcopy(conf) conf2 = config.update_config_with_defaults(conf, dict(p2p=dict(new_key=1))) assert conf is conf2 assert conf == conf2 assert conf_copy != conf
def test_profile(profile): config = dict(eth=dict()) konfig.update_config_with_defaults( config, {'eth': { 'block': blocks.default_config }}) # Set config values based on profile selection merge_dict(config, PROFILES[profile]) # Load genesis config update_config_from_genesis_json(config, config['eth']['genesis']) bc = config['eth']['block'] pprint(bc) env = Env(DB(), bc) genesis = blocks.genesis(env) assert genesis.hash.encode('hex') == config['eth']['genesis_hash']
def setting_config(app, tmpdir, bootstrap_nodes=None): # bootstrap_nodes example: ['enode://288b97262895b1c7ec61cf314c2e2004407d0a5dc77566877aad # 1f2a36659c8b698f4b56fd06c4a0c0bf007b4cfb3e7122d907da3b005fa # 90e724441902eb19e # @192.168.43.149:30303'] config['data_dir'] = str(tmpdir) if bootstrap_nodes is not None: config['p2p']['bootstrap_nodes'] = bootstrap_nodes config['discovery']['bootstrap_nodes'] = bootstrap_nodes config['node'] = {'privkey_hex': encode_hex(mk_random_privkey())} config['pow'] = {'activated': True} config['eth']['network_id'] = 1337 config['eth']['block']['GENESIS_INITIAL_ALLOC'] = { encode_hex(tester.accounts[0]): { 'balance': 10**24 }, encode_hex(tester.accounts[1]): { 'balance': 10**24 }, encode_hex(tester.accounts[2]): { 'balance': 10**24 }, encode_hex(tester.accounts[3]): { 'balance': 10**24 }, } config['p2p']['listen_host'] = '127.0.0.1' services = [ DBService, AccountsService, PeerManager, ChainService, PoWService, Console ] update_config_with_defaults(config, get_default_config([app] + services)) update_config_with_defaults(config, {'eth': {'block': default_config}}) return config, services
def test_genesis(): for profile in ['frontier']: # fixme olympics config = dict(eth=dict()) # Set config values based on profile selection merge_dict(config, PROFILES[profile]) # Load genesis config update_config_from_genesis_json(config, config['eth']['genesis']) konfig.update_config_with_defaults(config, {'eth': {'block': blocks.default_config}}) print config['eth'].keys() bc = config['eth']['block'] print bc.keys() env = Env(DB(), bc) genesis = blocks.genesis(env) print 'genesis.hash', genesis.hash.encode('hex') print 'expected', config['eth']['genesis_hash'] assert genesis.hash == config['eth']['genesis_hash'].decode('hex')
def test_app(tmpdir): config = { 'eth': { 'pruning': -1, 'network_id': 1, 'block': { # reduced difficulty, increased gas limit, allocations to test accounts 'ACCOUNT_INITIAL_NONCE': 0, 'GENESIS_DIFFICULTY': 1, 'BLOCK_DIFF_FACTOR': 2, # greater than difficulty, thus difficulty is constant 'GENESIS_GAS_LIMIT': 3141592, 'GENESIS_INITIAL_ALLOC': { encode_hex(tester.accounts[0]): {'balance': 10 ** 24}, encode_hex(tester.accounts[1]): {'balance': 10 ** 24}, encode_hex(tester.accounts[2]): {'balance': 10 ** 24}, encode_hex(tester.accounts[3]): {'balance': 10 ** 24}, encode_hex(tester.accounts[4]): {'balance': 10 ** 24}, } } } } update_config_with_defaults(config, {'eth': {'block': eth_config.default_config}}) app = AppMock(config=config) app.chain = eth_service.ChainService(app) return app
def test_app(request, tmpdir): class TestApp(EthApp): def start(self): super(TestApp, self).start() log.debug("adding test accounts") # high balance account self.services.accounts.add_account(Account.new("", tester.keys[0]), store=False) # low balance account self.services.accounts.add_account(Account.new("", tester.keys[1]), store=False) # locked account locked_account = Account.new("", tester.keys[2]) locked_account.lock() self.services.accounts.add_account(locked_account, store=False) assert set(acct.address for acct in self.services.accounts) == set(tester.accounts[:3]) def mine_next_block(self): """Mine until a valid nonce is found. :returns: the new head """ log.debug("mining next block") block = self.services.chain.chain.head_candidate delta_nonce = 10 ** 6 for start_nonce in count(0, delta_nonce): bin_nonce, mixhash = mine( block.number, block.difficulty, block.mining_hash, start_nonce=start_nonce, rounds=delta_nonce ) if bin_nonce: break self.services.pow.recv_found_nonce(bin_nonce, mixhash, block.mining_hash) log.debug("block mined") return self.services.chain.chain.head def rpc_request(self, method, *args): """Simulate an incoming JSON RPC request and return the result. Example:: >>> assert test_app.rpc_request('eth_getBalance', '0x' + 'ff' * 20) == '0x0' """ log.debug("simulating rpc request", method=method) method = self.services.jsonrpc.dispatcher.get_method(method) res = method(*args) log.debug("got response", response=res) return res # genesis block with reduced difficulty, increased gas limit, and allocations to test accounts genesis_block = { "nonce": "0x0000000000000042", "difficulty": "0x1", "alloc": { tester.accounts[0].encode("hex"): {"balance": 10 ** 24}, tester.accounts[1].encode("hex"): {"balance": 1}, tester.accounts[2].encode("hex"): {"balance": 10 ** 24}, }, "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", "timestamp": "0x00", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "extraData": "0x", "gasLimit": "0x2fefd8", } genesis_block_file = tmpdir.join("test_genesis_block.json") genesis_block_file.write(json.dumps(genesis_block)) config = { "data_dir": str(tmpdir), "db": {"implementation": "EphemDB"}, "pow": {"activated": False}, "p2p": {"min_peers": 0, "max_peers": 0, "listen_port": 29873}, "node": {"privkey_hex": mk_random_privkey().encode("hex")}, "discovery": {"boostrap_nodes": [], "listen_port": 29873}, "eth": {"genesis": str(genesis_block_file), "block": ethereum.config.default_config}, "jsonrpc": {"listen_port": 29873}, } services = [DBService, AccountsService, PeerManager, ChainService, PoWService, JSONRPCServer] update_config_with_defaults(config, get_default_config([TestApp] + services)) app = TestApp(config) for service in services: service.register_with_app(app) def fin(): log.debug("stopping test app") app.stop() request.addfinalizer(fin) log.debug("starting test app") app.start() return app
def test_app(request, tmpdir): class TestApp(EthApp): def start(self): super(TestApp, self).start() log.debug('adding test accounts') # high balance account self.services.accounts.add_account(Account.new('', tester.keys[0]), store=False) # low balance account self.services.accounts.add_account(Account.new('', tester.keys[1]), store=False) # locked account locked_account = Account.new('', tester.keys[2]) locked_account.lock() self.services.accounts.add_account(locked_account, store=False) assert set(acct.address for acct in self.services.accounts) == set( tester.accounts[:3]) def mine_next_block(self): """Mine until a valid nonce is found. :returns: the new head """ log.debug('mining next block') block = self.services.chain.chain.head_candidate delta_nonce = 10**6 for start_nonce in count(0, delta_nonce): bin_nonce, mixhash = mine(block.number, block.difficulty, block.mining_hash, start_nonce=start_nonce, rounds=delta_nonce) if bin_nonce: break self.services.pow.recv_found_nonce(bin_nonce, mixhash, block.mining_hash) log.debug('block mined') return self.services.chain.chain.head def rpc_request(self, method, *args): """Simulate an incoming JSON RPC request and return the result. Example:: >>> assert test_app.rpc_request('eth_getBalance', '0x' + 'ff' * 20) == '0x0' """ log.debug('simulating rpc request', method=method) method = self.services.jsonrpc.dispatcher.get_method(method) res = method(*args) log.debug('got response', response=res) return res # genesis block with reduced difficulty, increased gas limit, and allocations to test accounts genesis_block = { "nonce": "0x0000000000000042", "difficulty": "0x1", "alloc": { tester.accounts[0].encode('hex'): { 'balance': 10**24 }, tester.accounts[1].encode('hex'): { 'balance': 1 }, tester.accounts[2].encode('hex'): { 'balance': 10**24 }, }, "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", "timestamp": "0x00", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "extraData": "0x", "gasLimit": "0x2fefd8" } genesis_block_file = tmpdir.join('test_genesis_block.json') genesis_block_file.write(json.dumps(genesis_block)) config = { 'data_dir': str(tmpdir), 'db': { 'implementation': 'EphemDB' }, 'pow': { 'activated': False }, 'p2p': { 'min_peers': 0, 'max_peers': 0, 'listen_port': 29873 }, 'node': { 'privkey_hex': mk_random_privkey().encode('hex') }, 'discovery': { 'boostrap_nodes': [], 'listen_port': 29873 }, 'eth': { 'genesis': str(genesis_block_file), 'block': ethereum.config.default_config }, 'jsonrpc': { 'listen_port': 29873 } } services = [ DBService, AccountsService, PeerManager, ChainService, PoWService, JSONRPCServer ] update_config_with_defaults(config, get_default_config([TestApp] + services)) app = TestApp(config) for service in services: service.register_with_app(app) def fin(): log.debug('stopping test app') app.stop() request.addfinalizer(fin) log.debug('starting test app') app.start() return app
def test_app(tmpdir): class TestApp(EthApp): def start(self): super(TestApp, self).start() log.debug('adding test accounts') # high balance account self.services.accounts.add_account(Account.new( 'Andy', tester.keys[0]), store=False) # low balance account self.services.accounts.add_account(Account.new( 'Choi', tester.keys[1]), store=False) # locked account locked_account = Account.new('Joseph', tester.keys[2]) locked_account.lock() self.services.accounts.add_account(locked_account, store=False) assert set(acct.address for acct in self.services.accounts) == set( tester.accounts[:3]) def mine_next_block(self): """Mine until a valid nonce is found. :returns: the new head """ log.debug('mining next block') block = self.services.chain.head_candidate chain = self.services.chain.chain head_number = chain.head.number delta_nonce = 10**6 for start_nonce in count(0, delta_nonce): bin_nonce, mixhash = mine(block.number, block.difficulty, block.mining_hash, start_nonce=start_nonce, rounds=delta_nonce) if bin_nonce: break self.services.pow.recv_found_nonce(bin_nonce, mixhash, block.mining_hash) if len(chain.time_queue) > 0: # If we mine two blocks within one second, pyethereum will # force the new block's timestamp to be in the future (see # ethereum1_setup_block()), and when we try to add that block # to the chain (via Chain.add_block()), it will be put in a # queue for later processing. Since we need to ensure the # block has been added before we continue the test, we # have to manually process the time queue. log.debug('block mined too fast, processing time queue') chain.process_time_queue(new_time=block.timestamp) log.debug('block mined') # assert chain.head.difficulty == 400 assert chain.head.number == head_number + 1 return chain.head config = { 'data_dir': str(tmpdir), 'db': { 'implementation': 'EphemDB' }, 'pow': { 'activated': False }, 'p2p': { 'min_peers': 1, 'max_peers': 3, 'listen_port': 30303, 'bootstrap_nodes': [ 'enode://94dd98401cf6ca0418580bb77ad0606a35ae8f442b22ab0f81011d8d2c78e70ff779c1d53d015640d79a13f0be99161ae3ff3adb60633ca03a7b542cbe116882@192.168.219.105:30303' ] }, 'node': { 'privkey_hex': '091bd6067cb4612df85d9c1ff85cc47f259ced4d4cd99816b14f35650f59c322' }, #encode_hex(mk_random_privkey())}, 'discovery': { 'bootstrap_nodes': [ 'enode://94dd98401cf6ca0418580bb77ad0606a35ae8f442b22ab0f81011d8d2c78e70ff779c1d53d015640d79a13f0be99161ae3ff3adb60633ca03a7b542cbe116882@192.168.219.105:30303' ], 'listen_port': 30303 }, 'eth': { 'block': { # reduced difficulty, increased gas limit, allocations to test accounts 'GENESIS_DIFFICULTY': 400, 'BLOCK_DIFF_FACTOR': 500, # greater than difficulty, thus difficulty is constant 'GENESIS_GAS_LIMIT': 3141592, 'GENESIS_INITIAL_ALLOC': { encode_hex(tester.accounts[0]): { 'balance': 10**24 }, encode_hex(tester.accounts[1]): { 'balance': 1 }, encode_hex(tester.accounts[2]): { 'balance': 10**24 }, } } }, 'jsonrpc': { 'listen_port': 30303 } } services = [ DBService, AccountsService, PeerManager, ChainService, PoWService, Console ] update_config_with_defaults(config, get_default_config([TestApp] + services)) update_config_with_defaults( config, {'eth': { 'block': ethereum.config.default_config }}) config['eth']['network_id'] = 1337 config['p2p']['listen_host'] = '192.168.0.3' config['discovery']['listen_host'] = '192.168.0.3' app = TestApp(config) for service in services: service.register_with_app(app) def fin(): log.debug('stopping test app') app.stop() log.debug('starting test app') app.start() return app
def test_app(request, tmpdir): class TestTransport(object): def __init__(self, call_func): self.call_func = call_func def send_message(self, request): request = json.loads(request) method = request.get('method') args = request.get('params') if not args: return self.call_func(method) else: return self.call_func(method, *args) class TestApp(EthApp): def start(self): super(TestApp, self).start() log.debug('adding test accounts') # high balance account self.services.accounts.add_account(Account.new('', tester.keys[0]), store=False) log.debug('added unlocked account %s' % tester.keys[0]) # low balance account self.services.accounts.add_account(Account.new('', tester.keys[1]), store=False) log.debug('added unlocked account %s' % tester.keys[1]) # locked account locked_account = Account.new('', tester.keys[2]) locked_account.lock() log.debug('added locked account %s' % tester.keys[1]) self.services.accounts.add_account(locked_account, store=False) self.privkey = None assert set(acct.address for acct in self.services.accounts) == set( tester.accounts[:3]) test_transport = TestTransport(call_func=self.rpc_request) self.client = JSONRPCClient(transport=test_transport) def mine_next_block(self): """Mine until a valid nonce is found. :returns: the new head """ log.debug('mining next block') chain = self.services.chain.chain head_number = chain.head.number block = self.services.chain.head_candidate delta_nonce = 10**6 for start_nonce in count(0, delta_nonce): bin_nonce, mixhash = mine(block.number, block.difficulty, block.mining_hash, start_nonce=start_nonce, rounds=delta_nonce) if bin_nonce: break self.services.pow.recv_found_nonce(bin_nonce, mixhash, block.mining_hash) if len(chain.time_queue) > 0: # If we mine two blocks within one second, pyethereum will # force the new block's timestamp to be in the future (see # ethereum1_setup_block()), and when we try to add that block # to the chain (via Chain.add_block()), it will be put in a # queue for later processing. Since we need to ensure the # block has been added before we continue the test, we # have to manually process the time queue. log.debug('block mined too fast, processing time queue') chain.process_time_queue(new_time=block.timestamp) log.debug('block mined') assert chain.head.difficulty == 1 assert chain.head.number == head_number + 1 return chain.head def rpc_request(self, method, *args, **kwargs): """Simulate an incoming JSON RPC request and return the result. Example:: >>> assert test_app.rpc_request('eth_getBalance', '0x' + 'ff' * 20) == '0x0' """ log.debug('simulating rpc request', method=method, call_args=args, call_kwargs=kwargs) method = self.services.jsonrpc.dispatcher.get_method(method) res = method(*args, **kwargs) log.debug('got response', response=res) return json.dumps( dict(result=res, jsonrpc=JSONRPCProtocol.JSON_RPC_VERSION, id=42)) config = { 'data_dir': str(tmpdir), 'db': { 'implementation': 'EphemDB' }, 'pow': { 'activated': False }, 'p2p': { 'min_peers': 0, 'max_peers': 0, 'listen_port': 29873 }, 'node': { 'privkey_hex': encode_hex(mk_random_privkey()) }, 'discovery': { 'boostrap_nodes': [], 'listen_port': 29873 }, 'eth': { 'block': { # reduced difficulty, increased gas limit, allocations to test accounts 'ACCOUNT_INITIAL_NONCE': request.param, 'GENESIS_DIFFICULTY': 1, 'BLOCK_DIFF_FACTOR': 2, # greater than difficulty, thus difficulty is constant 'GENESIS_GAS_LIMIT': 3141592, 'GENESIS_INITIAL_ALLOC': { encode_hex(tester.accounts[0]): { 'balance': 10**24 }, encode_hex(tester.accounts[1]): { 'balance': 1 }, encode_hex(tester.accounts[2]): { 'balance': 10**24 }, } } }, 'jsonrpc': { 'listen_port': 4488, 'listen_host': '127.0.0.1' } } services = [ DBService, AccountsService, PeerManager, ChainService, PoWService, JSONRPCServer ] update_config_with_defaults(config, get_default_config([TestApp] + services)) update_config_with_defaults( config, {'eth': { 'block': ethereum.config.default_config }}) app = TestApp(config) for service in services: service.register_with_app(app) def fin(): log.debug('stopping test app') for service in app.services: gevent.sleep(.1) try: app.services[service].stop() except Exception as e: log.DEV(str(e), exc_info=e) pass app.stop() gevent.killall(task for task in gc.get_objects() if isinstance(task, gevent.Greenlet)) request.addfinalizer(fin) log.debug('starting test app') app.start() return app
def test_app(request, tmpdir): class TestApp(EthApp): def start(self): super(TestApp, self).start() log.debug('adding test accounts') # high balance account self.services.accounts.add_account(Account.new('', tester.keys[0]), store=False) # low balance account self.services.accounts.add_account(Account.new('', tester.keys[1]), store=False) # locked account locked_account = Account.new('', tester.keys[2]) locked_account.lock() self.services.accounts.add_account(locked_account, store=False) assert set(acct.address for acct in self.services.accounts) == set( tester.accounts[:3]) def mine_next_block(self): """Mine until a valid nonce is found. :returns: the new head """ log.debug('mining next block') block = self.services.chain.head_candidate chain = self.services.chain.chain head_number = chain.head.number delta_nonce = 10**6 for start_nonce in count(0, delta_nonce): bin_nonce, mixhash = mine(block.number, block.difficulty, block.mining_hash, start_nonce=start_nonce, rounds=delta_nonce) if bin_nonce: break self.services.pow.recv_found_nonce(bin_nonce, mixhash, block.mining_hash) if len(chain.time_queue) > 0: # If we mine two blocks within one second, pyethereum will # force the new block's timestamp to be in the future (see # ethereum1_setup_block()), and when we try to add that block # to the chain (via Chain.add_block()), it will be put in a # queue for later processing. Since we need to ensure the # block has been added before we continue the test, we # have to manually process the time queue. log.debug('block mined too fast, processing time queue') chain.process_time_queue(new_time=block.timestamp) log.debug('block mined') assert chain.head.difficulty == 1 assert chain.head.number == head_number + 1 return chain.head config = { 'data_dir': str(tmpdir), 'db': { 'implementation': 'EphemDB' }, 'pow': { 'activated': False }, 'p2p': { 'min_peers': 0, 'max_peers': 0, 'listen_port': 29873 }, 'node': { 'privkey_hex': encode_hex(mk_random_privkey()) }, 'discovery': { 'boostrap_nodes': [], 'listen_port': 29873 }, 'eth': { 'block': { # reduced difficulty, increased gas limit, allocations to test accounts 'GENESIS_DIFFICULTY': 1, 'BLOCK_DIFF_FACTOR': 2, # greater than difficulty, thus difficulty is constant 'GENESIS_GAS_LIMIT': 3141592, 'GENESIS_INITIAL_ALLOC': { encode_hex(tester.accounts[0]): { 'balance': 10**24 }, encode_hex(tester.accounts[1]): { 'balance': 1 }, encode_hex(tester.accounts[2]): { 'balance': 10**24 }, } } }, 'jsonrpc': { 'listen_port': 29873 } } services = [ DBService, AccountsService, PeerManager, ChainService, PoWService, Console ] update_config_with_defaults(config, get_default_config([TestApp] + services)) update_config_with_defaults( config, {'eth': { 'block': ethereum.config.default_config }}) app = TestApp(config) for service in services: service.register_with_app(app) def fin(): log.debug('stopping test app') app.stop() request.addfinalizer(fin) log.debug('starting test app') app.start() return app
def test_app(request, tmpdir): class TestApp(EthApp): def start(self): super(TestApp, self).start() log.debug('adding test accounts') # high balance account self.services.accounts.add_account(Account.new('', tester.keys[0]), store=False) # low balance account self.services.accounts.add_account(Account.new('', tester.keys[1]), store=False) # locked account locked_account = Account.new('', tester.keys[2]) locked_account.lock() self.services.accounts.add_account(locked_account, store=False) assert set(acct.address for acct in self.services.accounts) == set( tester.accounts[:3]) def mine_next_block(self): """Mine until a valid nonce is found. :returns: the new head """ log.debug('mining next block') block = self.services.chain.chain.head_candidate delta_nonce = 10**6 for start_nonce in count(0, delta_nonce): bin_nonce, mixhash = mine(block.number, block.difficulty, block.mining_hash, start_nonce=start_nonce, rounds=delta_nonce) if bin_nonce: break self.services.pow.recv_found_nonce(bin_nonce, mixhash, block.mining_hash) log.debug('block mined') assert self.services.chain.chain.head.difficulty == 1 return self.services.chain.chain.head config = { 'data_dir': str(tmpdir), 'db': { 'implementation': 'EphemDB' }, 'pow': { 'activated': False }, 'p2p': { 'min_peers': 0, 'max_peers': 0, 'listen_port': 29873 }, 'node': { 'privkey_hex': mk_random_privkey().encode('hex') }, 'discovery': { 'boostrap_nodes': [], 'listen_port': 29873 }, 'eth': { 'block': { # reduced difficulty, increased gas limit, allocations to test accounts 'GENESIS_DIFFICULTY': 1, 'BLOCK_DIFF_FACTOR': 2, # greater than difficulty, thus difficulty is constant 'GENESIS_GAS_LIMIT': 3141592, 'GENESIS_INITIAL_ALLOC': { tester.accounts[0].encode('hex'): { 'balance': 10**24 }, tester.accounts[1].encode('hex'): { 'balance': 1 }, tester.accounts[2].encode('hex'): { 'balance': 10**24 }, } } }, 'jsonrpc': { 'listen_port': 29873 } } services = [ DBService, AccountsService, PeerManager, ChainService, PoWService, Console ] update_config_with_defaults(config, get_default_config([TestApp] + services)) update_config_with_defaults( config, {'eth': { 'block': ethereum.config.default_config }}) app = TestApp(config) for service in services: service.register_with_app(app) def fin(): log.debug('stopping test app') app.stop() request.addfinalizer(fin) log.debug('starting test app') app.start() return app