Repository: rotki/rotki

Issue:
If local premium DB is larger and more recent than remote don't ask user for replacement
## Problem Definition

If local premium DB is larger and more recent than remote don't ask user for replacement and instead replace remote.

![2020-10-15_15-27](https://user-images.githubusercontent.com/1658405/96132684-f762eb00-0efa-11eb-9ca9-8d72df1d3c35.png)

## Task

Do it lol


Discussion:

Resolving patch:
diff --git a/rotkehlchen/premium/sync.py b/rotkehlchen/premium/sync.py
--- a/rotkehlchen/premium/sync.py
+++ b/rotkehlchen/premium/sync.py
@@ -82,18 +82,21 @@ def _can_sync_data_from_server(self, new_account: bool) -> SyncCheckResult:
 
         our_last_write_ts = self.data.db.get_last_write_ts()
         data_bytes_size = len(base64.b64decode(b64_encoded_data))
-        if our_last_write_ts >= metadata.last_modify_ts:
+
+        local_more_recent = our_last_write_ts >= metadata.last_modify_ts
+        local_bigger = data_bytes_size >= metadata.data_size
+
+        if local_more_recent and local_bigger:
+            log.debug('sync from server stopped -- local is both newer and bigger')
+            return SyncCheckResult(can_sync=CanSync.NO, message='', payload=None)
+
+        if local_more_recent is False:  # remote is more recent
             message = (
-                'Detected remote database BUT with older last modification timestamp '
+                'Detected remote database with more recent modification timestamp '
                 'than the local one. '
             )
-        else:
-            if data_bytes_size > metadata.data_size:
-                message = (
-                    'Detected newer remote database BUT with smaller size than the local one. '
-                )
-            else:
-                message = 'Detected newer remote database. '
+        else:  # remote is bigger
+            message = 'Detected remote database with bigger size than the local one. '
 
         return SyncCheckResult(
             can_sync=CanSync.ASK_USER,
@@ -254,7 +257,7 @@ def try_premium_at_start(
         result = self._can_sync_data_from_server(new_account=create_new)
         if result.can_sync == CanSync.ASK_USER:
             if sync_approval == 'unknown':
-                log.info('DB data at server newer than local')
+                log.info('Remote DB is possibly newer. Ask user.')
                 raise RotkehlchenPermissionError(result.message, result.payload)
             elif sync_approval == 'yes':
                 log.info('User approved data sync from server')


Test patch:
diff --git a/rotkehlchen/tests/integration/test_premium.py b/rotkehlchen/tests/integration/test_premium.py
--- a/rotkehlchen/tests/integration/test_premium.py
+++ b/rotkehlchen/tests/integration/test_premium.py
@@ -6,11 +6,16 @@
 from rotkehlchen.constants import ROTKEHLCHEN_SERVER_TIMEOUT
 from rotkehlchen.constants.assets import A_EUR, A_GBP
 from rotkehlchen.db.settings import ModifiableDBSettings
-from rotkehlchen.errors import IncorrectApiKeyFormat, PremiumAuthenticationError
+from rotkehlchen.errors import (
+    IncorrectApiKeyFormat,
+    PremiumAuthenticationError,
+    RotkehlchenPermissionError,
+)
 from rotkehlchen.premium.premium import PremiumCredentials
 from rotkehlchen.tests.utils.constants import DEFAULT_TESTS_MAIN_CURRENCY
 from rotkehlchen.tests.utils.mock import MockResponse
 from rotkehlchen.tests.utils.premium import (
+    INVALID_BUT_BIGGER_REMOTE_DATA,
     REMOTE_DATA_OLDER_DB,
     VALID_PREMIUM_KEY,
     VALID_PREMIUM_SECRET,
@@ -282,7 +287,7 @@ def test_try_premium_at_start_old_account_same_hash(
 
 
 @pytest.mark.parametrize('start_with_valid_premium', [True])
-def test_try_premium_at_start_old_account_older_remote_ts(
+def test_try_premium_at_start_old_account_older_remote_ts_smaller_remote_size(
         rotkehlchen_instance,
         username,
         db_password,
@@ -298,7 +303,53 @@ def test_try_premium_at_start_old_account_older_remote_ts(
         newer_remote_db=False,
         db_can_sync_setting=True,
     )
-    assert_db_got_replaced(rotkehlchen_instance=rotkehlchen_instance, username=username)
+    # DB should not have changed
+    assert rotkehlchen_instance.data.db.get_main_currency() == DEFAULT_TESTS_MAIN_CURRENCY
+
+
+@pytest.mark.parametrize('start_with_valid_premium', [True])
+def test_try_premium_at_start_old_account_newer_remote_ts_smaller_remote_size(
+        rotkehlchen_instance,
+        username,
+        db_password,
+        rotki_premium_credentials,
+):
+    """Assure that newer remote ts and smaller remote size asks the user for sync"""
+    with pytest.raises(RotkehlchenPermissionError):
+        setup_starting_environment(
+            rotkehlchen_instance=rotkehlchen_instance,
+            username=username,
+            db_password=db_password,
+            premium_credentials=rotki_premium_credentials,
+            first_time=False,
+            same_hash_with_remote=False,
+            newer_remote_db=True,
+            db_can_sync_setting=True,
+            sync_approval='unknown',
+        )
+
+
+@pytest.mark.parametrize('start_with_valid_premium', [True])
+def test_try_premium_at_start_old_account_older_remote_ts_bigger_remote_size(
+        rotkehlchen_instance,
+        username,
+        db_password,
+        rotki_premium_credentials,
+):
+    """Assure that older remote ts but bigger remote size asks the user for sync"""
+    with pytest.raises(RotkehlchenPermissionError):
+        setup_starting_environment(
+            rotkehlchen_instance=rotkehlchen_instance,
+            username=username,
+            db_password=db_password,
+            premium_credentials=rotki_premium_credentials,
+            first_time=False,
+            same_hash_with_remote=False,
+            newer_remote_db=False,
+            db_can_sync_setting=True,
+            sync_approval='unknown',
+            remote_data=INVALID_BUT_BIGGER_REMOTE_DATA,
+        )
 
 
 @pytest.mark.parametrize('start_with_valid_premium', [True])
diff --git a/rotkehlchen/tests/utils/premium.py b/rotkehlchen/tests/utils/premium.py
--- a/rotkehlchen/tests/utils/premium.py
+++ b/rotkehlchen/tests/utils/premium.py
@@ -5,13 +5,18 @@
 from typing import Optional
 from unittest.mock import patch
 
+from typing_extensions import Literal
+
 from rotkehlchen.constants import ROTKEHLCHEN_SERVER_TIMEOUT
 from rotkehlchen.constants.assets import A_GBP
 from rotkehlchen.premium.premium import Premium, PremiumCredentials
 from rotkehlchen.rotkehlchen import Rotkehlchen
 from rotkehlchen.tests.utils.constants import DEFAULT_TESTS_MAIN_CURRENCY
+from rotkehlchen.tests.utils.factories import make_random_b64bytes
 from rotkehlchen.tests.utils.mock import MockResponse
 
+# Probably invalid remote data but bigger than the test local DB
+INVALID_BUT_BIGGER_REMOTE_DATA = base64.b64encode(make_random_b64bytes(16048)).decode()
 # Remote data containing a different main currency (GBP)
 REMOTE_DATA = b'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'  # noqa: E501
 # Remote data containing an older DB version
@@ -142,6 +147,7 @@ def setup_starting_environment(
         db_can_sync_setting: bool,
         premium_credentials: PremiumCredentials,
         remote_data: bytes = REMOTE_DATA,
+        sync_approval: Literal['yes', 'no', 'unknown'] = 'yes',
 ):
     """
     Sets up the starting environment for premium testing when the user
@@ -172,7 +178,7 @@ def setup_starting_environment(
         patch_get=True,
         metadata_last_modify_ts=metadata_last_modify_ts,
         metadata_data_hash=remote_hash,
-        metadata_data_size=len(base64.b64decode(REMOTE_DATA)),
+        metadata_data_size=len(base64.b64decode(remote_data)) if remote_data else 0,
         saved_data=remote_data,
     )
 
@@ -189,7 +195,7 @@ def setup_starting_environment(
             given_premium_credentials=given_premium_credentials,
             username=username,
             create_new=create_new,
-            sync_approval='yes',
+            sync_approval=sync_approval,
         )