def test_delete_utilized_tag( rotkehlchen_api_server, number_of_eth_accounts, ): """ Test that deleting a tag that is already utilized by an account also removes it from the account""" rotki = rotkehlchen_api_server.rest_api.rotkehlchen # Add two tags tag1 = { 'name': 'public', 'description': 'My public accounts', 'background_color': 'ffffff', 'foreground_color': '000000', } response = requests.put( api_url_for( rotkehlchen_api_server, 'tagsresource', ), json=tag1, ) assert_proper_response(response) tag2 = { 'name': 'desktop', 'description': 'Accounts that are stored in the desktop PC', 'background_color': '000000', 'foreground_color': 'ffffff', } response = requests.put( api_url_for( rotkehlchen_api_server, 'tagsresource', ), json=tag2, ) assert_proper_response(response) # Now add 2 accounts both of them using the above tags new_btc_accounts = [UNIT_BTC_ADDRESS1, UNIT_BTC_ADDRESS2] btc_balances = ['10000', '500500000'] setup = setup_balances( rotki, ethereum_accounts=None, btc_accounts=new_btc_accounts, eth_balances=None, token_balances=None, btc_balances=btc_balances, ) accounts_data = [{ "address": new_btc_accounts[0], "label": 'my btc miner', 'tags': ['public', 'desktop'], }, { "address": new_btc_accounts[1], 'label': 'other account', 'tags': ['desktop'], }] with setup.bitcoin_patch: response = requests.put(api_url_for( rotkehlchen_api_server, "blockchainsaccountsresource", blockchain='BTC', ), json={'accounts': accounts_data}) assert_proper_response(response) assert_btc_balances_result( json_data=response.json(), btc_accounts=new_btc_accounts, btc_balances=btc_balances, also_eth=False, ) # Now delete the tag used by both accounts delete_tag_data = { 'name': 'desktop', } response = requests.delete( api_url_for( rotkehlchen_api_server, "tagsresource", ), json=delete_tag_data, ) assert_proper_response(response) data = response.json() assert len(data['result']) == 1 assert data['result']['public'] is not None # Now check the DB directly and see that tag mappings of the deleted tag are gone cursor = rotki.data.db.conn.cursor() query = cursor.execute( 'SELECT object_reference, tag_name FROM tag_mappings;').fetchall() assert len(query) == 1 assert query[0][0] == UNIT_BTC_ADDRESS1 assert query[0][1] == 'public'
def test_multiple_balance_queries_not_concurrent( rotkehlchen_api_server_with_exchanges, ethereum_accounts, btc_accounts, separate_blockchain_calls, ): """Test multiple different balance query requests happening concurrently This tests that if multiple balance query requests happen concurrently we do not end up doing them multiple times, but reuse the results thanks to cache. Try running both all blockchain balances in one call and each blockchain call separately. """ rotki = rotkehlchen_api_server_with_exchanges.rest_api.rotkehlchen setup = setup_balances(rotki, ethereum_accounts, btc_accounts) multieth_balance_patch = patch.object( rotki.chain_manager.ethereum, 'get_multieth_balance', wraps=rotki.chain_manager.ethereum.get_multieth_balance, ) btc_balances_patch = patch( 'rotkehlchen.chain.manager.get_bitcoin_addresses_balances', wraps=get_bitcoin_addresses_balances, ) binance = rotki.exchange_manager.connected_exchanges['binance'] binance_querydict_patch = patch.object(binance, 'api_query_dict', wraps=binance.api_query_dict) # Test all balances request by requesting to not save the data with ExitStack() as stack: setup.enter_all_patches(stack) eth = stack.enter_context(multieth_balance_patch) btc = stack.enter_context(btc_balances_patch) bn = stack.enter_context(binance_querydict_patch) response = requests.get( api_url_for( rotkehlchen_api_server_with_exchanges, "allbalancesresource", ), json={'async_query': True}, ) task_id_all = assert_ok_async_response(response) response = requests.get(api_url_for( rotkehlchen_api_server_with_exchanges, "named_exchanges_balances_resource", name='binance', ), json={'async_query': True}) task_id_one_exchange = assert_ok_async_response(response) if separate_blockchain_calls: response = requests.get(api_url_for( rotkehlchen_api_server_with_exchanges, "blockchainbalancesresource", ), json={ 'async_query': True, 'blockchain': 'ETH' }) task_id_blockchain_eth = assert_ok_async_response(response) response = requests.get(api_url_for( rotkehlchen_api_server_with_exchanges, "blockchainbalancesresource", ), json={ 'async_query': True, 'blockchain': 'BTC' }) task_id_blockchain_btc = assert_ok_async_response(response) else: response = requests.get(api_url_for( rotkehlchen_api_server_with_exchanges, "blockchainbalancesresource", ), json={'async_query': True}) task_id_blockchain = assert_ok_async_response(response) outcome_all = wait_for_async_task_with_result( rotkehlchen_api_server_with_exchanges, task_id_all, timeout=ASYNC_TASK_WAIT_TIMEOUT * 2, ) outcome_one_exchange = wait_for_async_task( rotkehlchen_api_server_with_exchanges, task_id_one_exchange, timeout=ASYNC_TASK_WAIT_TIMEOUT * 2, ) if separate_blockchain_calls: outcome_eth = wait_for_async_task_with_result( rotkehlchen_api_server_with_exchanges, task_id_blockchain_eth, timeout=ASYNC_TASK_WAIT_TIMEOUT * 2, ) outcome_btc = wait_for_async_task_with_result( rotkehlchen_api_server_with_exchanges, task_id_blockchain_btc, timeout=ASYNC_TASK_WAIT_TIMEOUT * 2, ) else: outcome_blockchain = wait_for_async_task_with_result( rotkehlchen_api_server_with_exchanges, task_id_blockchain, timeout=ASYNC_TASK_WAIT_TIMEOUT * 2, ) assert eth.call_count == 1, 'eth balance query should only fire once' assert btc.call_count == 1, 'btc balance query should only happen once' assert bn.call_count == 3, 'binance balance query should do 2 calls' assert_all_balances( result=outcome_all, db=rotki.data.db, expected_data_in_db=True, setup=setup, ) assert_binance_balances_result(outcome_one_exchange['result']) if not separate_blockchain_calls: outcome_eth = outcome_blockchain outcome_btc = outcome_blockchain assert_eth_balances_result( rotki=rotki, result=outcome_eth, eth_accounts=ethereum_accounts, eth_balances=setup.eth_balances, token_balances=setup.token_balances, also_btc=not separate_blockchain_calls, ) assert_btc_balances_result( result=outcome_btc, btc_accounts=btc_accounts, btc_balances=setup.btc_balances, also_eth=not separate_blockchain_calls, )
def test_remove_blockchain_accounts_async( rotkehlchen_api_server, ethereum_accounts, btc_accounts, number_of_eth_accounts, ): """A simpler version of the above test for removing blockchain accounts for async The main purpose of this test is to see that querying the endpoint asynchronously also works""" # Disable caching of query results rotki = rotkehlchen_api_server.rest_api.rotkehlchen rotki.blockchain.cache_ttl_secs = 0 # Test by having balances queried before removing an account removed_eth_accounts = [ethereum_accounts[0], ethereum_accounts[2]] eth_accounts_after_removal = [ethereum_accounts[1], ethereum_accounts[3]] all_eth_balances = ['1000000', '2000000', '3000000', '4000000'] token_balances = {'RDN': ['0', '250000000', '450000000', '0']} eth_balances_after_removal = ['2000000', '4000000'] token_balances_after_removal = {'RDN': ['250000000', '0']} setup = setup_balances( rotki, ethereum_accounts=ethereum_accounts, btc_accounts=btc_accounts, eth_balances=all_eth_balances, token_balances=token_balances, ) with setup.etherscan_patch, setup.bitcoin_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "blockchainbalancesresource", )) setup = setup_balances( rotki, ethereum_accounts=ethereum_accounts, btc_accounts=btc_accounts, eth_balances=all_eth_balances, token_balances=token_balances, ) # The application has started with 4 ethereum accounts. Remove two and see that balances match with setup.etherscan_patch: response = requests.delete(api_url_for( rotkehlchen_api_server, "blockchainsaccountsresource", blockchain='ETH', ), json={ 'accounts': removed_eth_accounts, 'async_query': True }) task_id = assert_ok_async_response(response) outcome = wait_for_async_task(rotkehlchen_api_server, task_id) assert_eth_balances_result( rotki=rotki, json_data=outcome, eth_accounts=eth_accounts_after_removal, eth_balances=eth_balances_after_removal, token_balances=token_balances_after_removal, also_btc=True, # We queried all balances at the start ) # Also make sure they are removed from the DB accounts = rotki.data.db.get_blockchain_accounts() assert len(accounts.eth) == 2 assert all(acc in accounts.eth for acc in eth_accounts_after_removal) assert len(accounts.btc) == 2 assert all(acc in accounts.btc for acc in btc_accounts) # Now try to query all balances to make sure the result is the stored with setup.etherscan_patch, setup.bitcoin_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "blockchainbalancesresource", )) assert_proper_response(response) json_data = response.json() assert json_data['message'] == '' assert_eth_balances_result( rotki=rotki, json_data=json_data, eth_accounts=eth_accounts_after_removal, eth_balances=eth_balances_after_removal, token_balances=token_balances_after_removal, also_btc=True, ) # Now we will try to remove a BTC account. Setup the mocking infrastructure again all_btc_accounts = [UNIT_BTC_ADDRESS1, UNIT_BTC_ADDRESS2] btc_accounts_after_removal = [UNIT_BTC_ADDRESS2] setup = setup_balances( rotki, ethereum_accounts=eth_accounts_after_removal, btc_accounts=all_btc_accounts, eth_balances=eth_balances_after_removal, token_balances=token_balances_after_removal, btc_balances=['3000000', '5000000'], ) # remove the new BTC account with setup.bitcoin_patch: response = requests.delete(api_url_for( rotkehlchen_api_server, "blockchainsaccountsresource", blockchain='BTC', ), json={ 'accounts': [UNIT_BTC_ADDRESS1], 'async_query': True }) task_id = assert_ok_async_response(response) outcome = wait_for_async_task(rotkehlchen_api_server, task_id) assert_btc_balances_result( json_data=outcome, btc_accounts=btc_accounts_after_removal, btc_balances=['5000000'], also_eth=True, ) # Also make sure it's removed from the DB accounts = rotki.data.db.get_blockchain_accounts() assert len(accounts.eth) == 2 assert all(acc in accounts.eth for acc in eth_accounts_after_removal) assert len(accounts.btc) == 1 assert all(acc in accounts.btc for acc in btc_accounts_after_removal) # Now try to query all balances to make sure the result is also stored with setup.etherscan_patch, setup.bitcoin_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "blockchainbalancesresource", )) assert_proper_response(response) json_data = response.json() assert json_data['message'] == '' assert_btc_balances_result( json_data=json_data, btc_accounts=btc_accounts_after_removal, btc_balances=['5000000'], also_eth=True, )
def test_remove_blockchain_accounts( rotkehlchen_api_server, ethereum_accounts, btc_accounts, number_of_eth_accounts, query_balances_before_first_modification, ): """Test that the endpoint removing blockchain accounts works properly""" # Disable caching of query results rotki = rotkehlchen_api_server.rest_api.rotkehlchen rotki.blockchain.cache_ttl_secs = 0 removed_eth_accounts = [ethereum_accounts[0], ethereum_accounts[2]] eth_accounts_after_removal = [ethereum_accounts[1], ethereum_accounts[3]] all_eth_balances = ['1000000', '2000000', '3000000', '4000000'] token_balances = {'RDN': ['0', '0', '450000000', '0']} eth_balances_after_removal = ['2000000', '4000000'] token_balances_after_removal = {'RDN': ['0', '0']} if query_balances_before_first_modification: # Also test by having balances queried before removing an account setup = setup_balances( rotki, ethereum_accounts=ethereum_accounts, btc_accounts=btc_accounts, eth_balances=all_eth_balances, token_balances=token_balances, ) with setup.etherscan_patch, setup.bitcoin_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "blockchainbalancesresource", )) setup = setup_balances( rotki, ethereum_accounts=ethereum_accounts, btc_accounts=btc_accounts, eth_balances=all_eth_balances, token_balances=token_balances, ) # The application has started with 4 ethereum accounts. Remove two and see that balances match with setup.etherscan_patch: response = requests.delete(api_url_for( rotkehlchen_api_server, "blockchainsaccountsresource", blockchain='ETH', ), json={'accounts': removed_eth_accounts}) assert_proper_response(response) json_data = response.json() assert json_data['message'] == '' assert_eth_balances_result( rotki=rotki, json_data=json_data, eth_accounts=eth_accounts_after_removal, eth_balances=eth_balances_after_removal, token_balances=token_balances_after_removal, also_btc=query_balances_before_first_modification, ) # Also make sure they are removed from the DB accounts = rotki.data.db.get_blockchain_accounts() assert len(accounts.eth) == 2 assert all(acc in accounts.eth for acc in eth_accounts_after_removal) assert len(accounts.btc) == 2 assert all(acc in accounts.btc for acc in btc_accounts) # Now try to query all balances to make sure the result is the stored with setup.etherscan_patch, setup.bitcoin_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "blockchainbalancesresource", )) assert_proper_response(response) json_data = response.json() assert json_data['message'] == '' assert_eth_balances_result( rotki=rotki, json_data=json_data, eth_accounts=eth_accounts_after_removal, eth_balances=eth_balances_after_removal, token_balances=token_balances_after_removal, also_btc=True, ) # Now we will try to remove a BTC account. Setup the mocking infrastructure again all_btc_accounts = [UNIT_BTC_ADDRESS1, UNIT_BTC_ADDRESS2] btc_accounts_after_removal = [UNIT_BTC_ADDRESS2] setup = setup_balances( rotki, ethereum_accounts=eth_accounts_after_removal, btc_accounts=all_btc_accounts, eth_balances=eth_balances_after_removal, token_balances=token_balances_after_removal, btc_balances=['3000000', '5000000'], ) # remove the new BTC account with setup.bitcoin_patch: response = requests.delete(api_url_for( rotkehlchen_api_server, "blockchainsaccountsresource", blockchain='BTC', ), json={'accounts': [UNIT_BTC_ADDRESS1]}) assert_proper_response(response) json_data = response.json() assert json_data['message'] == '' assert_btc_balances_result( json_data=json_data, btc_accounts=btc_accounts_after_removal, btc_balances=['5000000'], also_eth=True, ) # Also make sure it's removed from the DB accounts = rotki.data.db.get_blockchain_accounts() assert len(accounts.eth) == 2 assert all(acc in accounts.eth for acc in eth_accounts_after_removal) assert len(accounts.btc) == 1 assert all(acc in accounts.btc for acc in btc_accounts_after_removal) # Now try to query all balances to make sure the result is also stored with setup.etherscan_patch, setup.bitcoin_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "blockchainbalancesresource", )) assert_proper_response(response) json_data = response.json() assert json_data['message'] == '' assert_btc_balances_result( json_data=json_data, btc_accounts=btc_accounts_after_removal, btc_balances=['5000000'], also_eth=True, )
def test_add_blockchain_accounts_async( rotkehlchen_api_server, ethereum_accounts, btc_accounts, number_of_eth_accounts, ): """A simpler version of the above test for adding blockchain accounts for async The main purpose of this test is to see that querying the endpoint asynchronously also works""" # Disable caching of query results rotki = rotkehlchen_api_server.rest_api.rotkehlchen rotki.blockchain.cache_ttl_secs = 0 # Test by having balances queried before adding an account eth_balances = ['1000000', '2000000'] token_balances = {'RDN': ['0', '4000000']} setup = setup_balances( rotki, ethereum_accounts=ethereum_accounts, btc_accounts=btc_accounts, eth_balances=eth_balances, token_balances=token_balances, ) new_eth_accounts = [make_ethereum_address(), make_ethereum_address()] all_eth_accounts = ethereum_accounts + new_eth_accounts eth_balances = ['1000000', '2000000', '3000000', '4000000'] token_balances = {'RDN': ['0', '4000000', '0', '250000000']} setup = setup_balances( rotki, ethereum_accounts=all_eth_accounts, btc_accounts=btc_accounts, eth_balances=eth_balances, token_balances=token_balances, ) # The application has started only with 2 ethereum accounts. Let's add two more with setup.etherscan_patch: response = requests.put(api_url_for( rotkehlchen_api_server, "blockchainsaccountsresource", blockchain='ETH', ), json={ 'accounts': new_eth_accounts, 'async_query': True }) task_id = assert_ok_async_response(response) outcome = wait_for_async_task(rotkehlchen_api_server, task_id) assert_eth_balances_result( rotki=rotki, json_data=outcome, eth_accounts=all_eth_accounts, eth_balances=setup.eth_balances, token_balances=setup.token_balances, also_btc=False, # All blockchain assets have not been queried yet ) # Also make sure they are added in the DB accounts = rotki.data.db.get_blockchain_accounts() assert len(accounts.eth) == 4 assert all(acc in accounts.eth for acc in all_eth_accounts) assert len(accounts.btc) == 2 assert all(acc in accounts.btc for acc in btc_accounts) # Now try to query all balances to make sure the result is the stored with setup.etherscan_patch, setup.bitcoin_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "blockchainbalancesresource", )) assert_proper_response(response) json_data = response.json() assert json_data['message'] == '' assert_eth_balances_result( rotki=rotki, json_data=json_data, eth_accounts=all_eth_accounts, eth_balances=setup.eth_balances, token_balances=setup.token_balances, also_btc=True, ) # Now we will try to add a new BTC account. Setup the mocking infrastructure again all_btc_accounts = btc_accounts + [UNIT_BTC_ADDRESS3] setup = setup_balances( rotki, ethereum_accounts=all_eth_accounts, btc_accounts=all_btc_accounts, eth_balances=eth_balances, token_balances=token_balances, btc_balances=['3000000', '5000000', '600000000'], ) # add the new BTC account with setup.bitcoin_patch: response = requests.put(api_url_for( rotkehlchen_api_server, "blockchainsaccountsresource", blockchain='BTC', ), json={ 'accounts': [UNIT_BTC_ADDRESS3], 'async_query': True }) task_id = assert_ok_async_response(response) outcome = wait_for_async_task(rotkehlchen_api_server, task_id) assert_btc_balances_result( json_data=outcome, btc_accounts=all_btc_accounts, btc_balances=setup.btc_balances, also_eth=True, ) # Also make sure it's added in the DB accounts = rotki.data.db.get_blockchain_accounts() assert len(accounts.eth) == 4 assert all(acc in accounts.eth for acc in all_eth_accounts) assert len(accounts.btc) == 3 assert all(acc in accounts.btc for acc in all_btc_accounts) # Now try to query all balances to make sure the result is also stored with setup.etherscan_patch, setup.bitcoin_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "blockchainbalancesresource", )) assert_proper_response(response) json_data = response.json() assert json_data['message'] == '' assert_btc_balances_result( json_data=json_data, btc_accounts=all_btc_accounts, btc_balances=setup.btc_balances, also_eth=True, )
def test_query_blockchain_balances( rotkehlchen_api_server, ethereum_accounts, btc_accounts, number_of_eth_accounts, ): """Test that the query blockchain balances endpoint works correctly. That is: - Querying only ETH chain returns only ETH and token balances - Querying only BTC chain returns only BTC account balances - Querying with no chain returns all balances (ETH, tokens and BTC) """ # Disable caching of query results rotki = rotkehlchen_api_server.rest_api.rotkehlchen rotki.blockchain.cache_ttl_secs = 0 setup = setup_balances(rotki, ethereum_accounts=ethereum_accounts, btc_accounts=btc_accounts) # First query only ETH and token balances with setup.etherscan_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "named_blockchain_balances_resource", blockchain='ETH', )) assert_proper_response(response) json_data = response.json() assert json_data['message'] == '' assert_eth_balances_result( rotki=rotki, json_data=json_data, eth_accounts=ethereum_accounts, eth_balances=setup.eth_balances, token_balances=setup.token_balances, also_btc=False, ) # Then query only BTC balances with setup.bitcoin_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "named_blockchain_balances_resource", blockchain='BTC', )) assert_proper_response(response) assert json_data['message'] == '' json_data = response.json() assert_btc_balances_result( json_data=json_data, btc_accounts=btc_accounts, btc_balances=setup.btc_balances, also_eth=False, ) # Finally query all balances with setup.etherscan_patch, setup.bitcoin_patch: response = requests.get( api_url_for( rotkehlchen_api_server, "blockchainbalancesresource", )) assert_proper_response(response) assert json_data['message'] == '' json_data = response.json() assert_eth_balances_result( rotki=rotki, json_data=json_data, eth_accounts=ethereum_accounts, eth_balances=setup.eth_balances, token_balances=setup.token_balances, also_btc=True, ) assert_btc_balances_result( json_data=json_data, btc_accounts=btc_accounts, btc_balances=setup.btc_balances, also_eth=True, ) # Try to query not existing blockchain response = requests.get( api_url_for( rotkehlchen_api_server, "named_blockchain_balances_resource", blockchain='NOTEXISTING', )) assert_error_response( response=response, contained_in_msg= 'Unrecognized value NOTEXISTING given for blockchain name', )
def test_query_blockchain_balances_async( rotkehlchen_api_server, ethereum_accounts, btc_accounts, number_of_eth_accounts, ): """Test that the query blockchain balances endpoint works when queried asynchronously """ # Disable caching of query results rotki = rotkehlchen_api_server.rest_api.rotkehlchen rotki.blockchain.cache_ttl_secs = 0 setup = setup_balances(rotki, ethereum_accounts=ethereum_accounts, btc_accounts=btc_accounts) # First query only ETH and token balances response = requests.get(api_url_for( rotkehlchen_api_server, "named_blockchain_balances_resource", blockchain='ETH', ), json={'async_query': True}) task_id = assert_ok_async_response(response) with setup.etherscan_patch: outcome = wait_for_async_task(rotkehlchen_api_server, task_id) assert_eth_balances_result( rotki=rotki, json_data=outcome, eth_accounts=ethereum_accounts, eth_balances=setup.eth_balances, token_balances=setup.token_balances, also_btc=False, ) # Then query only BTC balances response = requests.get(api_url_for( rotkehlchen_api_server, "named_blockchain_balances_resource", blockchain='BTC', ), json={'async_query': True}) task_id = assert_ok_async_response(response) with setup.bitcoin_patch: outcome = wait_for_async_task(rotkehlchen_api_server, task_id) assert_btc_balances_result( json_data=outcome, btc_accounts=btc_accounts, btc_balances=setup.btc_balances, also_eth=False, ) # Finally query all balances response = requests.get(api_url_for( rotkehlchen_api_server, "blockchainbalancesresource", ), json={'async_query': True}) task_id = assert_ok_async_response(response) with setup.etherscan_patch, setup.bitcoin_patch: outcome = wait_for_async_task(rotkehlchen_api_server, task_id) assert_eth_balances_result( rotki=rotki, json_data=outcome, eth_accounts=ethereum_accounts, eth_balances=setup.eth_balances, token_balances=setup.token_balances, also_btc=True, ) assert_btc_balances_result( json_data=outcome, btc_accounts=btc_accounts, btc_balances=setup.btc_balances, also_eth=True, )