async def test_only_apps_query(self): data_encoder, private_key_to_address users = [('bob{}'.format(i), private_key_to_address(data_encoder(os.urandom(32))), False) for i in range(6)] bots = [('bot{}'.format(i), private_key_to_address(data_encoder(os.urandom(32))), True) for i in range(4)] async with self.pool.acquire() as con: for args in users + bots: await con.execute( "INSERT INTO users (username, toshi_id, is_app) VALUES ($1, $2, $3)", *args) resp = await self.fetch("/search/user?query=bo", method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 10) resp = await self.fetch("/search/user?query=bo&apps=false", method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 6) resp = await self.fetch("/search/user?query=bo&apps=true", method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 4)
async def get_tx_skel(self, from_key, to_addr, val, nonce=None, gas_price=None, gas=None, data=None): from_addr = private_key_to_address(from_key) body = {"from": from_addr, "to": to_addr, "value": val} if nonce is not None: body['nonce'] = nonce if gas_price is not None: body['gasPrice'] = gas_price if gas is not None: body['gas'] = gas if data is not None: body['data'] = data resp = await self.fetch("/tx/skel", method="POST", body=body) self.assertResponseCodeEqual(resp, 200, resp.body) body = json_decode(resp.body) tx = body['tx'] return tx
async def get_tx_skel(self, from_key, to_addr, val, nonce=None, gas_price=None, gas=None, data=None, token_address=None, expected_response_code=200): from_addr = private_key_to_address(from_key) body = { "from": from_addr, "to": to_addr, "value": hex(val) if isinstance(val, int) else val } if nonce is not None: body['nonce'] = nonce if gas_price is not None: body['gasPrice'] = gas_price if gas is not None: body['gas'] = gas if data is not None: body['data'] = data if token_address is not None: body['token_address'] = token_address resp = await self.fetch("/tx/skel", method="POST", body=body) self.assertResponseCodeEqual(resp, expected_response_code, resp.body) if expected_response_code == 200: body = json_decode(resp.body) tx = body['tx'] return tx return None
async def test_username_query(self): username = "******" positive_query = 'Tos' private_key = os.urandom(32) toshi_id = private_key_to_address(private_key) async with self.pool.acquire() as con: await con.execute( "INSERT INTO users (username, name, toshi_id, is_bot, is_public) VALUES ($1, $2, $3, $4, $5)", username, username, toshi_id, True, True) resp = await self.fetch("/search/apps?query={}".format(positive_query), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 0) con = await self.websocket_connect(private_key) resp = await self.fetch("/search/apps?query={}".format(positive_query), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 1)
def __init__(self, name, contract, *, from_key=None, constant=None, return_raw_tx=False): self.name = name self.contract = contract # TODO: forcing const seems to do nothing, since eth_call # will just return a tx_hash (on parity at least) if constant is None: self.is_constant = self.contract.translator.function_data[name][ 'is_constant'] else: # force constantness of this function self.is_constant = constant if from_key: if isinstance(from_key, str): self.from_key = data_decoder(from_key) else: self.from_key = from_key self.from_address = private_key_to_address(from_key) else: self.from_key = None self.from_address = None self.return_raw_tx = return_raw_tx
async def test_apps_vs_public(self): """Make sure if something is marked as being an app it doesn't show up in the public list even if marked with public""" no_of_users_to_generate = 20 insert_vals = [] for i in range(0, no_of_users_to_generate): key = os.urandom(32) name = namegen.get_full_name() username = name.lower().replace(' ', '') insert_vals.append((private_key_to_address(key), username, name, (i / (no_of_users_to_generate - 1)) * 5.0, 10, True, True if i % 2 == 0 else False)) async with self.pool.acquire() as con: await con.executemany( "INSERT INTO users (toshi_id, username, name, reputation_score, review_count, is_public, is_app) VALUES ($1, $2, $3, $4, $5, $6, $7)", insert_vals) resp = await self.fetch("/search/user?limit={}".format(i + 1), method="GET") self.assertEqual(resp.code, 200) results = json_decode(resp.body)['results'] self.assertEqual(len(results), no_of_users_to_generate) resp = await self.fetch("/search/user?public=true&limit={}".format(i + 1), method="GET") self.assertEqual(resp.code, 200) results = json_decode(resp.body)['results'] self.assertEqual(len(results), (i + (1 if i % 2 == 1 else 2)) // 2)
async def test_large_volume_of_txs(self): """Tests that the service can handle a large volume of transactions from different users """ num_of_txs = 10 # create sending user keys from_keys = [os.urandom(32) for _ in range(num_of_txs)] # create receiver user addresses to_addresses = [data_encoder(os.urandom(20)) for _ in range(num_of_txs)] # faucet sending users txs = [] for key in from_keys: addr = private_key_to_address(key) txs.append((await self.send_tx(FAUCET_PRIVATE_KEY, addr, 10 * (10 ** 18)))) # send transactions for key, address in zip(from_keys, to_addresses): txs.append((await self.send_tx(key, address, 10 ** 18))) while True: async with self.pool.acquire() as con: rows = await con.fetch("SELECT status, COUNT(*) FROM transactions WHERE hash = ANY($1) GROUP BY status", txs) s = [] for row in rows: s.append("{}: {}".format(row['status'], row['count'])) if row['status'] == 'confirmed' and row['count'] == len(txs): return if row['status'] == 'queued' and row['count'] == 1: async with self.pool.acquire() as con: row = await con.fetchrow("SELECT * FROM transactions WHERE status = 'queued'") print(row) print(', '.join(s)) await asyncio.sleep(1)
def fetch_signed(self, path, *, signing_key=None, signature=None, timestamp=None, address=None, **kwargs): if not isinstance(path, str) or not path.startswith("/"): # for simplicity's sake, don't accept HTTPRequest objects or external urls in the tests raise Exception("first argument must be path string starting with a / (e.g. /v1/tx)") # find out if there's a path prefix added by get_url prefix = "/{}".format(self.get_url(path).split('/', 3)[-1]).split(path)[0] headers = kwargs.setdefault('headers', tornado.httputil.HTTPHeaders()) if 'body' in kwargs: body = kwargs.pop('body') if isinstance(body, dict): headers['Content-Type'] = "application/json" body = tornado.escape.json_encode(body).encode('utf-8') elif isinstance(body, str): # try and find the charset to use to encode this if 'Content-Type' in headers: idx = headers['Content-Type'].find('charset=') if idx >= 0: charset = headers['Content-Type'][idx + 8:] idx = charset.find(';') if idx >= 0: charset = charset[:idx] else: charset = 'utf-8' else: charset = 'utf-8' # encode to a byte string body = body.encode(charset) elif not isinstance(body, bytes): raise Exception("Unable to handle bodys of type '{}'".format(type(body))) else: body = None method = kwargs.setdefault('method', 'GET').upper() if signing_key is None and (address is None or signature is None): raise Exception("signing_key is required unless address and signature is given") if timestamp is None and signature is not None: raise Exception("timestamp is required if signature is given explicitly") if address is None: address = private_key_to_address(signing_key) if timestamp is None: timestamp = int(time.time()) if signature is None: signature = sign_request(signing_key, method, "{}{}".format(prefix, path), timestamp, body) headers[TOSHI_ID_ADDRESS_HEADER] = address headers[TOSHI_SIGNATURE_HEADER] = signature headers[TOSHI_TIMESTAMP_HEADER] = str(timestamp) # because tornado doesn't like POSTs with body set to None if body is None and method == "POST": body = b"" return self.fetch(path, body=body, **kwargs)
async def test_non_query_search(self): positive_query = 'bot' setup_data = [("ToshiBotA", "toshi bot a", os.urandom(32), True), ("ToshiBotB", "toshi bot b", os.urandom(32), True), ("ToshiBotC", "toshi bot c", os.urandom(32), True), ("ToshiBotD", "toshi bot d", os.urandom(32), True), ("ToshiBotE", "toshi bot e", os.urandom(32), True)] count = 0 sessions = [] for username, name, private_key, featured in setup_data: async with self.pool.acquire() as con: toshi_id = private_key_to_address(private_key) if count > 2: time = datetime.utcnow() - timedelta(minutes=2) else: time = datetime.utcnow() session_id = uuid.uuid4().hex await con.execute( "INSERT INTO users (username, name, toshi_id, featured, is_app, is_public) VALUES ($1, $2, $3, $4, $5, $6)", username, name, toshi_id, featured, True, True) await con.execute( "INSERT INTO websocket_sessions VALUES ($1, $2, $3)", session_id, toshi_id, time) sessions.append((session_id, toshi_id)) count += 1 resp = await self.fetch("/search/apps".format(positive_query), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 5) housekeeping = HousekeepingApplication( config=self._app.config, connection_pool=self._app.connection_pool, delay=1) housekeeping.start() await asyncio.sleep(0.1) resp = await self.fetch("/search/apps".format(positive_query), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 3) async with self.pool.acquire() as con: await con.execute("UPDATE websocket_sessions SET last_seen = $1", datetime.utcnow() - timedelta(minutes=2)) await asyncio.sleep(1) resp = await self.fetch("/search/apps".format(positive_query), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 0)
async def faucet(self, to, value, *, from_private_key=FAUCET_PRIVATE_KEY, startgas=None, gasprice=DEFAULT_GASPRICE, nonce=None, data=b"", wait_on_confirmation=True): if isinstance(from_private_key, str): from_private_key = data_decoder(from_private_key) from_address = private_key_to_address(from_private_key) ethclient = JsonRPCClient(config['ethereum']['url']) to = data_decoder(to) if len(to) not in (20, 0): raise Exception( 'Addresses must be 20 or 0 bytes long (len was {})'.format( len(to))) if nonce is None: nonce = await ethclient.eth_getTransactionCount(from_address) balance = await ethclient.eth_getBalance(from_address) if startgas is None: startgas = await ethclient.eth_estimateGas(from_address, to, data=data, nonce=nonce, value=value, gasprice=gasprice) tx = Transaction(nonce, gasprice, startgas, to, value, data, 0, 0, 0) if balance < (tx.value + (tx.startgas * tx.gasprice)): raise Exception("Faucet doesn't have enough funds") tx.sign(from_private_key) tx_encoded = data_encoder(rlp.encode(tx, Transaction)) tx_hash = await ethclient.eth_sendRawTransaction(tx_encoded) while wait_on_confirmation: resp = await ethclient.eth_getTransactionByHash(tx_hash) if resp is None or resp['blockNumber'] is None: await asyncio.sleep(0.1) else: break if to == b'': print("contract address: {}".format(data_encoder(tx.creates))) return tx_hash
async def test_search_order_by_reputation(self): no_of_users_to_generate = 7 insert_vals = [] for i in range(0, no_of_users_to_generate): key = os.urandom(32) name = "John Smith" username = '******'.format(i) insert_vals.append((private_key_to_address(key), username, name, (i / (no_of_users_to_generate - 1)) * 5.0, 10)) for j in range(i + 1, i + 4): key = os.urandom(32) name = "John Smith" username = '******'.format(j) insert_vals.append((private_key_to_address(key), username, name, (i / (no_of_users_to_generate - 1)) * 5.0, j)) # add some users with no score to make sure # users who haven't been reviewed appear last for k in range(j + 1, j + 2): key = os.urandom(32) username = '******'.format(k) insert_vals.append( (private_key_to_address(key), username, name, None, 0)) async with self.pool.acquire() as con: await con.executemany( "INSERT INTO users (toshi_id, username, name, reputation_score, review_count) VALUES ($1, $2, $3, $4, $5)", insert_vals) resp = await self.fetch("/search/user?query=Smith&limit={}".format(k + 1), method="GET") self.assertEqual(resp.code, 200) results = json_decode(resp.body)['results'] self.assertEqual(len(results), k + 1) # make sure that the highest rated "Smith" is first previous_rating = 5.1 previous_count = None for user in results: rep = 2.01 if user['reputation_score'] is None else user[ 'reputation_score'] self.assertLessEqual(rep, previous_rating) if rep == previous_rating: self.assertLessEqual(user['review_count'], previous_count) previous_count = user['review_count'] previous_rating = rep
async def deploy_contract(self, bytecode, *, from_private_key=FAUCET_PRIVATE_KEY, startgas=None, gasprice=DEFAULT_GASPRICE, wait_on_confirmation=True): if isinstance(from_private_key, str): from_private_key = data_decoder(from_private_key) from_address = private_key_to_address(from_private_key) ethclient = JsonRPCClient(config['ethereum']['url']) nonce = await ethclient.eth_getTransactionCount(from_address) balance = await ethclient.eth_getBalance(from_address) gasestimate = await ethclient.eth_estimateGas(from_address, '', data=bytecode, nonce=nonce, value=0, gasprice=gasprice) if startgas is None: startgas = gasestimate elif gasestimate > startgas: raise Exception( "Estimated gas usage is larger than the provided gas") tx = Transaction(nonce, gasprice, startgas, '', 0, bytecode, 0, 0, 0) if balance < (tx.value + (tx.startgas * tx.gasprice)): raise Exception("Faucet doesn't have enough funds") tx.sign(from_private_key) tx_encoded = data_encoder(rlp.encode(tx, Transaction)) tx_hash = await ethclient.eth_sendRawTransaction(tx_encoded) contract_address = data_encoder(tx.creates) while wait_on_confirmation: resp = await ethclient.eth_getTransactionByHash(tx_hash) if resp is None or resp['blockNumber'] is None: await asyncio.sleep(0.1) else: code = await ethclient.eth_getCode(contract_address) if code == '0x': raise Exception("Failed to deploy contract") break return tx_hash, contract_address
async def test_fulltextsearch(self): no_of_users_to_generate = 100 insert_vals = [(private_key_to_address(os.urandom(32)), "user0", "Bob Smith")] some_bobs = False for i in range(1, no_of_users_to_generate): key = os.urandom(32) while True: name = namegen.get_full_name() # make sure we never generate any user's called bob if 'Bob' in name or 'bob' in name: continue break # give ten of the users a 'bob##' username if i % (no_of_users_to_generate / 10) == 0: some_bobs = True username = '******'.format(i) else: username = '******'.format(i) #resp = await self.fetch_signed( # "/user", method="POST", signing_key=key, # body=body) #self.assertEqual(resp.code, 200) insert_vals.append((private_key_to_address(key), username, name)) async with self.pool.acquire() as con: await con.executemany( "INSERT INTO users (toshi_id, username, name) VALUES ($1, $2, $3)", insert_vals) count = await con.fetchrow("SELECT count(*) FROM users") bobcount = await con.fetchrow( "SELECT count(*) FROM users where username ilike 'bob%'") self.assertTrue(count['count'] > 0) self.assertTrue(bobcount['count'] > 0) self.assertTrue(some_bobs) resp = await self.fetch("/search/user?query=bob", method="GET") self.assertEqual(resp.code, 200) results = json_decode(resp.body)['results'] self.assertTrue(len(results) > 1) # make sure that name is prefered over username self.assertEqual(results[0]['name'], "Bob Smith") self.assertTrue(results[1]['username'].startswith("bob"))
async def test_multiple_websockets(self): username = "******" private_key = os.urandom(32) toshi_id = private_key_to_address(private_key) username2 = "ToshiBot2" private_key2 = os.urandom(32) toshi_id2 = private_key_to_address(private_key2) async with self.pool.acquire() as con: await con.execute( "INSERT INTO users (username, name, toshi_id, is_bot, is_public) VALUES ($1, $2, $3, $4, $5)", username, username, toshi_id, True, True) await con.execute( "INSERT INTO users (username, name, toshi_id, is_bot, is_public) VALUES ($1, $2, $3, $4, $5)", username2, username2, toshi_id2, True, True) resp = await self.fetch("/search/apps", method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 0) cons = [] for _ in range(10): con = await self.websocket_connect(private_key) cons.append(con) async with self.pool.acquire() as con: count = await con.fetchval( "SELECT COUNT(*) FROM websocket_sessions") self.assertEqual(count, len(cons)) resp = await self.fetch("/search/apps", method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 1)
async def connect(self): # find out if there's a path prefix added by get_url path = "/{}".format(self.url.split('/', 3)[-1]) address = private_key_to_address(self.signing_key) timestamp = int(time.time()) signature = sign_request(self.signing_key, "GET", path, timestamp, None) request = tornado.httpclient.HTTPRequest( self.url, headers={ 'User-Agent': 'Toshi-Test-Websocket-Client', TOSHI_ID_ADDRESS_HEADER: address, TOSHI_SIGNATURE_HEADER: signature, TOSHI_TIMESTAMP_HEADER: str(timestamp) }) self.con = await tornado.websocket.websocket_connect(request) return self.con
async def test_users_vs_public(self): """Make sure only apps show up in public searches""" no_of_users_to_generate = 20 insert_vals = [] for i in range(0, no_of_users_to_generate): key = os.urandom(32) name = namegen.get_full_name() username = name.lower().replace(' ', '') insert_vals.append( (private_key_to_address(key), username, name, (i / (no_of_users_to_generate - 1)) * 5.0, 10, True if i % 4 == 0 else False, True if i % 2 == 0 else False)) no_of_apps = (i + (1 if i % 2 == 1 else 2)) // 2 no_of_public_apps = (i + (1 if i % 4 == 1 else 2)) // 4 async with self.pool.acquire() as con: await con.executemany( "INSERT INTO users (toshi_id, username, name, reputation_score, review_count, is_public, is_bot) VALUES ($1, $2, $3, $4, $5, $6, $7)", insert_vals) resp = await self.fetch("/search/user?apps=true&limit={}".format(i + 1), method="GET") self.assertEqual(resp.code, 200) results = json_decode(resp.body)['results'] self.assertEqual(len(results), no_of_apps) for user in results: self.assertTrue(user['is_app']) # make sure apps search only includes public apps by default resp = await self.fetch("/search/apps?limit={}".format(i + 1), method="GET") self.assertEqual(resp.code, 200) results = json_decode(resp.body)['results'] self.assertEqual(len(results), no_of_public_apps) for user in results: self.assertTrue(user['is_app']) self.assertTrue(user['public'])
async def test_non_query_search(self): setup_data = [("ToshiBotA", "toshi bot a", os.urandom(32), True), ("ToshiBotB", "toshi bot b", os.urandom(32), True), ("ToshiBotC", "toshi bot c", os.urandom(32), True), ("ToshiBotD", "toshi bot d", os.urandom(32), True), ("ToshiBotE", "toshi bot e", os.urandom(32), True)] cons = [] for username, name, private_key, featured in setup_data: async with self.pool.acquire() as con: await con.execute( "INSERT INTO users (username, name, toshi_id, featured, is_bot, is_public) VALUES ($1, $2, $3, $4, $5, $6)", username, name, private_key_to_address(private_key), featured, True, True) cons = [] resp = await self.fetch("/search/apps", method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 0) con = await self.websocket_connect(setup_data[0][2]) cons.append(con) resp = await self.fetch("/search/apps", method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 1) for _, _, private_key, _ in setup_data[1:]: con = await self.websocket_connect(private_key) cons.append(con) resp = await self.fetch("/search/apps", method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 5)
async def from_source_code(cls, sourcecode, contract_name, constructor_data=None, *, address=None, deployer_private_key=None, import_mappings=None, libraries=None, optimize=False, deploy=True, cwd=None, wait_for_confirmation=True): if deploy: ethurl = get_url() if address is None and deployer_private_key is None: raise TypeError( "requires either address or deployer_private_key") if address is None and not isinstance(constructor_data, (list, type(None))): raise TypeError( "must supply constructor_data as a list (hint: use [] if args should be empty)" ) args = ['solc', '--combined-json', 'bin,abi'] if libraries: args.extend([ '--libraries', ','.join(['{}:{}'.format(*library) for library in libraries]) ]) if optimize: args.append('--optimize') if import_mappings: args.extend([ "{}={}".format(path, mapping) for path, mapping in import_mappings ]) # check if sourcecode is actually a filename if cwd: filename = os.path.join(cwd, sourcecode) else: filename = sourcecode if os.path.exists(filename): args.append(filename) sourcecode = None else: filename = '<stdin>' process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) output, stderrdata = process.communicate(input=sourcecode) try: output = json_decode(output) except json.JSONDecodeError: if output and stderrdata: output += b'\n' + stderrdata elif stderrdata: output = stderrdata raise Exception("Failed to compile source: {}\n{}\n{}".format( filename, ' '.join(args), output.decode('utf-8'))) try: contract = output['contracts']['{}:{}'.format( filename, contract_name)] except KeyError: print(output) raise abi = json_decode(contract['abi']) # deploy contract translator = ContractTranslator(abi) # fix things that don't have a constructor if not deploy: return Contract(abi=abi, address=address, translator=translator) ethclient = JsonRPCClient(ethurl) if address is not None: # verify there is code at the given address for i in range(10): code = await ethclient.eth_getCode(address) if code == "0x": await asyncio.sleep(1) continue break else: raise Exception("No code found at given address") return Contract(abi=abi, address=address, translator=translator) try: bytecode = data_decoder(contract['bin']) except binascii.Error: print(contract['bin']) raise if constructor_data is not None: constructor_call = translator.encode_constructor_arguments( constructor_data) bytecode += constructor_call if isinstance(deployer_private_key, str): deployer_private_key = data_decoder(deployer_private_key) deployer_address = private_key_to_address(deployer_private_key) nonce = await ethclient.eth_getTransactionCount(deployer_address) balance = await ethclient.eth_getBalance(deployer_address) gasprice = 20000000000 value = 0 startgas = await ethclient.eth_estimateGas(deployer_address, '', data=bytecode, nonce=nonce, value=0, gasprice=gasprice) if balance < (startgas * gasprice): raise Exception("Given account doesn't have enough funds") tx = Transaction(nonce, gasprice, startgas, '', value, bytecode, 0, 0, 0) tx.sign(deployer_private_key) tx_encoded = data_encoder(rlp.encode(tx, Transaction)) contract_address = data_encoder(tx.creates) tx_hash = await ethclient.eth_sendRawTransaction(tx_encoded) # wait for the contract to be deployed while wait_for_confirmation: resp = await ethclient.eth_getTransactionByHash(tx_hash) if resp is None or resp['blockNumber'] is None: await asyncio.sleep(0.1) else: code = await ethclient.eth_getCode(contract_address) if code == '0x': raise Exception( "Failed to deploy contract: resulting address '{}' has no code" .format(contract_address)) break return Contract(abi=abi, address=contract_address, translator=translator, creation_tx_hash=tx_hash)
async def test_search_order_by_reputation_without_query(self): no_of_users_to_generate = 20 insert_vals = [] for i in range(0, no_of_users_to_generate): key = os.urandom(32) name = namegen.get_full_name() username = name.lower().replace(' ', '') insert_vals.append((private_key_to_address(key), username, name, (i / (no_of_users_to_generate - 1)) * 5.0, 10, True if i % 2 == 0 else False)) for j in range(i + 1, i + 4): key = os.urandom(32) name = namegen.get_full_name() username = name.lower().replace(' ', '') insert_vals.append((private_key_to_address(key), username, name, (i / (no_of_users_to_generate - 1)) * 5.0, j, True if j % 2 == 0 else False)) # add some users with no score to make sure # users who haven't been reviewed appear last for k in range(j + 1, j + 7): key = os.urandom(32) name = namegen.get_full_name() username = name.lower().replace(' ', '') insert_vals.append((private_key_to_address(key), username, name, None, 0, True if k % 2 == 0 else False)) async with self.pool.acquire() as con: await con.executemany( "INSERT INTO users (toshi_id, username, name, reputation_score, review_count, is_public) VALUES ($1, $2, $3, $4, $5, $6)", insert_vals) resp = await self.fetch("/search/user?top=true&limit={}".format(k + 1), method="GET") self.assertEqual(resp.code, 200) results = json_decode(resp.body)['results'] self.assertEqual(len(results), k + 1) # make sure that the highest rated is first previous_rating = 5.1 previous_count = None for user in results: rep = 2.01 if user['reputation_score'] is None else user[ 'reputation_score'] self.assertLessEqual(rep, previous_rating) if rep == previous_rating: self.assertLessEqual(user['review_count'], previous_count) previous_count = user['review_count'] previous_rating = rep # check public search resp = await self.fetch( "/search/user?top=true&public=true&limit={}".format(k + 1), method="GET") self.assertEqual(resp.code, 200) results = json_decode(resp.body)['results'] self.assertEqual(len(results), (k + (1 if k % 2 == 1 else 2)) // 2) # make sure that the highest rated is first previous_rating = 5.1 previous_count = None for user in results: self.assertTrue(user['public']) rep = 2.01 if user['reputation_score'] is None else user[ 'reputation_score'] self.assertLessEqual(rep, previous_rating) if rep == previous_rating: self.assertLessEqual(user['review_count'], previous_count) previous_count = user['review_count'] previous_rating = rep
async def test_get_app_index(self): resp = await self.fetch("/apps/", method="GET") self.assertResponseCodeEqual(resp, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 0) setup_data = [ ("ToshiBotA", private_key_to_address(os.urandom(32)), False, True, True), ("ToshiBotB", private_key_to_address(os.urandom(32)), False, True, True), ("FeaturedBotA", private_key_to_address(os.urandom(32)), True, True, True), ("FeaturedBotB", private_key_to_address(os.urandom(32)), True, True, True), ("FeaturedBotC", private_key_to_address(os.urandom(32)), True, True, True), ("NotPublicBotA", private_key_to_address(os.urandom(32)), True, True, False), ("NotPublicBotB", private_key_to_address(os.urandom(32)), False, True, False), ("NotPublicBotC", private_key_to_address(os.urandom(32)), True, True, False), ("NormalUser1", private_key_to_address(os.urandom(32)), False, False, True), ("NormalUser2", private_key_to_address(os.urandom(32)), False, False, False), ("NormalUser3", private_key_to_address(os.urandom(32)), False, False, True), ] for username, addr, featured, is_bot, is_public in setup_data: async with self.pool.acquire() as con: await con.execute( "INSERT INTO users (username, name, toshi_id, is_bot, featured, is_public) VALUES ($1, $2, $3, $4, $5, $6)", username, username, addr, is_bot, featured, is_public) resp = await self.fetch("/apps", method="GET") self.assertResponseCodeEqual(resp, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 5) # test /apps/featured resp = await self.fetch("/apps/featured", method="GET") self.assertResponseCodeEqual(resp, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 3) # ensure we got a tracking event self.assertEqual((await self.next_tracking_event())[0], None) resp = await self.fetch("/apps?featured", method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 3) for true in ['', 'true', 'featured', 'TRUE', 'True']: resp = await self.fetch("/apps?featured={}".format(true), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 3, "Failed to map featured={} to true".format(true)) for false in ['false', 'FALSE', 'False']: resp = await self.fetch("/apps?featured={}".format(false), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual( len(body['results']), 2, "Failed to map featured={} to false".format(false))
async def test_featured_query(self): positive_query = 'bot' setup_data = [ ("ToshiBotA", "toshi bot a", os.urandom(32), False), ("ToshiBotB", "toshi bot b", os.urandom(32), False), ("FeaturedBotA", "featured toshi bot a", os.urandom(32), True), ("FeaturedBotB", "featured toshi bot b", os.urandom(32), True), ("FeaturedBotC", "featured toshi bot c", os.urandom(32), True) ] cons = [] for username, name, private_key, featured in setup_data: async with self.pool.acquire() as con: await con.execute( "INSERT INTO users (username, name, toshi_id, featured, is_bot, is_public) VALUES ($1, $2, $3, $4, $5, $6)", username, name, private_key_to_address(private_key), featured, True, True) con = await self.websocket_connect(private_key) cons.append(con) resp = await self.fetch("/search/apps?query={}".format(positive_query), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 5) resp = await self.fetch( "/search/apps?query={}&featured".format(positive_query), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 3) for con in cons[:3]: con.close() await asyncio.sleep(0.2) resp = await self.fetch( "/search/apps?query={}&featured".format(positive_query), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 2) cons[3].close() await asyncio.sleep(0.2) resp = await self.fetch( "/search/apps?query={}&featured".format(positive_query), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 1) cons[4].close() await asyncio.sleep(0.2) resp = await self.fetch( "/search/apps?query={}&featured".format(positive_query), method="GET") self.assertEqual(resp.code, 200) body = json_decode(resp.body) self.assertEqual(len(body['results']), 0)
from tornado.testing import gen_test from toshieth.test.base import EthServiceBaseTest, requires_full_stack from toshi.test.ethereum.faucet import FAUCET_PRIVATE_KEY, FAUCET_ADDRESS from toshi.ethereum.utils import private_key_to_address, data_decoder from toshi.ethereum.contract import Contract from ethereum.utils import sha3 ABC_TOKEN_ADDRESS = "0x056db290f8ba3250ca64a45d16284d04bc6f5fbf" YAC_TOKEN_ADDRESS = "0x9ab6c6111577c51da46e2c4c93a3622671578657" ARTTOKEN_CONTRACT = open(os.path.join(os.path.dirname(__file__), "arttokencreator.sol")).read().encode('utf-8') TEST_PRIVATE_KEY = data_decoder("0xe8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35") TEST_PRIVATE_KEY_2 = data_decoder("0x8945608e66736aceb34a83f94689b4e98af497ffc9dc2004a93824096330fa77") TEST_ADDRESS = private_key_to_address(TEST_PRIVATE_KEY) TEST_ADDRESS_2 = private_key_to_address(TEST_PRIVATE_KEY_2) TEST_APN_ID = "64be4fe95ba967bb533f0c240325942b9e1f881b5cd2982568a305dd4933e0bd" class FakeIPFSHandler(tornado.web.RequestHandler): def get(self, key): self.write({"properties": { "image": {"description": "http://{}.png".format(key)} }}) class ERC721Test(EthServiceBaseTest): def get_urls(self): return super().get_urls() + [
def __init__(self, signing_key): self.address = private_key_to_address(signing_key) self.signing_key = signing_key