Repository: rotki/rotki

Issue:
Speed up uniswap unit tests
## Problem Definition

The uniswap unit tests seemed a bit slow to me compared to other unit tests. I think it's because in each test you instantiate the uniswap fixture: https://github.com/rotki/rotki/blob/c0e01b71a8da1de2debb50e91f992add599013fe/rotkehlchen/tests/unit/uniswap/conftest.py#L22

Underneath that also instantiates a Graph object. For each Graph instantiation a roundtrip to the graph server needs to be made.

## Task

To fix that just mock away the uniswap's Graph object for the unit tests. If I am not mistake no graph queries are made in those tests.




Discussion:
This issue is related with #1727, in fact it could removed and keep it all here.
The first endpoint implementation didn't use fake injection, therefore the graph was mocked in the test suite.

Resolving patch:
diff --git a/rotkehlchen/chain/ethereum/uniswap/uniswap.py b/rotkehlchen/chain/ethereum/uniswap/uniswap.py
--- a/rotkehlchen/chain/ethereum/uniswap/uniswap.py
+++ b/rotkehlchen/chain/ethereum/uniswap/uniswap.py
@@ -2,7 +2,7 @@
 from collections import defaultdict
 from datetime import datetime, time
 from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, Union
+from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Set, Tuple, Union
 
 from eth_utils import to_checksum_address
 from gevent.lock import Semaphore
@@ -198,10 +198,9 @@ def _calculate_events_balances(
 
         return events_balances
 
-    @staticmethod
     def _get_balances_graph(
-        addresses: List[ChecksumEthAddress],
-        graph_query: Callable,
+            self,
+            addresses: List[ChecksumEthAddress],
     ) -> ProtocolBalance:
         """Get the addresses' pools data querying the Uniswap subgraph
 
@@ -226,7 +225,7 @@ def _get_balances_graph(
             'balance': '0',
         }
         while True:
-            result = graph_query(
+            result = self.graph.query(  # type: ignore # caller already checks
                 querystr=querystr,
                 param_types=param_types,
                 param_values=param_values,
@@ -331,7 +330,6 @@ def get_balances_chain(self, addresses: List[ChecksumEthAddress]) -> ProtocolBal
     def _get_known_asset_price(
             known_assets: Set[EthereumToken],
             unknown_assets: Set[UnknownEthereumToken],
-            price_query: Callable,
     ) -> AssetPrice:
         """Get the tokens prices via Inquirer
 
@@ -341,7 +339,7 @@ def _get_known_asset_price(
         asset_price: AssetPrice = {}
 
         for known_asset in known_assets:
-            asset_usd_price = price_query(known_asset)
+            asset_usd_price = Inquirer().find_usd_price(known_asset)
 
             if asset_usd_price != Price(ZERO):
                 asset_price[known_asset.ethereum_address] = asset_usd_price
@@ -834,10 +832,9 @@ def _get_trades_graph_for_address(
             }
         return trades
 
-    @staticmethod
     def _get_unknown_asset_price_graph(
+            self,
             unknown_assets: Set[UnknownEthereumToken],
-            graph_query: Callable,
     ) -> AssetPrice:
         """Get today's tokens prices via the Uniswap subgraph
 
@@ -869,7 +866,7 @@ def _get_unknown_asset_price_graph(
             'datetime': today_epoch,
         }
         while True:
-            result = graph_query(
+            result = self.graph.query(  # type: ignore # caller already checks
                 querystr=querystr,
                 param_types=param_types,
                 param_values=param_values,
@@ -933,13 +930,10 @@ def get_balances(
         Premium users can request balances either via the Uniswap subgraph or
         on-chain.
         """
-        is_graph_mode = self.graph and self.premium
+        is_graph_mode = self.graph is not None and self.premium
 
         if is_graph_mode:
-            protocol_balance = self._get_balances_graph(
-                addresses=addresses,
-                graph_query=self.graph.query,  # type: ignore # caller already checks
-            )
+            protocol_balance = self._get_balances_graph(addresses=addresses)
         else:
             protocol_balance = self.get_balances_chain(addresses)
 
@@ -949,15 +943,11 @@ def get_balances(
         known_asset_price = self._get_known_asset_price(
             known_assets=known_assets,
             unknown_assets=unknown_assets,
-            price_query=Inquirer().find_usd_price,
         )
 
         unknown_asset_price: AssetPrice = {}
         if is_graph_mode:
-            unknown_asset_price = self._get_unknown_asset_price_graph(
-                unknown_assets=unknown_assets,
-                graph_query=self.graph.query,  # type: ignore # caller already checks
-            )
+            unknown_asset_price = self._get_unknown_asset_price_graph(unknown_assets=unknown_assets)  # noqa:E501
 
         self._update_assets_prices_in_address_balances(
             address_balances=protocol_balance.address_balances,


Test patch:
diff --git a/rotkehlchen/tests/db/test_utils.py b/rotkehlchen/tests/db/test_utils.py
--- a/rotkehlchen/tests/db/test_utils.py
+++ b/rotkehlchen/tests/db/test_utils.py
@@ -11,7 +11,7 @@
             'timestamp',
             None,
             None,
-            'SELECT * FROM adex_events ORDER BY timestamp ASC;',  # noqa:E501
+            'SELECT * FROM adex_events ORDER BY timestamp ASC;',
             (),
         ),
         (
diff --git a/rotkehlchen/tests/unit/uniswap/conftest.py b/rotkehlchen/tests/unit/uniswap/conftest.py
--- a/rotkehlchen/tests/unit/uniswap/conftest.py
+++ b/rotkehlchen/tests/unit/uniswap/conftest.py
@@ -1,4 +1,4 @@
-from unittest.mock import MagicMock, patch
+from unittest.mock import patch
 
 import pytest
 
@@ -6,14 +6,30 @@
 from rotkehlchen.premium.premium import Premium
 
 
+@pytest.fixture(name='mock_graph')
+def fixture_graph():
+    with patch('rotkehlchen.chain.ethereum.uniswap.uniswap.Graph'):
+        yield
+
+
+@pytest.fixture(name='mock_graph_query_limit')
+def fixture_graph_query_limit(graph_query_limit):
+    with patch(
+        'rotkehlchen.chain.ethereum.uniswap.uniswap.GRAPH_QUERY_LIMIT',
+        new=graph_query_limit,
+    ):
+        yield
+
+
 @pytest.fixture
-def uniswap_module(
+def mock_uniswap(
         ethereum_manager,
         database,
         start_with_valid_premium,
         rotki_premium_credentials,
         function_scope_messages_aggregator,
         data_dir,
+        mock_graph,  # pylint: disable=unused-argument
 ) -> Uniswap:
     premium = None
 
@@ -28,12 +44,3 @@ def uniswap_module(
         data_directory=data_dir,
     )
     return uniswap
-
-
-@pytest.fixture
-def patch_graph_query_limit(graph_query_limit):
-    with patch(
-        'rotkehlchen.chain.ethereum.uniswap.uniswap.GRAPH_QUERY_LIMIT',
-        new_callable=MagicMock(return_value=graph_query_limit),
-    ):
-        yield
diff --git a/rotkehlchen/tests/unit/uniswap/test_get_balances_graph.py b/rotkehlchen/tests/unit/uniswap/test_get_balances_graph.py
--- a/rotkehlchen/tests/unit/uniswap/test_get_balances_graph.py
+++ b/rotkehlchen/tests/unit/uniswap/test_get_balances_graph.py
@@ -3,10 +3,10 @@
 from rotkehlchen.chain.ethereum.uniswap.typing import ProtocolBalance
 
 from .utils import (
-    EXP_LIQUIDITY_POOL_1,
-    EXP_LIQUIDITY_POOL_2,
     EXP_KNOWN_ASSETS_1,
     EXP_KNOWN_ASSETS_2,
+    EXP_LIQUIDITY_POOL_1,
+    EXP_LIQUIDITY_POOL_2,
     EXP_UNKNOWN_ASSETS_1,
     EXP_UNKNOWN_ASSETS_2,
     LIQUIDITY_POSITION_1,
@@ -18,24 +18,15 @@
 )
 
 
-def test_single_address_balance(uniswap_module):
+def test_single_address_balance(mock_uniswap):
     """Test <ProtocolBalance> contains the following data:
 
         - TEST_ADDRESS_1: has 1 LP (LIQUIDITY_POSITION_1)
     """
-    def fake_graph_query(
-        *args,  # pylint: disable=unused-argument
-        **kwargs,  # pylint: disable=unused-argument
-    ):
-        return {'liquidityPositions': [LIQUIDITY_POSITION_1]}
-
+    mock_uniswap.graph.query.return_value = {'liquidityPositions': [LIQUIDITY_POSITION_1]}
     addresses = [TEST_ADDRESS_1]
 
-    # Main call
-    protocol_balance = uniswap_module._get_balances_graph(
-        addresses=addresses,
-        graph_query=fake_graph_query,
-    )
+    protocol_balance = mock_uniswap._get_balances_graph(addresses=addresses)
 
     exp_protocol_balance = ProtocolBalance(
         address_balances={TEST_ADDRESS_1: [EXP_LIQUIDITY_POOL_1]},
@@ -45,7 +36,7 @@ def fake_graph_query(
     assert exp_protocol_balance == protocol_balance
 
 
-def test_multiple_addresses_balances(uniswap_module):
+def test_multiple_addresses_balances(mock_uniswap):
     """Test <ProtocolBalance> contains the following data:
 
         - TEST_ADDRESS_1: has 1 LP (LIQUIDITY_POSITION_1)
@@ -53,21 +44,12 @@ def test_multiple_addresses_balances(uniswap_module):
 
     As TEST_ADDRESS_3 has no LPs is not included.
     """
-    def fake_graph_query(
-        *args,  # pylint: disable=unused-argument
-        **kwargs,  # pylint: disable=unused-argument
-    ):
-        return {
-            'liquidityPositions': [LIQUIDITY_POSITION_1, LIQUIDITY_POSITION_2],
-        }
-
+    mock_uniswap.graph.query.return_value = {
+        'liquidityPositions': [LIQUIDITY_POSITION_1, LIQUIDITY_POSITION_2],
+    }
     addresses = [TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3]
 
-    # Main call
-    protocol_balance = uniswap_module._get_balances_graph(
-        addresses=addresses,
-        graph_query=fake_graph_query,
-    )
+    protocol_balance = mock_uniswap._get_balances_graph(addresses=addresses)
 
     exp_protocol_balance = ProtocolBalance(
         address_balances={
@@ -82,10 +64,10 @@ def fake_graph_query(
 
 @pytest.mark.parametrize("graph_query_limit, no_requests", [(2, 2), (3, 1)])
 def test_pagination(
-        uniswap_module,
+        mock_uniswap,
         graph_query_limit,
         no_requests,
-        patch_graph_query_limit,  # pylint: disable=unused-argument
+        mock_graph_query_limit,  # pylint: disable=unused-argument
 ):
     """Test an extra graph request is done when the number of items in the
     response equals GRAPH_QUERY_LIMIT.
@@ -101,25 +83,20 @@ def get_graph_response():
             yield response
 
     @store_call_args
-    def fake_graph_query(
+    def mock_response(
         *args,  # pylint: disable=unused-argument
         **kwargs,  # pylint: disable=unused-argument
     ):
         return next(get_response)
 
-    addresses = [TEST_ADDRESS_1, TEST_ADDRESS_2]
     get_response = get_graph_response()
+    mock_uniswap.graph.query.side_effect = mock_response
+    addresses = [TEST_ADDRESS_1, TEST_ADDRESS_2]
 
-    # Main call
-    uniswap_module._get_balances_graph(
-        addresses=addresses,
-        graph_query=fake_graph_query,
-    )
-
-    assert len(fake_graph_query.calls) == no_requests
+    mock_uniswap._get_balances_graph(addresses=addresses)
 
-    # Check limit and offset
-    for idx, call_args in enumerate(fake_graph_query.calls):
+    assert len(mock_response.calls) == no_requests
+    for idx, call_args in enumerate(mock_response.calls):
         param_values = call_args['kwargs']['param_values']
         assert param_values['limit'] == graph_query_limit
         assert param_values['offset'] == idx * graph_query_limit
diff --git a/rotkehlchen/tests/unit/uniswap/test_get_known_asset_price.py b/rotkehlchen/tests/unit/uniswap/test_get_known_asset_price.py
--- a/rotkehlchen/tests/unit/uniswap/test_get_known_asset_price.py
+++ b/rotkehlchen/tests/unit/uniswap/test_get_known_asset_price.py
@@ -1,56 +1,41 @@
+import pytest
+
 from rotkehlchen.assets.unknown_asset import UnknownEthereumToken
 from rotkehlchen.constants import ZERO
 from rotkehlchen.typing import Price
 
-from .utils import (
-    ASSET_WETH,
-    USD_PRICE_WETH,
-)
+from .utils import ASSET_WETH, USD_PRICE_WETH
 
 
-def test_known_asset_has_usd_price(uniswap_module):
+@pytest.mark.parametrize('mocked_current_prices', [{ASSET_WETH: USD_PRICE_WETH}])
+def test_known_asset_has_usd_price(mock_uniswap, inquirer):  # pylint: disable=unused-argument
     """Test `known_asset_price` contains the known asset address and USD
     price when Inquirer returns a price gt ZERO.
     """
-    def fake_price_query(
-        *args,  # pylint: disable=unused-argument
-        **kwargs,  # pylint: disable=unused-argument
-    ):
-        return USD_PRICE_WETH
-
     known_assets = {ASSET_WETH}
     unknown_assets = set()
 
-    # Main call
-    known_asset_price = uniswap_module._get_known_asset_price(
+    known_asset_price = mock_uniswap._get_known_asset_price(
         known_assets=known_assets,
         unknown_assets=unknown_assets,
-        price_query=fake_price_query,
     )
 
     assert known_asset_price == {ASSET_WETH.ethereum_address: USD_PRICE_WETH}
     assert unknown_assets == set()
 
 
-def test_known_asset_has_zero_usd_price(uniswap_module):
+@pytest.mark.parametrize('mocked_current_prices', [{ASSET_WETH: Price(ZERO)}])
+def test_known_asset_has_zero_usd_price(mock_uniswap, inquirer):  # pylint: disable=unused-argument
     """Test `known_asset_price` is empty and that an <UnknownEthereumToken>
     has been added in `unknown_assets` when Inquirer returns a price eq
     ZERO.
     """
-    def fake_price_query(
-        *args,  # pylint: disable=unused-argument
-        **kwargs,  # pylint: disable=unused-argument
-    ):
-        return Price(ZERO)
-
     known_assets = {ASSET_WETH}
     unknown_assets = set()
 
-    # Main call
-    known_asset_price = uniswap_module._get_known_asset_price(
+    known_asset_price = mock_uniswap._get_known_asset_price(
         known_assets=known_assets,
         unknown_assets=unknown_assets,
-        price_query=fake_price_query,
     )
 
     assert known_asset_price == {}
diff --git a/rotkehlchen/tests/unit/uniswap/test_get_unknown_asset_price.py b/rotkehlchen/tests/unit/uniswap/test_get_unknown_asset_price.py
--- a/rotkehlchen/tests/unit/uniswap/test_get_unknown_asset_price.py
+++ b/rotkehlchen/tests/unit/uniswap/test_get_unknown_asset_price.py
@@ -6,44 +6,26 @@
 from .utils import ASSET_SHUF, ASSET_TGX, TOKEN_DAY_DATA_SHUF, TOKEN_DAY_DATA_TGX, store_call_args
 
 
-def test_unknown_asset_does_not_have_usd_price(uniswap_module):
+def test_unknown_asset_does_not_have_usd_price(mock_uniswap):
     """Test returned `asset_price` is empty when the unknown asset price is
     not found via subgraph.
     """
-    def fake_graph_query(
-        *args,  # pylint: disable=unused-argument
-        **kwargs,  # pylint: disable=unused-argument
-    ):
-        return {'tokenDayDatas': []}
-
+    mock_uniswap.graph.query.return_value = {'tokenDayDatas': []}
     unknown_assets = {ASSET_TGX}
 
-    # Main call
-    asset_price = uniswap_module._get_unknown_asset_price_graph(
-        unknown_assets=unknown_assets,
-        graph_query=fake_graph_query,
-    )
+    asset_price = mock_uniswap._get_unknown_asset_price_graph(unknown_assets=unknown_assets)
 
     assert asset_price == {}
 
 
-def test_unknown_asset_has_usd_price(uniswap_module):
+def test_unknown_asset_has_usd_price(mock_uniswap):
     """Test returned `asset_price` contains the unknown token address and
     its USD price when the price is found via subgraph.
     """
-    def fake_graph_query(
-        *args,  # pylint: disable=unused-argument
-        **kwargs,  # pylint: disable=unused-argument
-    ):
-        return {'tokenDayDatas': [TOKEN_DAY_DATA_TGX]}
-
+    mock_uniswap.graph.query.return_value = {'tokenDayDatas': [TOKEN_DAY_DATA_TGX]}
     unknown_assets = {ASSET_TGX}
 
-    # Main call
-    asset_price = uniswap_module._get_unknown_asset_price_graph(
-        unknown_assets=unknown_assets,
-        graph_query=fake_graph_query,
-    )
+    asset_price = mock_uniswap._get_unknown_asset_price_graph(unknown_assets=unknown_assets)
 
     exp_asset_price = {
         ASSET_TGX.ethereum_address: Price(FVal(TOKEN_DAY_DATA_TGX['priceUSD'])),
@@ -53,10 +35,10 @@ def fake_graph_query(
 
 @pytest.mark.parametrize("graph_query_limit, no_requests", [(2, 2), (3, 1)])
 def test_pagination(
-        uniswap_module,
+        mock_uniswap,
         graph_query_limit,
         no_requests,
-        patch_graph_query_limit,  # pylint: disable=unused-argument
+        mock_graph_query_limit,  # pylint: disable=unused-argument
 ):
     """Test an extra graph request is done when the number of items in the
     response equals GRAPH_QUERY_LIMIT.
@@ -72,25 +54,20 @@ def get_graph_response():
             yield response
 
     @store_call_args
-    def fake_graph_query(
+    def mock_response(
         *args,  # pylint: disable=unused-argument
         **kwargs,  # pylint: disable=unused-argument
     ):
         return next(get_response)
 
-    unknown_assets = {ASSET_TGX, ASSET_SHUF}
     get_response = get_graph_response()
+    mock_uniswap.graph.query.side_effect = mock_response
+    unknown_assets = {ASSET_TGX, ASSET_SHUF}
 
-    # Main call
-    uniswap_module._get_unknown_asset_price_graph(
-        unknown_assets=unknown_assets,
-        graph_query=fake_graph_query,
-    )
-
-    assert len(fake_graph_query.calls) == no_requests
+    mock_uniswap._get_unknown_asset_price_graph(unknown_assets=unknown_assets)
 
-    # Check limit and offset
-    for idx, call_args in enumerate(fake_graph_query.calls):
+    assert len(mock_response.calls) == no_requests
+    for idx, call_args in enumerate(mock_response.calls):
         param_values = call_args['kwargs']['param_values']
         assert param_values['limit'] == graph_query_limit
         assert param_values['offset'] == idx * graph_query_limit
diff --git a/rotkehlchen/tests/unit/uniswap/test_get_update_assets_prices_in_address_balances.py b/rotkehlchen/tests/unit/uniswap/test_get_update_assets_prices_in_address_balances.py
--- a/rotkehlchen/tests/unit/uniswap/test_get_update_assets_prices_in_address_balances.py
+++ b/rotkehlchen/tests/unit/uniswap/test_get_update_assets_prices_in_address_balances.py
@@ -10,14 +10,14 @@
     UPDATED_LIQUIDITY_POOL_1,
     UPDATED_LIQUIDITY_POOL_2,
     UPDATED_LIQUIDITY_POOL_2_ONLY_USDT,
-    USD_PRICE_WETH,
-    USD_PRICE_USDT,
     USD_PRICE_SHUF,
     USD_PRICE_TGX,
+    USD_PRICE_USDT,
+    USD_PRICE_WETH,
 )
 
 
-def test_half_asset_prices_are_updated(uniswap_module):
+def test_half_asset_prices_are_updated(mock_uniswap):
     """Test when an asset price is not found in `known_asset_price`,
     nor in `unknown_asset_price`, its `usd_price` and `usd_value` remain 0,
     and the liquidity pool `usd_value` does not count it.
@@ -32,7 +32,7 @@ def test_half_asset_prices_are_updated(uniswap_module):
     unknown_asset_price = {}  # TGX not in it
 
     # Main call
-    uniswap_module._update_assets_prices_in_address_balances(
+    mock_uniswap._update_assets_prices_in_address_balances(
         address_balances=address_balances,
         known_asset_price=known_asset_price,
         unknown_asset_price=unknown_asset_price,
@@ -44,7 +44,7 @@ def test_half_asset_prices_are_updated(uniswap_module):
     )
 
 
-def test_all_asset_prices_are_updated(uniswap_module):
+def test_all_asset_prices_are_updated(mock_uniswap):
     """Test when all the assets prices are found either in
     `known_asset_price` or `unknown_asset_price`, all pool assets have
     their `usd_price` and `usd_value` updated, and the pool `usd_value` is
@@ -64,7 +64,7 @@ def test_all_asset_prices_are_updated(uniswap_module):
     }
 
     # Main call
-    uniswap_module._update_assets_prices_in_address_balances(
+    mock_uniswap._update_assets_prices_in_address_balances(
         address_balances=address_balances,
         known_asset_price=known_asset_price,
         unknown_asset_price=unknown_asset_price,
diff --git a/rotkehlchen/tests/unit/uniswap/test_swaps_to_trades.py b/rotkehlchen/tests/unit/uniswap/test_swaps_to_trades.py
--- a/rotkehlchen/tests/unit/uniswap/test_swaps_to_trades.py
+++ b/rotkehlchen/tests/unit/uniswap/test_swaps_to_trades.py
@@ -1,4 +1,4 @@
-def test_empty_list(uniswap_module):
+def test_empty_list(mock_uniswap):
     """Test passing empty list of swaps returns empty list
     """
-    assert uniswap_module.swaps_to_trades([]) == []
+    assert mock_uniswap.swaps_to_trades([]) == []