Esempio n. 1
0
def test_purge_ethereum_transaction_data(rotkehlchen_api_server):
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    db = DBEthTx(rotki.data.db)
    db.add_ethereum_transactions([
        EthereumTransaction(
            tx_hash=bytes(),
            timestamp=1,
            block_number=1,
            from_address=make_ethereum_address(),
            to_address=make_ethereum_address(),
            value=FVal(1),
            gas=FVal(1),
            gas_price=FVal(1),
            gas_used=FVal(1),
            input_data=bytes(),
            nonce=1,
        )
    ], )
    filter_ = ETHTransactionsFilterQuery.make()

    result, filter_count = db.get_ethereum_transactions(filter_)
    assert len(result) == 1
    assert filter_count == 1
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            "ethereumtransactionsresource",
        ), )
    assert_simple_ok_response(response)
    result, filter_count = db.get_ethereum_transactions(filter_)
    assert len(result) == 0
    assert filter_count == 0
Esempio n. 2
0
def test_user_set_premium_credentials(rotkehlchen_api_server, username):
    """Test that setting the premium credentials endpoint works.

    We mock the server accepting the premium credentials
    """
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    _, patched_premium_at_set, patched_get = create_patched_premium(
        PremiumCredentials(VALID_PREMIUM_KEY, VALID_PREMIUM_SECRET),
        patch_get=True,
        metadata_last_modify_ts=0,
        metadata_data_hash=b'',
        metadata_data_size=0,
    )

    # Set premium credentials for current user
    data = {
        'premium_api_key': VALID_PREMIUM_KEY,
        'premium_api_secret': VALID_PREMIUM_SECRET
    }
    with patched_premium_at_set:
        response = requests.patch(
            api_url_for(rotkehlchen_api_server,
                        "usersbynameresource",
                        name=username),
            json=data,
        )
    assert_simple_ok_response(response)
    assert rotki.premium is not None
    assert rotki.premium.credentials.serialize_key() == VALID_PREMIUM_KEY
    assert rotki.premium.credentials.serialize_secret() == VALID_PREMIUM_SECRET
    with patched_get:
        assert rotki.premium.is_active()
Esempio n. 3
0
def test_qerying_settings(rotkehlchen_api_server, username):
    """Make sure that querying settings works for logged in user"""
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "settingsresource"))
    assert_proper_response(response)
    json_data = response.json()

    result = json_data['result']
    assert json_data['message'] == ''
    assert result['version'] == ROTKEHLCHEN_DB_VERSION
    for setting in DBSettings._fields:
        assert setting in result

    # Logout of the active user
    data = {'action': 'logout'}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_simple_ok_response(response)

    # and now with no logged in user it should fail
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "settingsresource"))
    assert_error_response(
        response=response,
        contained_in_msg='No user is currently logged in',
        status_code=HTTPStatus.CONFLICT,
    )
Esempio n. 4
0
def test_query_aave_history_with_borrowing(rotkehlchen_api_server,
                                           ethereum_accounts, aave_use_graph):  # pylint: disable=unused-argument  # noqa: E501
    """Check querying the aave histoy endpoint works. Uses real data."""
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    setup = setup_balances(
        rotki,
        ethereum_accounts=ethereum_accounts,
        btc_accounts=None,
        original_queries=['zerion', 'logs', 'blocknobytime'],
    )
    _query_borrowing_aave_history_test(setup, rotkehlchen_api_server)
    # Run it 2 times to make sure that data can be queried properly from the DB
    _query_borrowing_aave_history_test(setup, rotkehlchen_api_server)

    # Make sure events end up in the DB
    assert len(rotki.data.db.get_aave_events(AAVE_TEST_ACC_3)) != 0
    # test aave data purging from the db works
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            'namedethereummoduledataresource',
            module_name='aave',
        ))
    assert_simple_ok_response(response)
    assert len(rotki.data.db.get_aave_events(AAVE_TEST_ACC_3)) == 0
Esempio n. 5
0
def test_setup_exchange_does_not_stay_in_mapping_after_500_error(
        rotkehlchen_api_server):
    """Test that if 500 error is returned during setup of an exchange and it's stuck
    in the exchange mapping Rotki doesn't still think the exchange is registered.

    Regression test for the second part of https://github.com/rotki/rotki/issues/943
    """
    data = {'name': 'kraken', 'api_key': 'ddddd', 'api_secret': 'fffffff'}
    with API_KEYPAIR_KRAKEN_VALIDATION_FAIL_PATCH:
        response = requests.put(
            api_url_for(rotkehlchen_api_server, "exchangesresource"),
            json=data,
        )
    assert_error_response(
        response=response,
        status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
    )

    # Now try to register the exchange again
    data = {'name': 'kraken', 'api_key': 'ddddd', 'api_secret': 'fffffff'}
    with API_KEYPAIR_VALIDATION_PATCH:
        response = requests.put(
            api_url_for(rotkehlchen_api_server, "exchangesresource"),
            json=data,
        )
    assert_simple_ok_response(response)

    # and check that kraken is now registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "exchangesresource"))
    assert_proper_response(response)
    json_data = response.json()
    assert json_data['message'] == ''
    assert json_data['result'] == ['kraken']
Esempio n. 6
0
def test_remove_exchange(rotkehlchen_api_server):
    """Test that removing a setup exchange via the api works"""
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    db = rotki.data.db
    # Setup coinbase exchange
    data = {'name': 'coinbase', 'api_key': 'ddddd', 'api_secret': 'fffffff'}
    with API_KEYPAIR_COINBASE_VALIDATION_PATCH:
        response = requests.put(
            api_url_for(rotkehlchen_api_server, "exchangesresource"),
            json=data,
        )
    assert_simple_ok_response(response)

    # Add query ranges to see that they also get deleted when removing the exchange
    cursor = db.conn.cursor()
    cursor.executemany(
        'INSERT OR REPLACE INTO used_query_ranges(name, start_ts, end_ts) VALUES (?, ?, ?)',
        [('coinbasepro_trades', 0, 1579564096),
         ('coinbasepro_margins', 0, 1579564096),
         ('coinbasepro_asset_movements', 0, 1579564096),
         ('coinbase_trades', 0, 1579564096),
         ('coinbase_margins', 0, 1579564096),
         ('coinbase_asset_movements', 0, 1579564096),
         ('binance_trades', 0, 1579564096), ('binance_margins', 0, 1579564096),
         ('binance_asset_movements', 0, 1579564096)],
    )

    # Now remove the registered coinbase exchange
    data = {'name': 'coinbase'}
    response = requests.delete(api_url_for(rotkehlchen_api_server,
                                           "exchangesresource"),
                               json=data)
    assert_simple_ok_response(response)
    # and check that it's not registered anymore
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "exchangesresource"))
    assert_proper_response(response)
    json_data = response.json()
    assert json_data['message'] == ''
    assert json_data['result'] == []
    # Also check that the coinbase query ranges have been deleted but not the other ones
    cursor = db.conn.cursor()
    result = cursor.execute('SELECT name from used_query_ranges')
    count = 0
    for entry in result:
        count += 1
        msg = 'only binance or coinbasepro query ranges should remain'
        assert 'binance' in entry[0] or 'coinbasepro' in entry[0], msg
    assert count == 6, 'only 6 query ranges should remain in the DB'

    # now try to remove a non-registered exchange
    data = {'name': 'binance'}
    response = requests.delete(api_url_for(rotkehlchen_api_server,
                                           "exchangesresource"),
                               json=data)
    assert_error_response(
        response=response,
        contained_in_msg='Exchange binance is not registered',
        status_code=HTTPStatus.CONFLICT,
    )
Esempio n. 7
0
def test_purge_ethereum_transaction_data(rotkehlchen_api_server):
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    db = rotki.data.db
    db.add_ethereum_transactions(
        [EthereumTransaction(
            tx_hash=bytes(),
            timestamp=1,
            block_number=1,
            from_address=make_ethereum_address(),
            to_address=make_ethereum_address(),
            value=FVal(1),
            gas=FVal(1),
            gas_price=FVal(1),
            gas_used=FVal(1),
            input_data=bytes(),
            nonce=1,
        )],
        from_etherscan=True,
    )
    assert len(db.get_ethereum_transactions()) == 1
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            "ethereumtransactionsresource",
        ),
    )
    assert_simple_ok_response(response)
    assert len(db.get_ethereum_transactions()) == 0
Esempio n. 8
0
def test_query_yearn_vault_history(rotkehlchen_api_server, ethereum_accounts):
    """Check querying the yearn vaults history endpoint works. Uses real data."""
    async_query = random.choice([True, False])
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    setup = setup_balances(
        rotki,
        ethereum_accounts=ethereum_accounts,
        btc_accounts=None,
        original_queries=['zerion', 'logs', 'blocknobytime'],
    )

    for _ in range(2):
        # Run 2 times to make sure that loading data from DB the 2nd time works fine
        with ExitStack() as stack:
            # patch ethereum/etherscan to not autodetect tokens (not needed with infura)
            setup.enter_ethereum_patches(stack)
            response = requests.get(api_url_for(
                rotkehlchen_api_server,
                "yearnvaultshistoryresource",
            ),
                                    json={'async_query': async_query})
            if async_query:
                task_id = assert_ok_async_response(response)
                outcome = wait_for_async_task(rotkehlchen_api_server,
                                              task_id,
                                              timeout=600)
                assert outcome['message'] == ''
                result = outcome['result']
            else:
                result = assert_proper_response_with_result(response)

        # Make sure some data was saved in the DB after first call
        events = rotki.data.db.get_yearn_vaults_events(
            TEST_ACC1,
            YEARN_VAULTS['yyDAI+yUSDC+yUSDT+yTUSD'],
        )
        assert len(events) >= 11

        result = result[TEST_ACC1]
        check_vault_history('YALINK Vault', EXPECTED_HISTORY, result)
        check_vault_history('YCRV Vault', EXPECTED_HISTORY, result)
        check_vault_history('YSRENCURVE Vault', EXPECTED_HISTORY, result)
        check_vault_history('YUSDC Vault', EXPECTED_HISTORY, result)
        check_vault_history('YUSDT Vault', EXPECTED_HISTORY, result)
        check_vault_history('YYFI Vault', EXPECTED_HISTORY, result)

    # Make sure events end up in the DB
    # test yearn vault data purging from the db works
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            'ethereummoduledataresource',
            module_name='yearn_vaults',
        ))
    assert_simple_ok_response(response)
    events = rotki.data.db.get_yearn_vaults_events(
        TEST_ACC1,
        YEARN_VAULTS['yyDAI+yUSDC+yUSDT+yTUSD'],
    )
    assert len(events) == 0
Esempio n. 9
0
def test_query_yearn_vault_v2_history(rotkehlchen_api_server,
                                      ethereum_accounts):
    """Check querying the yearn vaults v2 history endpoint works. Uses real data."""

    async_query = random.choice([True, False])
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    setup = setup_balances(
        rotki,
        ethereum_accounts=ethereum_accounts,
        btc_accounts=None,
        token_balances={
            '0x5f18C75AbDAe578b483E5F43f12a39cF75b973a9': ['70000000'],
            '0xB8C3B7A2A618C552C23B1E4701109a9E756Bab67':
            ['2550000000000000000000'],
        },
        original_queries=['blocknobytime'],
    )

    with ExitStack() as stack:
        # patch ethereum/etherscan to not autodetect tokens
        setup.enter_ethereum_patches(stack)
        response = requests.get(api_url_for(
            rotkehlchen_api_server,
            "yearnvaultsv2historyresource",
        ),
                                json={'async_query': async_query})
        if async_query:
            task_id = assert_ok_async_response(response)
            outcome = wait_for_async_task(rotkehlchen_api_server, task_id)
            assert outcome['message'] == ''
            result = outcome['result']
        else:
            result = assert_proper_response_with_result(response)

    # Make sure some data was saved in the DB after first call
    events = rotki.data.db.get_yearn_vaults_v2_events(TEST_V2_ACC2, 0,
                                                      12770065)
    assert len(events) >= 11

    result = result[TEST_V2_ACC2]
    check_vault_history(
        '_ceth_0x1C6a9783F812b3Af3aBbf7de64c3cD7CC7D1af44',
        EXPECTED_V2_HISTORY,
        result,
    )

    # Make sure events end up in the DB
    # test yearn vault data purging from the db works
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            'ethereummoduledataresource',
            module_name='yearn_vaults_v2',
        ))
    assert_simple_ok_response(response)
    events = rotki.data.db.get_yearn_vaults_v2_events(TEST_V2_ACC2, 0,
                                                      12770065)
    assert len(events) == 0
Esempio n. 10
0
def test_edit_exchange_credentials(rotkehlchen_api_server_with_exchanges):
    server = rotkehlchen_api_server_with_exchanges
    rotki = rotkehlchen_api_server_with_exchanges.rest_api.rotkehlchen

    # Test that valid api key/secret is edited properly
    new_key = 'new_key'
    new_secret = 'new_secret'
    for location in SUPPORTED_EXCHANGES:
        exchange = try_get_first_exchange(rotki.exchange_manager, location)
        # change both passphrase and name -- kucoin
        data = {
            'name': exchange.name,
            'location': str(location),
            'new_name': f'my_{exchange.name}',
            'api_key': new_key,
            'api_secret': new_secret,
        }
        with mock_validate_api_key_success(location):
            response = requests.patch(api_url_for(server, 'exchangesresource'),
                                      json=data)
            assert_simple_ok_response(response)
            assert exchange.api_key == new_key
            assert exchange.secret == new_secret.encode()
            if location == Location.ICONOMI:
                continue  # except for iconomi
            # all of the api keys end up in session headers. Check they are properly
            # updated there
            assert any(new_key in value
                       for _, value in exchange.session.headers.items())

    # Test that api key validation failure is handled correctly
    for location in SUPPORTED_EXCHANGES:
        exchange = try_get_first_exchange(rotki.exchange_manager, location)
        # change both passphrase and name -- kucoin
        data = {
            'name': exchange.name,
            'location': str(location),
            'new_name': f'my_{exchange.name}',
            'api_key': 'invalid',
            'api_secret': 'invalid',
        }
        with mock_validate_api_key_failure(location):
            response = requests.patch(api_url_for(server, 'exchangesresource'),
                                      json=data)
            assert_error_response(
                response=response,
                contained_in_msg='BOOM ERROR',
                status_code=HTTPStatus.CONFLICT,
            )
            # Test that the api key/secret DID NOT change
            assert exchange.api_key == new_key
            assert exchange.secret == new_secret.encode()
            if location == Location.ICONOMI:
                continue  # except for iconomi
            # all of the api keys end up in session headers. Check they are properly
            # updated there
            assert any(new_key in value
                       for _, value in exchange.session.headers.items())
Esempio n. 11
0
def test_purge_single_exchange_data(rotkehlchen_api_server_with_exchanges, added_exchanges):
    rotki = rotkehlchen_api_server_with_exchanges.rest_api.rotkehlchen
    target_exchange = Location.POLONIEX
    mock_exchange_data_in_db(added_exchanges, rotki)
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server_with_exchanges,
            "named_exchanges_data_resource",
            location=target_exchange,
        ),
    )
    assert_simple_ok_response(response)
    check_saved_events_for_exchange(target_exchange, rotki.data.db, should_exist=False)
    check_saved_events_for_exchange(Location.BINANCE, rotki.data.db, should_exist=True)
Esempio n. 12
0
def test_purge_all_exchange_data(rotkehlchen_api_server_with_exchanges, added_exchanges):
    rotki = rotkehlchen_api_server_with_exchanges.rest_api.rotkehlchen
    mock_exchange_data_in_db(added_exchanges, rotki)
    for exchange_location in added_exchanges:
        check_saved_events_for_exchange(exchange_location, rotki.data.db, should_exist=True)
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server_with_exchanges,
            "exchangesdataresource",
        ),
    )
    assert_simple_ok_response(response)
    for exchange_location in added_exchanges:
        check_saved_events_for_exchange(exchange_location, rotki.data.db, should_exist=False)
Esempio n. 13
0
def test_setup_exchange_does_not_stay_in_mapping_after_500_error(
        rotkehlchen_api_server):
    """Test that if 500 error is returned during setup of an exchange and it's stuck
    in the exchange mapping rotki doesn't still think the exchange is registered.

    Regression test for the second part of https://github.com/rotki/rotki/issues/943
    """
    data = {
        'location': 'kraken',
        'name': 'my_kraken',
        'api_key': 'ddddd',
        'api_secret': 'fffffff'
    }
    with API_KEYPAIR_KRAKEN_VALIDATION_FAIL_PATCH:
        response = requests.put(
            api_url_for(rotkehlchen_api_server, 'exchangesresource'),
            json=data,
        )
    assert_error_response(
        response=response,
        status_code=HTTPStatus.CONFLICT,
    )

    # Now try to register the exchange again
    data = {
        'location': 'kraken',
        'name': 'my_kraken',
        'api_key': 'ddddd',
        'api_secret': 'fffffff'
    }
    with mock_validate_api_key_success(Location.KRAKEN):
        response = requests.put(
            api_url_for(rotkehlchen_api_server, 'exchangesresource'),
            json=data,
        )
    assert_simple_ok_response(response)

    # and check that kraken is now registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, 'exchangesresource'))
    result = assert_proper_response_with_result(response)
    assert result == [{
        'location': 'kraken',
        'name': 'my_kraken',
        'kraken_account_type': 'starter'
    }]  # noqa: E501
Esempio n. 14
0
def test_refresh_icon(rotkehlchen_api_server):
    """Test that checks refreshing the icon of an asset works."""
    # add icon for an asset
    icon_manager = rotkehlchen_api_server.rest_api.rotkehlchen.icon_manager
    root_path = Path(__file__).resolve().parent.parent.parent.parent
    sample_filepath = root_path / 'frontend' / 'app' / 'src' / 'assets' / 'images' / 'exchanges' / 'kraken.svg'  # noqa: E501
    icon_filepath = icon_manager.icons_dir / 'DOGE_small.png'
    shutil.copyfile(sample_filepath, icon_filepath)

    now = ts_now()
    response = requests.patch(
        api_url_for(
            rotkehlchen_api_server,
            'asseticonsresource',
            asset=A_DOGE.identifier,
        ), )
    assert_simple_ok_response(response)
    assert icon_filepath.stat().st_ctime > now
Esempio n. 15
0
def test_purge_single_exchange_data(rotkehlchen_api_server_with_exchanges,
                                    added_exchanges):
    rotki = rotkehlchen_api_server_with_exchanges.rest_api.rotkehlchen
    target_exchange = 'poloniex'
    mock_exchange_data_in_db(added_exchanges, rotki)
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server_with_exchanges,
            "named_exchanges_data_resource",
            name=target_exchange,
        ), )
    assert_simple_ok_response(response)
    check_saved_events_for_exchange(target_exchange,
                                    rotki.data.db,
                                    should_exist=False)
    check_saved_events_for_exchange('binance',
                                    rotki.data.db,
                                    should_exist=True)
Esempio n. 16
0
def test_purge_ethereum_transaction_data(rotkehlchen_api_server):
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    addr1 = make_ethereum_address()
    rotki.data.db.add_blockchain_accounts(
        blockchain=SupportedBlockchain.ETHEREUM,
        account_data=[
            BlockchainAccountData(address=addr1),
        ],
    )
    db = DBEthTx(rotki.data.db)
    db.add_ethereum_transactions(
        [
            EthereumTransaction(
                tx_hash=make_evm_tx_hash(bytes()),
                timestamp=1,
                block_number=1,
                from_address=addr1,
                to_address=make_ethereum_address(),
                value=FVal(1),
                gas=FVal(1),
                gas_price=FVal(1),
                gas_used=FVal(1),
                input_data=bytes(),
                nonce=1,
            )
        ],
        relevant_address=addr1,
    )
    filter_ = ETHTransactionsFilterQuery.make()

    result, filter_count = db.get_ethereum_transactions_and_limit_info(
        filter_, True)
    assert len(result) == 1
    assert filter_count == 1
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumtransactionsresource',
        ), )
    assert_simple_ok_response(response)
    result, filter_count = db.get_ethereum_transactions_and_limit_info(
        filter_, True)
    assert len(result) == 0
    assert filter_count == 0
Esempio n. 17
0
def test_user_logout(rotkehlchen_api_server, username):
    """Test that user logout works succesfully and that common errors are handled"""
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen

    # Logout of a non-existing/different user
    data = {'action': 'logout'}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name='nobody'),
        json=data,
    )
    assert_error_response(
        response=response,
        contained_in_msg='Provided user nobody is not the logged in user',
        status_code=HTTPStatus.CONFLICT,
    )
    assert rotki.user_is_logged_in is True

    # Logout of the active user
    data = {'action': 'logout'}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_simple_ok_response(response)
    assert rotki.user_is_logged_in is False

    # Now try to log out of the same user again
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_error_response(
        response=response,
        contained_in_msg='No user is currently logged in',
        status_code=HTTPStatus.CONFLICT,
    )
    assert rotki.user_is_logged_in is False
Esempio n. 18
0
def test_importing_custom_assets_list(rotkehlchen_api_server, method,
                                      file_type):
    """Test that the endpoint for importing custom assets works correctly"""
    dir_path = Path(__file__).resolve().parent.parent
    if file_type == 'zip':
        filepath = dir_path / 'data' / 'exported_assets.zip'
    else:
        filepath = dir_path / 'data' / 'exported_assets.json'

    if method == 'put':
        response = requests.put(
            api_url_for(
                rotkehlchen_api_server,
                'userassetsresource',
            ),
            json={
                'action': 'upload',
                'file': str(filepath)
            },
        )
    else:
        response = requests.post(
            api_url_for(
                rotkehlchen_api_server,
                'userassetsresource',
            ),
            json={'action': 'upload'},
            files={'file': open(filepath, 'rb')},
        )

    assert_simple_ok_response(response)
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    errors = rotki.msg_aggregator.consume_errors()
    warnings = rotki.msg_aggregator.consume_errors()
    assert len(errors) == 0
    assert len(warnings) == 0

    assert_proper_response_with_result(response)
    stinch = EthereumToken('0xA0446D8804611944F1B527eCD37d7dcbE442caba')
    assert stinch.symbol == 'st1INCH'
    assert len(stinch.underlying_tokens) == 1
    assert stinch.decimals == 18
Esempio n. 19
0
def test_create_download_delete_backup(rotkehlchen_api_server, data_dir, username):
    """Test that creating, downloading and deleting a backup works fine"""
    start_ts = ts_now()
    response = requests.put(api_url_for(rotkehlchen_api_server, 'databasebackupsresource'))
    filepath = Path(assert_proper_response_with_result(response))
    assert filepath.exists()
    assert filepath.parent == Path(data_dir, username)

    response = requests.get(api_url_for(rotkehlchen_api_server, 'databaseinforesource'))
    result = assert_proper_response_with_result(response)
    backups = result['userdb']['backups']
    assert len(backups) == 1
    assert backups[0]['time'] >= start_ts
    assert backups[0]['version'] == ROTKEHLCHEN_DB_VERSION

    # now also try to download that backup and make sure it's the same file
    response = requests.get(
        api_url_for(rotkehlchen_api_server, 'databasebackupsresource'),
        json={'file': str(filepath)},
    )
    with tempfile.TemporaryDirectory() as tmpdirname:
        tempdbpath = Path(tmpdirname, 'temp.db')
        tempdbpath.write_bytes(response.content)
        assert filecmp.cmp(filepath, tempdbpath)

    # create an extra database to check that lists work correctly
    second_filepath = filepath.parent / 'back.db'
    second_filepath.touch()

    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            'databasebackupsresource'),
        json={'files': [str(filepath), str(second_filepath)]},
    )
    assert_simple_ok_response(response)
    assert not filepath.exists()
    assert not second_filepath.exists()
    response = requests.get(api_url_for(rotkehlchen_api_server, 'databaseinforesource'))
    result = assert_proper_response_with_result(response)
    backups = result['userdb']['backups']
    assert len(backups) == 0
Esempio n. 20
0
def test_delete_snapshot(rotkehlchen_api_server):
    conn = rotkehlchen_api_server.rest_api.rotkehlchen.data.db.conn
    ts = Timestamp(ts_now())
    _populate_db_with_balances(conn, ts)
    _populate_db_with_location_data(conn, ts)
    rotkehlchen_api_server.rest_api.rotkehlchen.data.db.set_settings(
        ModifiableDBSettings(main_currency=A_EUR))  # noqa: E501
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            'dbsnapshotdeletingresource',
        ),
        json={'timestamp': ts},
    )
    assert_simple_ok_response(response)
    cursor = conn.cursor()
    assert len(
        cursor.execute('SELECT time FROM timed_balances WHERE time=?',
                       (ts, )).fetchall()) == 0  # noqa: 501
    assert len(
        cursor.execute('SELECT time FROM timed_location_data WHERE time=?',
                       (ts, )).fetchall()) == 0  # noqa: 501

    # check that an error is thrown for invalid timestamp
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            'dbsnapshotdeletingresource',
        ),
        json={'timestamp': 1000000},
    )
    assert_error_response(
        response,
        contained_in_msg='No snapshot found for the specified timestamp',
        status_code=HTTPStatus.CONFLICT,
    )
Esempio n. 21
0
def assert_csv_export_response(response,
                               csv_dir,
                               main_currency: Asset,
                               is_download=False):
    if is_download:
        assert response.status_code == HTTPStatus.OK
    else:
        assert_simple_ok_response(response)

    with open(os.path.join(csv_dir, BALANCES_FILENAME), newline='') as csvfile:
        reader = csv.DictReader(csvfile)
        count = 0
        for row in reader:
            assert len(row) == 5
            assert row['category'] in (
                'asset',
                'liability',
            )
            assert row['amount'] is not None
            assert row['asset'] is not None
            assert row['timestamp'] is not None
            assert row[f'{main_currency.symbol.lower()}_value'] is not None
            count += 1
        assert count == 2

    with open(os.path.join(csv_dir, BALANCES_FOR_IMPORT_FILENAME),
              newline='') as csvfile:
        reader = csv.DictReader(csvfile)
        count = 0
        for row in reader:
            assert len(row) == 5
            assert row['category'] in (
                'asset',
                'liability',
            )
            assert row['amount'] is not None
            assert row['asset_identifier'] is not None
            assert row['timestamp'] is not None
            assert row['usd_value'] is not None
            count += 1
        assert count == 2

    with open(os.path.join(csv_dir, LOCATION_DATA_FILENAME),
              newline='') as csvfile:
        reader = csv.DictReader(csvfile)
        count = 0
        for row in reader:
            assert len(row) == 3
            assert row['timestamp'] is not None
            assert Location.deserialize(row['location']) is not None
            assert row[f'{main_currency.symbol.lower()}_value'] is not None
            count += 1
        assert count == 3

    with open(os.path.join(csv_dir, LOCATION_DATA_IMPORT_FILENAME),
              newline='') as csvfile:
        reader = csv.DictReader(csvfile)
        count = 0
        for row in reader:
            assert len(row) == 3
            assert row['timestamp'] is not None
            assert Location.deserialize(row['location']) is not None
            assert row['usd_value'] is not None
            count += 1
        assert count == 3
Esempio n. 22
0
def test_setup_exchange(rotkehlchen_api_server):
    """Test that setting up an exchange via the api works"""
    # Check that no exchanges are registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "exchangesresource"))
    assert_proper_response(response)
    json_data = response.json()
    assert json_data['message'] == ''
    assert json_data['result'] == []

    # First test that if api key validation fails we get an error, for every exchange
    for location in SUPPORTED_EXCHANGES:
        data = {
            'location': str(location),
            'name': f'my_{str(location)}',
            'api_key': 'ddddd',
            'api_secret': 'fffffff'
        }  # noqa: E501
        if location in (Location.COINBASEPRO, Location.KUCOIN):
            data['passphrase'] = '123'
        response = requests.put(
            api_url_for(rotkehlchen_api_server, 'exchangesresource'),
            json=data,
        )
        assert_error_response(
            response=response,
            contained_in_msg=[
                'Provided API Key or secret is invalid',
                'Provided API Key is invalid',
                'Provided API Key is in invalid Format',
                'Provided API Secret is invalid',
                'Provided Gemini API key needs to have "Auditor" permission activated',
                BITSTAMP_API_KEY_ERROR_CODE_ACTION['API0011'],
                BITFINEX_API_KEY_ERROR_MESSAGE,
                KUCOIN_API_KEY_ERROR_CODE[400003],
                'Bad combination of API Keys',
                'ApiKey has invalid value',
            ],
            status_code=HTTPStatus.CONFLICT,
        )
    # Make sure that no exchange is registered after that
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    assert len(rotki.exchange_manager.connected_exchanges) == 0

    # Mock the api pair validation and make sure that the exchange is setup
    data = {
        'location': 'kraken',
        'name': 'my_kraken',
        'api_key': 'ddddd',
        'api_secret': 'fffffff'
    }  # noqa: E501
    with mock_validate_api_key_success(Location.KRAKEN):
        response = requests.put(
            api_url_for(rotkehlchen_api_server, 'exchangesresource'),
            json=data,
        )
    assert_simple_ok_response(response)

    # and check that kraken is now registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, 'exchangesresource'))
    result = assert_proper_response_with_result(response)
    assert result == [{
        'location': 'kraken',
        'name': 'my_kraken',
        'kraken_account_type': 'starter'
    }]  # noqa: E501

    # Check that we get an error if we try to re-setup an already setup exchange
    data = {
        'location': 'kraken',
        'name': 'my_kraken',
        'api_key': 'ddddd',
        'api_secret': 'fffffff'
    }  # noqa: E501
    with mock_validate_api_key_success(Location.KRAKEN):
        response = requests.put(
            api_url_for(rotkehlchen_api_server, 'exchangesresource'),
            json=data,
        )
    assert_error_response(
        response=response,
        contained_in_msg='kraken exchange my_kraken is already registered',
        status_code=HTTPStatus.CONFLICT,
    )

    # But check that same location different name works
    data = {
        'location': 'kraken',
        'name': 'my_other_kraken',
        'api_key': 'aadddddd',
        'api_secret': 'fffffff'
    }  # noqa: E501
    with mock_validate_api_key_success(Location.KRAKEN):
        response = requests.put(
            api_url_for(rotkehlchen_api_server, 'exchangesresource'),
            json=data,
        )
    assert_simple_ok_response(response)

    # and check that kraken is now registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, 'exchangesresource'))
    result = assert_proper_response_with_result(response)
    assert result == [
        {
            'location': 'kraken',
            'name': 'my_kraken',
            'kraken_account_type': 'starter'
        },
        {
            'location': 'kraken',
            'name': 'my_other_kraken',
            'kraken_account_type': 'starter'
        },
    ]

    # Check that giving a passphrase is fine
    data = {
        'location': 'coinbasepro',
        'name': 'my_coinbasepro',
        'api_key': 'ddddd',
        'api_secret': 'fffff',
        'passphrase': 'sdf'
    }  # noqa: E501
    with mock_validate_api_key_success(Location.COINBASEPRO):
        response = requests.put(
            api_url_for(rotkehlchen_api_server, 'exchangesresource'),
            json=data,
        )
    assert_simple_ok_response(response)
    # and check that coinbasepro is now registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, 'exchangesresource'))
    result = assert_proper_response_with_result(response)
    assert result == [
        {
            'location': 'kraken',
            'name': 'my_kraken',
            'kraken_account_type': 'starter'
        },
        {
            'location': 'kraken',
            'name': 'my_other_kraken',
            'kraken_account_type': 'starter'
        },
        {
            'location': 'coinbasepro',
            'name': 'my_coinbasepro'
        },
    ]
Esempio n. 23
0
def test_get_events(rotkehlchen_api_server, ethereum_accounts):  # pylint: disable=unused-argument
    async_query = random.choice([False, True])
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen

    setup = setup_balances(
        rotki,
        ethereum_accounts=ethereum_accounts,
        btc_accounts=None,
        original_queries=['zerion', 'logs', 'blocknobytime'],
    )

    with ExitStack() as stack:
        # patch ethereum/etherscan to not autodetect tokens
        setup.enter_ethereum_patches(stack)
        response = requests.get(
            api_url_for(rotkehlchen_api_server, 'adexhistoryresource'),
            json={
                'async_query': async_query,
                'to_timestamp': 1611747322
            },
        )
        if async_query:
            task_id = assert_ok_async_response(response)
            outcome = wait_for_async_task(rotkehlchen_api_server, task_id)
            assert outcome['message'] == ''
            result = outcome['result']
        else:
            result = assert_proper_response_with_result(response)

    identity_address = '0x2a6c38D16BFdc7b4a20f1F982c058F07BDCe9204'
    tom_pool_id = '0x2ce0c96383fb229d9776f33846e983a956a7d95844fac57b180ed0071d93bb28'
    bond_id = '0x540cab9883923c01e657d5da4ca5674b6e4626b4a148224635495502d674c7c5'
    channel_id = '0x30d87bab0ef1e7f8b4c3b894ca2beed41bbd54c481f31e5791c1e855c9dbf4ba'
    result = result[ADEX_TEST_ADDR]
    expected_events = [
        Bond(
            tx_hash=
            '0x9989f47c6c0a761f98f910ac24e2438d858be96c12124a13be4bb4b3150c55ea',
            address=ADEX_TEST_ADDR,
            identity_address=identity_address,
            timestamp=1604366004,
            bond_id=bond_id,
            pool_id=tom_pool_id,
            value=Balance(FVal(100000), FVal(200000)),
            nonce=0,
            slashed_at=0,
        ),
        ChannelWithdraw(
            tx_hash=
            '0xa9ee91af823c0173fc5ada908ff9fe3f4d7c84a2c9da795f0889b3f4ace75b13',
            address=ADEX_TEST_ADDR,
            identity_address=identity_address,
            timestamp=1607453764,
            channel_id=channel_id,
            pool_id=tom_pool_id,
            value=Balance(FVal('5056.894263641728544592'),
                          FVal('10113.788527283457089184')),
            token=A_ADX,
            log_index=316,
        ),
        Unbond(
            tx_hash=
            '0xa9ee91af823c0173fc5ada908ff9fe3f4d7c84a2c9da795f0889b3f4ace75b13',
            address=ADEX_TEST_ADDR,
            identity_address=identity_address,
            timestamp=1607453764,
            bond_id=bond_id,
            pool_id=tom_pool_id,
            value=Balance(FVal(100000), FVal(200000)),
        )
    ]
    assert len(result['events']) == 8
    assert result['events'][:len(expected_events)] == [
        x.serialize() for x in expected_events
    ]
    assert 'staking_details' in result
    # Make sure events end up in the DB
    assert len(rotki.data.db.get_adex_events()) != 0
    # test adex data purging from the db works
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            'namedethereummoduledataresource',
            module_name='adex',
        ))
    assert_simple_ok_response(response)
    assert len(rotki.data.db.get_adex_events()) == 0
Esempio n. 24
0
def test_query_transactions_over_limit(
    rotkehlchen_api_server,
    ethereum_accounts,
    start_with_valid_premium,
):
    start_ts = 0
    end_ts = 1598453214
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    db = rotki.data.db
    all_transactions_num = FREE_ETH_TX_LIMIT + 50
    transactions = [
        EthereumTransaction(
            tx_hash=x.to_bytes(2, byteorder='little'),
            timestamp=x,
            block_number=x,
            from_address=ethereum_accounts[0],
            to_address=make_ethereum_address(),
            value=x,
            gas=x,
            gas_price=x,
            gas_used=x,
            input_data=x.to_bytes(2, byteorder='little'),
            nonce=x,
        ) for x in range(FREE_ETH_TX_LIMIT - 10)
    ]
    transactions.extend([
        EthereumTransaction(
            tx_hash=(x + 500).to_bytes(2, byteorder='little'),
            timestamp=x,
            block_number=x,
            from_address=ethereum_accounts[1],
            to_address=make_ethereum_address(),
            value=x,
            gas=x,
            gas_price=x,
            gas_used=x,
            input_data=x.to_bytes(2, byteorder='little'),
            nonce=x,
        ) for x in range(60)
    ])

    dbethtx = DBEthTx(db)
    dbethtx.add_ethereum_transactions(transactions)
    # Also make sure to update query ranges so as not to query etherscan at all
    for address in ethereum_accounts:
        DBQueryRanges(db).update_used_query_range(
            location_string=f'ethtxs_{address}',
            start_ts=start_ts,
            end_ts=end_ts,
            ranges_to_query=[],
        )

    free_expected_entries_total = [FREE_ETH_TX_LIMIT - 10, 10]
    free_expected_entries_found = [FREE_ETH_TX_LIMIT - 10, 60]
    premium_expected_entries = [FREE_ETH_TX_LIMIT - 10, 60]

    # Check that we get all transactions correctly even if we query two times
    for _ in range(2):
        response = requests.post(
            api_url_for(
                rotkehlchen_api_server,
                'limitscounterresetresource',
                location='ethereum_transactions',
            ), )
        assert_simple_ok_response(response)
        for idx, address in enumerate(ethereum_accounts):
            response = requests.get(
                api_url_for(
                    rotkehlchen_api_server,
                    'ethereumtransactionsresource',
                ),
                json={
                    'from_timestamp': start_ts,
                    'to_timestamp': end_ts,
                    'address': address
                },
            )
            result = assert_proper_response_with_result(response)
            if start_with_valid_premium:
                assert len(result['entries']) == premium_expected_entries[idx]
                assert result['entries_total'] == all_transactions_num
                assert result['entries_found'] == premium_expected_entries[idx]
                assert result['entries_limit'] == -1
            else:
                assert len(
                    result['entries']) == free_expected_entries_total[idx]
                assert result['entries_total'] == all_transactions_num
                assert result['entries_found'] == free_expected_entries_found[
                    idx]
                assert result['entries_limit'] == FREE_ETH_TX_LIMIT
Esempio n. 25
0
def test_setup_exchange(rotkehlchen_api_server):
    """Test that setting up an exchange via the api works"""
    # Check that no exchanges are registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "exchangesresource"))
    assert_proper_response(response)
    json_data = response.json()
    assert json_data['message'] == ''
    assert json_data['result'] == []

    # First test that if api key validation fails we get an error, for every exchange
    for name in SUPPORTED_EXCHANGES:
        data = {'name': name, 'api_key': 'ddddd', 'api_secret': 'fffffff'}
        if name in ('coinbasepro', 'kucoin'):
            data['passphrase'] = '123'
        response = requests.put(
            api_url_for(rotkehlchen_api_server, "exchangesresource"),
            json=data,
        )
        assert_error_response(
            response=response,
            contained_in_msg=[
                'Provided API Key or secret is invalid',
                'Provided API Key is invalid',
                'Provided API Key is in invalid Format',
                'Provided API Secret is invalid',
                'Provided Gemini API key needs to have "Auditor" permission activated',
                BITSTAMP_API_KEY_ERROR_CODE_ACTION['API0011'],
                BITFINEX_API_KEY_ERROR_MESSAGE,
                KUCOIN_API_KEY_ERROR_CODE[400003],
                'Bad combination of API Keys',
            ],
            status_code=HTTPStatus.CONFLICT,
        )
    # Make sure that no exchange is registered after that
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    assert len(rotki.exchange_manager.connected_exchanges) == 0

    # Mock the api pair validation and make sure that the exchange is setup
    data = {'name': 'kraken', 'api_key': 'ddddd', 'api_secret': 'fffffff'}
    with API_KEYPAIR_VALIDATION_PATCH:
        response = requests.put(
            api_url_for(rotkehlchen_api_server, "exchangesresource"),
            json=data,
        )
    assert_simple_ok_response(response)

    # and check that kraken is now registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "exchangesresource"))
    assert_proper_response(response)
    json_data = response.json()
    assert json_data['message'] == ''
    assert json_data['result'] == ['kraken']

    # Check that we get an error if we try to re-setup an already setup exchange
    data = {'name': 'kraken', 'api_key': 'ddddd', 'api_secret': 'fffffff'}
    with API_KEYPAIR_VALIDATION_PATCH:
        response = requests.put(
            api_url_for(rotkehlchen_api_server, "exchangesresource"),
            json=data,
        )
    assert_error_response(
        response=response,
        contained_in_msg='Exchange kraken is already registered',
        status_code=HTTPStatus.CONFLICT,
    )

    # Check that giving a passphrase is fine
    data = {
        'name': 'coinbasepro',
        'api_key': 'ddddd',
        'api_secret': 'fffff',
        'passphrase': 'sdf'
    }
    with API_KEYPAIR_COINBASEPRO_VALIDATION_PATCH:
        response = requests.put(
            api_url_for(rotkehlchen_api_server, "exchangesresource"),
            json=data,
        )
    assert_simple_ok_response(response)
    # and check that coinbasepro is now registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "exchangesresource"))
    assert_proper_response(response)
    json_data = response.json()
    assert json_data['message'] == ''
    assert json_data['result'] == ['kraken', 'coinbasepro']
Esempio n. 26
0
def test_setup_exchange(rotkehlchen_api_server):
    """Test that setting up an exchange via the api works"""
    # Check that no exchanges are registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "exchangesresource"))
    assert_proper_response(response)
    json_data = response.json()
    assert json_data['message'] == ''
    assert json_data['result'] == []

    # First test that if api key validation fails we get an error
    data = {'name': 'kraken', 'api_key': 'ddddd', 'api_secret': 'fffffff'}
    response = requests.put(api_url_for(rotkehlchen_api_server,
                                        "exchangesresource"),
                            json=data)
    assert_error_response(
        response=response,
        contained_in_msg='Provided API Key or secret is in invalid Format',
        status_code=HTTPStatus.CONFLICT,
    )

    # Mock the api pair validation and make sure that the exchange is setup
    data = {'name': 'kraken', 'api_key': 'ddddd', 'api_secret': 'fffffff'}
    with API_KEYPAIR_VALIDATION_PATCH:
        response = requests.put(
            api_url_for(rotkehlchen_api_server, "exchangesresource"),
            json=data,
        )
    assert_simple_ok_response(response)

    # and check that kraken is now registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "exchangesresource"))
    assert_proper_response(response)
    json_data = response.json()
    assert json_data['message'] == ''
    assert json_data['result'] == ['kraken']

    # Check that we get an error if we try to re-setup an already setup exchange
    data = {'name': 'kraken', 'api_key': 'ddddd', 'api_secret': 'fffffff'}
    with API_KEYPAIR_VALIDATION_PATCH:
        response = requests.put(
            api_url_for(rotkehlchen_api_server, "exchangesresource"),
            json=data,
        )
    assert_error_response(
        response=response,
        contained_in_msg='Exchange kraken is already registered',
        status_code=HTTPStatus.CONFLICT,
    )

    # Check that giving a passphrase is fine
    data = {
        'name': 'coinbasepro',
        'api_key': 'ddddd',
        'api_secret': 'fffff',
        'passphrase': 'sdf'
    }
    with API_KEYPAIR_COINBASEPRO_VALIDATION_PATCH:
        response = requests.put(
            api_url_for(rotkehlchen_api_server, "exchangesresource"),
            json=data,
        )
    assert_simple_ok_response(response)
    # and check that coinbasepro is now registered
    response = requests.get(
        api_url_for(rotkehlchen_api_server, "exchangesresource"))
    assert_proper_response(response)
    json_data = response.json()
    assert json_data['message'] == ''
    assert json_data['result'] == ['kraken', 'coinbasepro']
Esempio n. 27
0
def test_import_snapshot(rotkehlchen_api_server, tmpdir_factory):
    conn = rotkehlchen_api_server.rest_api.rotkehlchen.data.db.conn
    ts = Timestamp(ts_now())
    _populate_db_with_balances(conn, ts)
    _populate_db_with_location_data(conn, ts)
    rotkehlchen_api_server.rest_api.rotkehlchen.data.db.set_settings(
        ModifiableDBSettings(main_currency=A_EUR))  # noqa: E501

    # check that importing a valid snapshot passes using PUT
    csv_dir = str(tmpdir_factory.mktemp('test_csv_dir'))
    _create_snapshot_with_valid_data(csv_dir, Timestamp(1651071105))
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'dbsnapshotimportingresource',
        ),
        json={
            'balances_snapshot_file':
            f'{csv_dir}/{BALANCES_FOR_IMPORT_FILENAME}',
            'location_data_snapshot_file':
            f'{csv_dir}/{LOCATION_DATA_IMPORT_FILENAME}',
        },
    )
    assert_simple_ok_response(response)

    # check that POST with the file works.
    csv_dir2 = str(tmpdir_factory.mktemp('test_csv_dir_2'))
    _create_snapshot_with_valid_data_for_post(csv_dir2, Timestamp(1651075))
    response = requests.post(
        api_url_for(
            rotkehlchen_api_server,
            'dbsnapshotimportingresource',
        ),
        files={
            'balances_snapshot_file':
            open(f'{csv_dir2}/{BALANCES_FOR_IMPORT_FILENAME}'),
            'location_data_snapshot_file':
            open(f'{csv_dir2}/{LOCATION_DATA_IMPORT_FILENAME}'),
        },
    )
    assert_simple_ok_response(response)

    # check that importing a snapshot that is present in the db fails.
    csv_dir3 = str(tmpdir_factory.mktemp('test_csv_dir3'))
    response = requests.post(
        api_url_for(
            rotkehlchen_api_server,
            'dbsnapshotexportingresource',
        ),
        json={
            'timestamp': ts,
            'path': csv_dir3,
        },
    )
    assert_csv_export_response(response,
                               csv_dir3,
                               main_currency=A_EUR,
                               is_download=False)
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'dbsnapshotimportingresource',
        ),
        json={
            'balances_snapshot_file':
            f'{csv_dir3}/{BALANCES_FOR_IMPORT_FILENAME}',
            'location_data_snapshot_file':
            f'{csv_dir3}/{LOCATION_DATA_IMPORT_FILENAME}',
        },
    )
    assert_error_response(
        response,
        contained_in_msg='Adding timed_balance failed',
        status_code=HTTPStatus.CONFLICT,
    )

    # check that importing snapshot with different timestamps fails.
    csv_dir4 = str(tmpdir_factory.mktemp('test_csv_dir4'))
    _create_snapshot_different_timestamps(csv_dir4, ts)
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'dbsnapshotimportingresource',
        ),
        json={
            'balances_snapshot_file':
            f'{csv_dir4}/{BALANCES_FOR_IMPORT_FILENAME}',
            'location_data_snapshot_file':
            f'{csv_dir4}/{LOCATION_DATA_IMPORT_FILENAME}',
        },
    )
    assert_error_response(
        response,
        contained_in_msg='csv file has different timestamps',
        status_code=HTTPStatus.CONFLICT,
    )

    # check that importing snapshot with invalid header fails.
    csv_dir5 = str(tmpdir_factory.mktemp('test_csv_dir5'))
    _create_snapshot_with_invalid_headers(csv_dir5, ts)
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'dbsnapshotimportingresource',
        ),
        json={
            'balances_snapshot_file':
            f'{csv_dir5}/{BALANCES_FOR_IMPORT_FILENAME}',
            'location_data_snapshot_file':
            f'{csv_dir5}/{LOCATION_DATA_IMPORT_FILENAME}',
        },
    )
    assert_error_response(
        response,
        contained_in_msg='csv file has invalid headers',
        status_code=HTTPStatus.CONFLICT,
    )

    # check that importing snapshot with unknown asset_identifier fails.
    csv_dir6 = str(tmpdir_factory.mktemp('test_csv_dir6'))
    _create_snapshot_with_unknown_asset(csv_dir6, ts)
    response = requests.put(
        api_url_for(
            rotkehlchen_api_server,
            'dbsnapshotimportingresource',
        ),
        json={
            'balances_snapshot_file':
            f'{csv_dir6}/{BALANCES_FOR_IMPORT_FILENAME}',
            'location_data_snapshot_file':
            f'{csv_dir6}/{LOCATION_DATA_IMPORT_FILENAME}',
        },
    )
    assert_error_response(
        response,
        contained_in_msg='snapshot contains an unknown asset',
        status_code=HTTPStatus.CONFLICT,
    )
Esempio n. 28
0
def test_users_by_name_endpoint_errors(rotkehlchen_api_server, username,
                                       db_password):
    """Test that user by name endpoint errors are handled (for login/logout and edit)"""
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    # Now let's try to login while the user is already logged in
    data = {
        'action': 'login',
        'password': db_password,
        'sync_approval': 'unknown'
    }
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    expected_msg = (
        f'Can not login to user {username} because user {username} is '
        f'already logged in. Log out of that user first')
    assert_error_response(
        response=response,
        contained_in_msg=expected_msg,
        status_code=HTTPStatus.CONFLICT,
    )
    assert rotki.user_is_logged_in is True

    # Logout of the active user
    data = {'action': 'logout'}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_simple_ok_response(response)
    assert rotki.user_is_logged_in is False

    # Now let's try to login with an invalid password
    data = {
        'action': 'login',
        'password': '******',
        'sync_approval': 'unknown'
    }
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_error_response(
        response=response,
        contained_in_msg='Wrong password or invalid/corrupt database for user',
        status_code=HTTPStatus.UNAUTHORIZED,
    )
    assert rotki.user_is_logged_in is False

    # Login action without a password
    data = {'action': 'login', 'sync_approval': 'unknown'}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_error_response(
        response=response,
        contained_in_msg='Missing password field for login',
        status_code=HTTPStatus.BAD_REQUEST,
    )
    assert rotki.user_is_logged_in is False

    # No action and no premium credentials
    data = {'sync_approval': 'unknown'}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_error_response(
        response=response,
        contained_in_msg=
        'Without an action premium api key and secret must be provided',
        status_code=HTTPStatus.BAD_REQUEST,
    )
    assert rotki.user_is_logged_in is False

    # No action and only premium key
    data = {'sync_approval': 'unknown', 'premium_api_key': VALID_PREMIUM_KEY}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_error_response(
        response=response,
        contained_in_msg=
        'Without an action premium api key and secret must be provided',
        status_code=HTTPStatus.BAD_REQUEST,
    )
    assert rotki.user_is_logged_in is False

    # No action and only premium secret
    data = {
        'sync_approval': 'unknown',
        'premium_api_secret': VALID_PREMIUM_SECRET
    }
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_error_response(
        response=response,
        contained_in_msg=
        'Without an action premium api key and secret must be provided',
        status_code=HTTPStatus.BAD_REQUEST,
    )
    assert rotki.user_is_logged_in is False

    # Invalid action type
    data = {
        'action': 555.3,
        'password': db_password,
        'sync_approval': 'unknown'
    }
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_error_response(
        response=response,
        contained_in_msg='Not a valid string',
        status_code=HTTPStatus.BAD_REQUEST,
    )
    assert rotki.user_is_logged_in is False

    # Invalid action string
    data = {
        'action': 'chopwood',
        'password': db_password,
        'sync_approval': 'unknown'
    }
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_error_response(
        response=response,
        contained_in_msg='Must be one of: login, logout',
        status_code=HTTPStatus.BAD_REQUEST,
    )
    assert rotki.user_is_logged_in is False

    # Invalid password type
    data = {'action': 'login', 'password': True, 'sync_approval': 'unknown'}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_error_response(
        response=response,
        contained_in_msg='Not a valid string',
        status_code=HTTPStatus.BAD_REQUEST,
    )
    assert rotki.user_is_logged_in is False
Esempio n. 29
0
def test_user_login(rotkehlchen_api_server, username, db_password, data_dir):
    """Test that user login works properly"""
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen

    # Let's pretend there is another user, and try to create them again
    Path(data_dir / 'another_user').mkdir()
    Path(data_dir / 'another_user' / 'rotkehlchen.db').touch()

    # Check users status
    users_data = check_user_status(rotkehlchen_api_server)
    assert len(users_data) == 2
    assert users_data[username] == 'loggedin'
    assert users_data['another_user'] == 'loggedout'

    # Logout of the active user
    data = {'action': 'logout'}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_simple_ok_response(response)
    assert rotki.user_is_logged_in is False
    users_data = check_user_status(rotkehlchen_api_server)
    assert len(users_data) == 2
    assert users_data[username] == 'loggedout'
    assert users_data['another_user'] == 'loggedout'

    # Now let's try to login
    data = {
        'action': 'login',
        "password": db_password,
        'sync_approval': 'unknown'
    }
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    # And make sure it works
    assert_proper_response(response)
    check_proper_unlock_result(response.json())
    assert rotki.user_is_logged_in is True
    users_data = check_user_status(rotkehlchen_api_server)
    assert len(users_data) == 2
    assert users_data[username] == 'loggedin'
    assert users_data['another_user'] == 'loggedout'

    # Logout again
    data = {'action': 'logout'}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_simple_ok_response(response)
    assert rotki.user_is_logged_in is False
    users_data = check_user_status(rotkehlchen_api_server)
    assert len(users_data) == 2
    assert users_data[username] == 'loggedout'
    assert users_data['another_user'] == 'loggedout'

    # Now try to login with a wrong password
    data = {
        'action': 'login',
        "password": '******',
        'sync_approval': 'unknown'
    }
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    # And make sure it fails
    assert_error_response(
        response=response,
        contained_in_msg='Wrong password or invalid/corrupt database for user',
        status_code=HTTPStatus.UNAUTHORIZED,
    )
    users_data = check_user_status(rotkehlchen_api_server)
    assert len(users_data) == 2
    assert users_data[username] == 'loggedout'
    assert users_data['another_user'] == 'loggedout'

    # Now let's manually add valid but not authenticable premium credentials in the DB
    data = {
        'action': 'login',
        "password": db_password,
        'sync_approval': 'unknown'
    }
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    credentials = PremiumCredentials(VALID_PREMIUM_KEY, VALID_PREMIUM_SECRET)
    rotki.data.db.set_rotkehlchen_premium(credentials)
    data = {'action': 'logout'}
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    assert_simple_ok_response(response)
    assert rotki.user_is_logged_in is False
    # And try to login while having these unauthenticable premium credentials in the DB
    data = {
        'action': 'login',
        "password": db_password,
        'sync_approval': 'unknown'
    }
    response = requests.patch(
        api_url_for(rotkehlchen_api_server,
                    "usersbynameresource",
                    name=username),
        json=data,
    )
    # And make sure it works despite having unauthenticable premium credentials in the DB
    assert_proper_response(response)
    check_proper_unlock_result(response.json())
    assert rotki.user_is_logged_in is True
    users_data = check_user_status(rotkehlchen_api_server)
    assert len(users_data) == 2
    assert users_data[username] == 'loggedin'
    assert users_data['another_user'] == 'loggedout'
Esempio n. 30
0
def test_user_password_change(rotkehlchen_api_server, username, db_password):
    """
    Test that changing a logged-in user's users password works successfully and that
    common errors are handled.
    """

    # wrong username
    data_wrong_user = {
        'name': 'billybob',
        'current_password': '******',
        'new_password': '******',
    }
    response = requests.patch(api_url_for(rotkehlchen_api_server,
                                          "userpasswordchangeresource",
                                          name=username),
                              json=data_wrong_user)
    msg = (
        f'Provided user "{data_wrong_user["name"]}" is not the logged in user')
    assert_error_response(
        response=response,
        contained_in_msg=msg,
        status_code=HTTPStatus.BAD_REQUEST,
    )

    # wrong password
    data_wrong_pass = {
        'name': username,
        'current_password': '******',
        'new_password': '******',
    }
    response = requests.patch(api_url_for(rotkehlchen_api_server,
                                          "userpasswordchangeresource",
                                          name=username),
                              json=data_wrong_pass)
    msg = ('Provided current password is not correct')
    assert_error_response(
        response=response,
        contained_in_msg=msg,
        status_code=HTTPStatus.UNAUTHORIZED,
    )

    # success
    data_success = {
        'name': username,
        'current_password': db_password,
        'new_password': '******',
    }
    response = requests.patch(api_url_for(rotkehlchen_api_server,
                                          "userpasswordchangeresource",
                                          name=username),
                              json=data_success)
    assert_simple_ok_response(response)

    # revert password
    data_revert = {
        'name': username,
        'current_password': data_success['new_password'],
        'new_password': db_password,
    }
    response = requests.patch(api_url_for(rotkehlchen_api_server,
                                          "userpasswordchangeresource",
                                          name=username),
                              json=data_revert)
    assert_simple_ok_response(response)