Repository: rotki/rotki

Issue:
Pressing the upload DB button for premium users fails.
## Problem Definition

![2023-08-18_09-29](https://github.com/rotki/rotki/assets/1658405/754ff3e8-561f-40b6-a11e-258df2d2c99a)


## Logs

```
[18/08/2023 09:27:05 CEST] ERROR rotkehlchen.api.rest Greenlet with id 140113331603520: Greenlet for task 37 dies with exception: RestAPI.sync_data() got an unexpected keyword argument 'perform_migrations'.
Exception Name: <class 'TypeError'>
Exception Info: RestAPI.sync_data() got an unexpected keyword argument 'perform_migrations'
Traceback:
   File "src/gevent/greenlet.py", line 908, in gevent._gevent_cgreenlet.Greenlet.run
  File "rotkehlchen/api/rest.py", line 369, in _do_query_async
```

### System Description


Operating system: All
Rotki version: 1.30.0



Discussion:

Resolving patch:
diff --git a/rotkehlchen/api/v1/resources.py b/rotkehlchen/api/v1/resources.py
--- a/rotkehlchen/api/v1/resources.py
+++ b/rotkehlchen/api/v1/resources.py
@@ -1284,7 +1284,6 @@ def put(self, async_query: bool, action: Literal['upload', 'download']) -> Respo
         return self.rest_api.sync_data(
             async_query=async_query,
             action=action,
-            perform_migrations=True,  # we can do migrations since all is initialized by now
         )
 
 
diff --git a/rotkehlchen/premium/premium.py b/rotkehlchen/premium/premium.py
--- a/rotkehlchen/premium/premium.py
+++ b/rotkehlchen/premium/premium.py
@@ -8,6 +8,7 @@
 from collections.abc import Sequence
 from enum import Enum
 from http import HTTPStatus
+from json import JSONDecodeError
 from typing import Any, Literal, NamedTuple, Optional
 from urllib.parse import urlencode
 
@@ -42,10 +43,14 @@ class RemoteMetadata(NamedTuple):
     data_size: int
 
 
+DEFAULT_ERROR_MSG = 'Failed to contact rotki server. Check logs for more details'
+DEFAULT_OK_CODES = (HTTPStatus.OK, HTTPStatus.UNAUTHORIZED, HTTPStatus.BAD_REQUEST)
+
+
 def check_response_status_code(
         response: requests.Response,
         status_codes: Sequence[HTTPStatus],
-        user_msg: str = 'Failed to contact rotki server. Check logs for more details',
+        user_msg: str = DEFAULT_ERROR_MSG,
 ) -> None:
     """
     Check the rotki.com response and if status code is not in the expected list
@@ -53,20 +58,29 @@ def check_response_status_code(
     """
     if response.status_code not in status_codes:
         log.error(
-            'rotki server responded with an error response '
+            f'rotki server responded with an error response to {response.url} '
             f'{response.status_code=} and {response.text=}',
         )
         raise RemoteError(user_msg)
 
 
-def _process_dict_response(response: requests.Response) -> dict:
+def _process_dict_response(
+        response: requests.Response,
+        status_codes: Sequence[HTTPStatus] = DEFAULT_OK_CODES,
+        user_msg: str = DEFAULT_ERROR_MSG,
+) -> dict:
     """Processess a dict response returned from the Rotkehlchen server and returns
     the result for success or raises RemoteError if an error happened"""
     check_response_status_code(
         response=response,
-        status_codes=(HTTPStatus.OK, HTTPStatus.UNAUTHORIZED, HTTPStatus.BAD_REQUEST),
+        status_codes=status_codes,
+        user_msg=user_msg,
     )
-    result_dict = jsonloads_dict(response.text)
+    try:
+        result_dict = jsonloads_dict(response.text)
+    except JSONDecodeError as e:
+        log.error(f'Could not decode rotki response {response.text} as json due to {e}')
+        raise RemoteError('Could not decode rotki server response as json. Check logs') from e
 
     if response.status_code == HTTPStatus.UNAUTHORIZED:
         raise PremiumAuthenticationError(result_dict.get('message', 'no message given'))
@@ -273,12 +287,11 @@ def upload_data(
             log.error(msg)
             raise RemoteError(msg) from e
 
-        check_response_status_code(
+        return _process_dict_response(
             response=response,
             status_codes=(HTTPStatus.OK,),
             user_msg='Size limit reached' if response.status_code == HTTPStatus.REQUEST_ENTITY_TOO_LARGE else f'Could not upload database backup due to: {response.text}',  # noqa: E501
         )
-        return _process_dict_response(response)
 
     def pull_data(self) -> Optional[bytes]:
         """Pulls data from the server and returns the binary file with the database encrypted
@@ -338,7 +351,6 @@ def query_last_data_metadata(self) -> RemoteMetadata:
             raise RemoteError(msg) from e
 
         result = _process_dict_response(response)
-
         try:
             metadata = RemoteMetadata(
                 upload_ts=Timestamp(result['upload_ts']),


Test patch:
diff --git a/rotkehlchen/tests/api/test_premium.py b/rotkehlchen/tests/api/test_premium.py
new file mode 100644
--- /dev/null
+++ b/rotkehlchen/tests/api/test_premium.py
@@ -0,0 +1,91 @@
+from contextlib import ExitStack
+from unittest.mock import patch
+
+import pytest
+import requests
+
+from rotkehlchen.tests.utils.api import (
+    api_url_for,
+    assert_error_response,
+    assert_ok_async_response,
+    wait_for_async_task,
+)
+from rotkehlchen.tests.utils.mock import MockResponse
+from rotkehlchen.tests.utils.premium import create_patched_requests_get_for_premium
+
+
+@pytest.mark.parametrize('start_with_valid_premium', [True])
+def test_upload_db(rotkehlchen_api_server):
+    """Just a smoke test that the api works fine. Would have prevented:
+    https://github.com/rotki/rotki/issues/6524.
+
+    We don't test the actual upload here, as the various scenarios are tested in
+    tests/integration/test_premium.py
+    """
+    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
+    patches = [patch.object(
+        rotki.premium.session,
+        verb,
+        return_value=MockResponse(200, '{}'),
+    ) for verb in ('put', 'post')]
+    patches.append(create_patched_requests_get_for_premium(
+        session=rotki.premium.session,
+        metadata_last_modify_ts=0,
+        metadata_data_hash=b'',
+        metadata_data_size=9999999999,
+        saved_data=b'foo',
+    ))
+
+    with ExitStack() as stack:
+        [stack.enter_context(patch) for patch in patches]  # pylint: disable=expression-not-assigned  # noqa: E501
+        response = requests.put(api_url_for(
+            rotkehlchen_api_server,  # testing normal flow works fine
+            'userpremiumsyncresource',
+        ), json={'async_query': True, 'action': 'upload'})
+        task_id = assert_ok_async_response(response)
+        result = wait_for_async_task(rotkehlchen_api_server, task_id)
+        assert result['message'] == ''
+        assert result['result'] is True
+
+        response = requests.put(api_url_for(
+            rotkehlchen_api_server,  # test for invalid action arg
+            'userpremiumsyncresource',
+        ), json={'async_query': True, 'action': 'invalid_action'})
+        assert_error_response(response, contained_in_msg='Must be one of: upload, download')
+
+
+@pytest.mark.parametrize('start_with_valid_premium', [True])
+def test_pull_db(rotkehlchen_api_server):
+    """Just a smoke test that the api works fine for this endpoint.
+
+    Actual functionality tested in tests/integration/test_premium.py
+    """
+    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
+    patches = [patch.object(
+        rotki.premium.session,
+        verb,
+        return_value=MockResponse(200, '{}'),
+    ) for verb in ('put', 'post')]
+    patches.append(create_patched_requests_get_for_premium(
+        session=rotki.premium.session,
+        metadata_last_modify_ts=0,
+        metadata_data_hash=b'',
+        metadata_data_size=9999999999,
+        saved_data=b'foo',
+    ))
+    patches.append(patch.object(
+        rotki.premium_sync_manager.data,
+        'decompress_and_decrypt_db',
+        return_value=None,
+    ))
+
+    with ExitStack() as stack:
+        [stack.enter_context(patch) for patch in patches]  # pylint: disable=expression-not-assigned  # noqa: E501
+        response = requests.put(api_url_for(
+            rotkehlchen_api_server,  # testing normal flow works fine
+            'userpremiumsyncresource',
+        ), json={'async_query': True, 'action': 'download'})
+        task_id = assert_ok_async_response(response)
+        result = wait_for_async_task(rotkehlchen_api_server, task_id)
+        assert result['message'] == ''
+        assert result['result'] is True