mirror of
https://github.com/gogcom/galaxy-integrations-python-api.git
synced 2026-01-01 03:18:25 -05:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4ded58c28 | ||
|
|
d2f34349b8 | ||
|
|
f062387ddb | ||
|
|
5a699100d6 | ||
|
|
5daa386f6e | ||
|
|
761598de54 | ||
|
|
ab44e137c3 | ||
|
|
948bfcd971 | ||
|
|
6196e751c6 | ||
|
|
a5b2a0890e | ||
|
|
46cda7d61a | ||
|
|
f0f6210c3e | ||
|
|
468dfcc60d | ||
|
|
8f91f705ee | ||
|
|
46588c321e | ||
|
|
947c578121 | ||
|
|
aba9b0ed6b | ||
|
|
f0d65a72ff | ||
|
|
96cb48fcaf | ||
|
|
17b0542fdf |
20
.github/workflows/ci.yml
vendored
Normal file
20
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.7
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements-dev.txt
|
||||
- name: Run tests
|
||||
run: |
|
||||
pytest
|
||||
@@ -7,7 +7,7 @@ stages:
|
||||
test_package:
|
||||
stage: test
|
||||
script:
|
||||
- pip install -r requirements.txt
|
||||
- pip install -r requirements-dev.txt
|
||||
- pytest
|
||||
except:
|
||||
- tags
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
dist: xenial # required for Python >= 3.7
|
||||
language: python
|
||||
python:
|
||||
- "3.7"
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
script:
|
||||
- pytest
|
||||
@@ -1,5 +1,5 @@
|
||||
Sphinx==2.0.1
|
||||
sphinx-rtd-theme==0.4.3
|
||||
sphinx-autodoc-typehints==1.6.0
|
||||
sphinxcontrib-asyncio==0.2.0
|
||||
m2r==0.2.1
|
||||
Sphinx==4.2.0
|
||||
sphinx-rtd-theme==1.0.0
|
||||
sphinx-autodoc-typehints==1.12.0
|
||||
sphinxcontrib-asyncio==0.3.0
|
||||
m2r2==0.3.1
|
||||
@@ -34,7 +34,7 @@ extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinxcontrib.asyncio',
|
||||
'sphinx_autodoc_typehints',
|
||||
'm2r' # mdinclude directive for makrdown files
|
||||
'm2r2' # mdinclude directive for makrdown files
|
||||
]
|
||||
autodoc_member_order = 'bysource'
|
||||
autodoc_inherit_docstrings = False
|
||||
|
||||
7
requirements-dev.txt
Normal file
7
requirements-dev.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
-r requirements.txt
|
||||
pytest==5.2.2
|
||||
pytest-asyncio==0.10.0
|
||||
pytest-mock==1.10.3
|
||||
pytest-mypy==0.4.1
|
||||
pytest-flakes==4.0.0
|
||||
types-certifi==2020.4.0
|
||||
@@ -1,10 +1,7 @@
|
||||
-e .
|
||||
pytest==5.2.2
|
||||
pytest-asyncio==0.10.0
|
||||
pytest-mock==1.10.3
|
||||
pytest-mypy==0.4.1
|
||||
pytest-flakes==4.0.0
|
||||
# because of pip bug https://github.com/pypa/pip/issues/4780
|
||||
# Copied from setup.py because of a pip bug
|
||||
# see https://github.com/pypa/pip/issues/4780
|
||||
aiohttp==3.5.4
|
||||
certifi==2019.3.9
|
||||
psutil==5.6.6; sys_platform == 'darwin'
|
||||
# End of copy from setup.py
|
||||
|
||||
2
setup.py
2
setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="galaxy.plugin.api",
|
||||
version="0.66.0",
|
||||
version="0.69",
|
||||
description="GOG Galaxy Integrations Python API",
|
||||
author='Galaxy team',
|
||||
author_email='galaxy@gog.com',
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
__path__: str = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore
|
||||
import logging
|
||||
|
||||
|
||||
logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
|
||||
__path__: str = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore
|
||||
|
||||
@@ -2,74 +2,87 @@ from galaxy.api.jsonrpc import ApplicationError, UnknownError
|
||||
|
||||
assert UnknownError
|
||||
|
||||
|
||||
class AuthenticationRequired(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(1, "Authentication required", data)
|
||||
def __init__(self, message="Authentication required", data=None):
|
||||
super().__init__(1, message, data)
|
||||
|
||||
|
||||
class BackendNotAvailable(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(2, "Backend not available", data)
|
||||
def __init__(self, message="Backend not available", data=None):
|
||||
super().__init__(2, message, data)
|
||||
|
||||
|
||||
class BackendTimeout(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(3, "Backend timed out", data)
|
||||
def __init__(self, message="Backend timed out", data=None):
|
||||
super().__init__(3, message, data)
|
||||
|
||||
|
||||
class BackendError(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(4, "Backend error", data)
|
||||
def __init__(self, message="Backend error", data=None):
|
||||
super().__init__(4, message, data)
|
||||
|
||||
class UnknownBackendResponse(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(4, "Backend responded in unknown way", data)
|
||||
|
||||
class TooManyRequests(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(5, "Too many requests. Try again later", data)
|
||||
def __init__(self, message="Too many requests. Try again later", data=None):
|
||||
super().__init__(5, message, data)
|
||||
|
||||
|
||||
class UnknownBackendResponse(ApplicationError):
|
||||
def __init__(self, message="Backend responded in unknown way", data=None):
|
||||
super().__init__(6, message, data)
|
||||
|
||||
|
||||
class InvalidCredentials(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(100, "Invalid credentials", data)
|
||||
def __init__(self, message="Invalid credentials", data=None):
|
||||
super().__init__(100, message, data)
|
||||
|
||||
|
||||
class NetworkError(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(101, "Network error", data)
|
||||
def __init__(self, message="Network error", data=None):
|
||||
super().__init__(101, message, data)
|
||||
|
||||
class LoggedInElsewhere(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(102, "Logged in elsewhere", data)
|
||||
|
||||
class ProtocolError(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(103, "Protocol error", data)
|
||||
def __init__(self, message="Protocol error", data=None):
|
||||
super().__init__(103, message, data)
|
||||
|
||||
|
||||
class TemporaryBlocked(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(104, "Temporary blocked", data)
|
||||
def __init__(self, message="Temporary blocked", data=None):
|
||||
super().__init__(104, message, data)
|
||||
|
||||
|
||||
class Banned(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(105, "Banned", data)
|
||||
def __init__(self, message="Banned", data=None):
|
||||
super().__init__(105, message, data)
|
||||
|
||||
|
||||
class AccessDenied(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(106, "Access denied", data)
|
||||
def __init__(self, message="Access denied", data=None):
|
||||
super().__init__(106, message, data)
|
||||
|
||||
|
||||
class FailedParsingManifest(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(200, "Failed parsing manifest", data)
|
||||
def __init__(self, message="Failed parsing manifest", data=None):
|
||||
super().__init__(200, message, data)
|
||||
|
||||
|
||||
class TooManyMessagesSent(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(300, "Too many messages sent", data)
|
||||
def __init__(self, message="Too many messages sent", data=None):
|
||||
super().__init__(300, message, data)
|
||||
|
||||
|
||||
class IncoherentLastMessage(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(400, "Different last message id on backend", data)
|
||||
def __init__(self, message="Different last message id on backend", data=None):
|
||||
super().__init__(400, message, data)
|
||||
|
||||
|
||||
class MessageNotFound(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(500, "Message not found", data)
|
||||
def __init__(self, message="Message not found", data=None):
|
||||
super().__init__(500, message, data)
|
||||
|
||||
|
||||
class ImportInProgress(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(600, "Import already in progress", data)
|
||||
def __init__(self, message="Import already in progress", data=None):
|
||||
super().__init__(600, message, data)
|
||||
|
||||
@@ -87,3 +87,16 @@ class CollectionImporter(Importer):
|
||||
self._notification_failure(id_, UnknownError())
|
||||
finally:
|
||||
self._notification_partially_finished(id_)
|
||||
|
||||
|
||||
class SynchroneousImporter(Importer):
|
||||
async def _import_elements(self, ids_, context_):
|
||||
try:
|
||||
for id_ in ids_:
|
||||
await self._import_element(id_, context_)
|
||||
self._notification_finished()
|
||||
self._complete()
|
||||
except asyncio.CancelledError:
|
||||
logger.debug("Importing %s cancelled", self._name)
|
||||
finally:
|
||||
self._import_in_progress = False
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import asyncio
|
||||
from collections import namedtuple
|
||||
from collections.abc import Iterable
|
||||
from collections.abc import Iterable, Mapping
|
||||
import logging
|
||||
import inspect
|
||||
import json
|
||||
@@ -15,8 +15,13 @@ logger = logging.getLogger(__name__)
|
||||
class JsonRpcError(Exception):
|
||||
def __init__(self, code, message, data=None):
|
||||
self.code = code
|
||||
self.message = message
|
||||
self.data = data
|
||||
self.message = str(message)
|
||||
self.data = {}
|
||||
if data is not None:
|
||||
if not isinstance(data, Mapping):
|
||||
raise TypeError(f"Data parameter should be a mapping, got this instead: {data}")
|
||||
self.data = data
|
||||
self.data.update({"internal_type": type(self).__name__})
|
||||
super().__init__()
|
||||
|
||||
def __eq__(self, other):
|
||||
@@ -25,37 +30,42 @@ class JsonRpcError(Exception):
|
||||
def json(self):
|
||||
obj = {
|
||||
"code": self.code,
|
||||
"message": self.message
|
||||
"message": self.message,
|
||||
"data": self.data
|
||||
}
|
||||
|
||||
if self.data is not None:
|
||||
obj["data"] = self.data
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
class ParseError(JsonRpcError):
|
||||
def __init__(self):
|
||||
super().__init__(-32700, "Parse error")
|
||||
def __init__(self, message="Parse error", data=None):
|
||||
super().__init__(-32700, message, data)
|
||||
|
||||
|
||||
class InvalidRequest(JsonRpcError):
|
||||
def __init__(self):
|
||||
super().__init__(-32600, "Invalid Request")
|
||||
def __init__(self, message="Invalid Request", data=None):
|
||||
super().__init__(-32600, message, data)
|
||||
|
||||
|
||||
class MethodNotFound(JsonRpcError):
|
||||
def __init__(self):
|
||||
super().__init__(-32601, "Method not found")
|
||||
def __init__(self, message="Method not found", data=None):
|
||||
super().__init__(-32601, message, data)
|
||||
|
||||
|
||||
class InvalidParams(JsonRpcError):
|
||||
def __init__(self):
|
||||
super().__init__(-32602, "Invalid params")
|
||||
def __init__(self, message="Invalid params", data=None):
|
||||
super().__init__(-32602, message, data)
|
||||
|
||||
|
||||
class Timeout(JsonRpcError):
|
||||
def __init__(self):
|
||||
super().__init__(-32000, "Method timed out")
|
||||
def __init__(self, message="Method timed out", data=None):
|
||||
super().__init__(-32000, message, data)
|
||||
|
||||
|
||||
class Aborted(JsonRpcError):
|
||||
def __init__(self):
|
||||
super().__init__(-32001, "Method aborted")
|
||||
def __init__(self, message="Method aborted", data=None):
|
||||
super().__init__(-32001, message, data)
|
||||
|
||||
|
||||
class ApplicationError(JsonRpcError):
|
||||
def __init__(self, code, message, data):
|
||||
@@ -63,9 +73,11 @@ class ApplicationError(JsonRpcError):
|
||||
raise ValueError("The error code in reserved range")
|
||||
super().__init__(code, message, data)
|
||||
|
||||
|
||||
class UnknownError(ApplicationError):
|
||||
def __init__(self, data=None):
|
||||
super().__init__(0, "Unknown error", data)
|
||||
def __init__(self, message="Unknown error", data=None):
|
||||
super().__init__(0, message, data)
|
||||
|
||||
|
||||
Request = namedtuple("Request", ["method", "params", "id"], defaults=[{}, None])
|
||||
Response = namedtuple("Response", ["id", "result", "error"], defaults=[None, {}, {}])
|
||||
@@ -299,14 +311,11 @@ class Connection():
|
||||
except TypeError:
|
||||
raise InvalidRequest()
|
||||
|
||||
def _send(self, data, sensitive=True):
|
||||
def _send(self, data, log_level=logging.DEBUG):
|
||||
try:
|
||||
line = self._encoder.encode(data)
|
||||
logger.log(log_level, "Sending data: %s", line)
|
||||
data = (line + "\n").encode("utf-8")
|
||||
if sensitive:
|
||||
logger.debug("Sending %d bytes of data", len(data))
|
||||
else:
|
||||
logging.debug("Sending data: %s", line)
|
||||
self._writer.write(data)
|
||||
except TypeError as error:
|
||||
logger.error(str(error))
|
||||
@@ -317,7 +326,7 @@ class Connection():
|
||||
"id": request_id,
|
||||
"result": result
|
||||
}
|
||||
self._send(response, sensitive=False)
|
||||
self._send(response, logging.INFO)
|
||||
|
||||
def _send_error(self, request_id, error):
|
||||
response = {
|
||||
@@ -325,8 +334,7 @@ class Connection():
|
||||
"id": request_id,
|
||||
"error": error.json()
|
||||
}
|
||||
|
||||
self._send(response, sensitive=False)
|
||||
self._send(response, logging.ERROR)
|
||||
|
||||
def _send_request(self, request_id, method, params):
|
||||
request = {
|
||||
@@ -335,7 +343,7 @@ class Connection():
|
||||
"id": request_id,
|
||||
"params": params
|
||||
}
|
||||
self._send(request, sensitive=True)
|
||||
self._send(request, logging.NOTSET)
|
||||
|
||||
def _send_notification(self, method, params):
|
||||
notification = {
|
||||
@@ -343,7 +351,7 @@ class Connection():
|
||||
"method": method,
|
||||
"params": params
|
||||
}
|
||||
self._send(notification, sensitive=True)
|
||||
self._send(notification, logging.NOTSET)
|
||||
|
||||
@staticmethod
|
||||
def _log_request(request, sensitive_params):
|
||||
|
||||
@@ -13,7 +13,7 @@ from galaxy.api.types import (
|
||||
Subscription, SubscriptionGame
|
||||
)
|
||||
from galaxy.task_manager import TaskManager
|
||||
from galaxy.api.importer import Importer, CollectionImporter
|
||||
from galaxy.api.importer import Importer, CollectionImporter, SynchroneousImporter
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -104,7 +104,7 @@ class Plugin:
|
||||
self._user_presence_import_finished,
|
||||
self.user_presence_import_complete
|
||||
)
|
||||
self._local_size_importer = Importer(
|
||||
self._local_size_importer = SynchroneousImporter(
|
||||
self._external_task_manager,
|
||||
"local size",
|
||||
self.get_local_size,
|
||||
@@ -292,7 +292,7 @@ class Plugin:
|
||||
await self._external_task_manager.wait()
|
||||
await self._internal_task_manager.wait()
|
||||
await self._connection.wait_closed()
|
||||
logger.debug("Plugin closed")
|
||||
logger.info("Plugin closed")
|
||||
|
||||
def create_task(self, coro, description):
|
||||
"""Wrapper around asyncio.create_task - takes care of canceling tasks on shutdown"""
|
||||
@@ -1063,7 +1063,7 @@ class Plugin:
|
||||
This method will only be used if :meth:`get_subscriptions` has been implemented.
|
||||
|
||||
:param context: the value returned from :meth:`prepare_subscription_games_context`
|
||||
:return a generator object that yields SubscriptionGames
|
||||
:return: a generator object that yields SubscriptionGames
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
@@ -1129,8 +1129,11 @@ def create_and_run_plugin(plugin_class, argv):
|
||||
async with plugin_class(reader, writer, token) as plugin:
|
||||
await plugin.run()
|
||||
finally:
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
try:
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
except (ConnectionAbortedError, ConnectionResetError):
|
||||
pass
|
||||
|
||||
try:
|
||||
if sys.platform == "win32":
|
||||
|
||||
@@ -33,7 +33,7 @@ class Cookie:
|
||||
|
||||
@dataclass
|
||||
class NextStep:
|
||||
"""Return this from :meth:`.authenticate` or :meth:`.pass_login_credentials` to open client built-in browser with given url.
|
||||
R"""Return this from :meth:`.authenticate` or :meth:`.pass_login_credentials` to open client built-in browser with given url.
|
||||
For example:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -166,8 +166,8 @@ class UserInfo:
|
||||
"""
|
||||
user_id: str
|
||||
user_name: str
|
||||
avatar_url: Optional[str]
|
||||
profile_url: Optional[str]
|
||||
avatar_url: Optional[str] = None
|
||||
profile_url: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -79,11 +79,11 @@ async def test_get_unlocked_achievements_success(plugin, read, write):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("exception,code,message", [
|
||||
(BackendError, 4, "Backend error"),
|
||||
(KeyError, 0, "Unknown error")
|
||||
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||
(BackendError, 4, "Backend error", "BackendError"),
|
||||
(KeyError, 0, "Unknown error", "UnknownError")
|
||||
])
|
||||
async def test_get_unlocked_achievements_error(exception, code, message, plugin, read, write):
|
||||
async def test_get_unlocked_achievements_error(exception, code, message, internal_type, plugin, read, write):
|
||||
plugin.prepare_achievements_context.return_value = async_return_value(None)
|
||||
request = {
|
||||
"jsonrpc": "2.0",
|
||||
@@ -113,7 +113,8 @@ async def test_get_unlocked_achievements_error(exception, code, message, plugin,
|
||||
"game_id": "14",
|
||||
"error": {
|
||||
"code": code,
|
||||
"message": message
|
||||
"message": message,
|
||||
"data": {"internal_type" : internal_type}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -145,7 +146,8 @@ async def test_prepare_get_unlocked_achievements_context_error(plugin, read, wri
|
||||
"id": "3",
|
||||
"error": {
|
||||
"code": 4,
|
||||
"message": "Backend error"
|
||||
"message": "Backend error",
|
||||
"data": {"internal_type": "BackendError"}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -192,7 +194,8 @@ async def test_import_in_progress(plugin, read, write):
|
||||
"id": "4",
|
||||
"error": {
|
||||
"code": 600,
|
||||
"message": "Import already in progress"
|
||||
"message": "Import already in progress",
|
||||
"data": {"internal_type": "ImportInProgress"}
|
||||
}
|
||||
} in messages
|
||||
|
||||
|
||||
@@ -2,8 +2,16 @@ import pytest
|
||||
|
||||
from galaxy.api.types import Authentication
|
||||
from galaxy.api.errors import (
|
||||
UnknownError, InvalidCredentials, NetworkError, LoggedInElsewhere, ProtocolError,
|
||||
BackendNotAvailable, BackendTimeout, BackendError, TemporaryBlocked, Banned, AccessDenied
|
||||
UnknownError,
|
||||
BackendNotAvailable,
|
||||
BackendTimeout,
|
||||
BackendError,
|
||||
InvalidCredentials,
|
||||
NetworkError,
|
||||
ProtocolError,
|
||||
TemporaryBlocked,
|
||||
Banned,
|
||||
AccessDenied,
|
||||
)
|
||||
from galaxy.unittest.mock import async_return_value, skip_loop
|
||||
|
||||
@@ -35,20 +43,19 @@ async def test_success(plugin, read, write):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("error,code,message", [
|
||||
pytest.param(UnknownError, 0, "Unknown error", id="unknown_error"),
|
||||
pytest.param(BackendNotAvailable, 2, "Backend not available", id="backend_not_available"),
|
||||
pytest.param(BackendTimeout, 3, "Backend timed out", id="backend_timeout"),
|
||||
pytest.param(BackendError, 4, "Backend error", id="backend_error"),
|
||||
pytest.param(InvalidCredentials, 100, "Invalid credentials", id="invalid_credentials"),
|
||||
pytest.param(NetworkError, 101, "Network error", id="network_error"),
|
||||
pytest.param(LoggedInElsewhere, 102, "Logged in elsewhere", id="logged_elsewhere"),
|
||||
pytest.param(ProtocolError, 103, "Protocol error", id="protocol_error"),
|
||||
pytest.param(TemporaryBlocked, 104, "Temporary blocked", id="temporary_blocked"),
|
||||
pytest.param(Banned, 105, "Banned", id="banned"),
|
||||
pytest.param(AccessDenied, 106, "Access denied", id="access_denied"),
|
||||
@pytest.mark.parametrize("error,code,message, internal_type", [
|
||||
pytest.param(UnknownError, 0, "Unknown error", "UnknownError"),
|
||||
pytest.param(BackendNotAvailable, 2, "Backend not available", "BackendNotAvailable"),
|
||||
pytest.param(BackendTimeout, 3, "Backend timed out", "BackendTimeout"),
|
||||
pytest.param(BackendError, 4, "Backend error", "BackendError"),
|
||||
pytest.param(InvalidCredentials, 100, "Invalid credentials", "InvalidCredentials"),
|
||||
pytest.param(NetworkError, 101, "Network error", "NetworkError"),
|
||||
pytest.param(ProtocolError, 103, "Protocol error", "ProtocolError"),
|
||||
pytest.param(TemporaryBlocked, 104, "Temporary blocked", "TemporaryBlocked"),
|
||||
pytest.param(Banned, 105, "Banned", "Banned"),
|
||||
pytest.param(AccessDenied, 106, "Access denied", "AccessDenied"),
|
||||
])
|
||||
async def test_failure(plugin, read, write, error, code, message):
|
||||
async def test_failure(plugin, read, write, error, code, message, internal_type):
|
||||
request = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": "3",
|
||||
@@ -66,7 +73,8 @@ async def test_failure(plugin, read, write, error, code, message):
|
||||
"id": "3",
|
||||
"error": {
|
||||
"code": code,
|
||||
"message": message
|
||||
"message": message,
|
||||
"data" : {"internal_type" : internal_type}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
147
tests/test_errors.py
Normal file
147
tests/test_errors.py
Normal file
@@ -0,0 +1,147 @@
|
||||
import pytest
|
||||
import galaxy.api.errors as errors
|
||||
import galaxy.api.jsonrpc as jsonrpc
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
{"key1": "value", "key2": "value2"},
|
||||
{},
|
||||
{"key1": ["list", "of", "things"], "key2": None},
|
||||
{"key1": ("tuple", Exception)},
|
||||
])
|
||||
def test_valid_error_data(data):
|
||||
test_message = "Test error message"
|
||||
test_code = 1
|
||||
err_obj = jsonrpc.JsonRpcError(code=test_code, message=test_message, data=data)
|
||||
data.update({"internal_type": "JsonRpcError"})
|
||||
expected_json = {"code": 1, "data": data, "message": "Test error message"}
|
||||
assert err_obj.json() == expected_json
|
||||
|
||||
|
||||
def test_error_default_data():
|
||||
test_message = "Test error message"
|
||||
test_code = 1
|
||||
err_obj = jsonrpc.JsonRpcError(code=test_code, message=test_message)
|
||||
expected_json = {"code": test_code, "data": {"internal_type": "JsonRpcError"}, "message": test_message}
|
||||
assert err_obj.json() == expected_json
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
123,
|
||||
["not", "a", "mapping"],
|
||||
"nor is this"
|
||||
])
|
||||
def test_invalid_error_data(data):
|
||||
test_message = "Test error message"
|
||||
test_code = 1
|
||||
with pytest.raises(TypeError):
|
||||
jsonrpc.JsonRpcError(code=test_code, message=test_message, data=data)
|
||||
|
||||
|
||||
def test_error_override_internal_type():
|
||||
test_message = "Test error message"
|
||||
test_code = 1
|
||||
test_data = {"internal_type": "SomeUserProvidedType", "details": "some more data"}
|
||||
err_obj = jsonrpc.JsonRpcError(code=test_code, message=test_message, data=test_data)
|
||||
expected_json = {"code": test_code, "data": {"details": "some more data", "internal_type": "JsonRpcError"}, "message": test_message}
|
||||
assert err_obj.json() == expected_json
|
||||
|
||||
|
||||
@pytest.mark.parametrize("error, expected_error_msg", [
|
||||
(errors.AuthenticationRequired, "Authentication required"),
|
||||
(errors.BackendNotAvailable, "Backend not available"),
|
||||
(errors.BackendTimeout, "Backend timed out"),
|
||||
(errors.BackendError, "Backend error"),
|
||||
(errors.UnknownBackendResponse, "Backend responded in unknown way"),
|
||||
(errors.TooManyRequests, "Too many requests. Try again later"),
|
||||
(errors.InvalidCredentials, "Invalid credentials"),
|
||||
(errors.NetworkError, "Network error"),
|
||||
(errors.ProtocolError, "Protocol error"),
|
||||
(errors.TemporaryBlocked, "Temporary blocked"),
|
||||
(errors.Banned, "Banned"),
|
||||
(errors.AccessDenied, "Access denied"),
|
||||
(errors.FailedParsingManifest, "Failed parsing manifest"),
|
||||
(errors.TooManyMessagesSent, "Too many messages sent"),
|
||||
(errors.IncoherentLastMessage, "Different last message id on backend"),
|
||||
(errors.MessageNotFound, "Message not found"),
|
||||
(errors.ImportInProgress, "Import already in progress"),
|
||||
(jsonrpc.UnknownError, "Unknown error"),
|
||||
(jsonrpc.ParseError, "Parse error"),
|
||||
(jsonrpc.InvalidRequest, "Invalid Request"),
|
||||
(jsonrpc.MethodNotFound, "Method not found"),
|
||||
(jsonrpc.InvalidParams, "Invalid params"),
|
||||
(jsonrpc.Timeout, "Method timed out"),
|
||||
(jsonrpc.Aborted, "Method aborted"),
|
||||
])
|
||||
def test_error_default_message(error, expected_error_msg):
|
||||
error_json = error().json()
|
||||
|
||||
assert error_json["message"] == expected_error_msg
|
||||
|
||||
|
||||
@pytest.mark.parametrize("error", [
|
||||
errors.AuthenticationRequired,
|
||||
errors.BackendNotAvailable,
|
||||
errors.BackendTimeout,
|
||||
errors.BackendError,
|
||||
errors.UnknownBackendResponse,
|
||||
errors.TooManyRequests,
|
||||
errors.InvalidCredentials,
|
||||
errors.NetworkError,
|
||||
errors.ProtocolError,
|
||||
errors.TemporaryBlocked,
|
||||
errors.Banned,
|
||||
errors.AccessDenied,
|
||||
errors.FailedParsingManifest,
|
||||
errors.TooManyMessagesSent,
|
||||
errors.IncoherentLastMessage,
|
||||
errors.MessageNotFound,
|
||||
errors.ImportInProgress,
|
||||
jsonrpc.UnknownError,
|
||||
jsonrpc.ParseError,
|
||||
jsonrpc.InvalidRequest,
|
||||
jsonrpc.MethodNotFound,
|
||||
jsonrpc.InvalidParams,
|
||||
jsonrpc.Timeout,
|
||||
jsonrpc.Aborted,
|
||||
])
|
||||
def test_set_error_custom_message(error):
|
||||
custom_message = "test message"
|
||||
|
||||
error_json = error(custom_message).json()
|
||||
|
||||
assert error_json["message"] == custom_message
|
||||
|
||||
|
||||
@pytest.mark.parametrize("error", [
|
||||
errors.AuthenticationRequired,
|
||||
errors.BackendNotAvailable,
|
||||
errors.BackendTimeout,
|
||||
errors.BackendError,
|
||||
errors.UnknownBackendResponse,
|
||||
errors.TooManyRequests,
|
||||
errors.InvalidCredentials,
|
||||
errors.NetworkError,
|
||||
errors.ProtocolError,
|
||||
errors.TemporaryBlocked,
|
||||
errors.Banned,
|
||||
errors.AccessDenied,
|
||||
errors.FailedParsingManifest,
|
||||
errors.TooManyMessagesSent,
|
||||
errors.IncoherentLastMessage,
|
||||
errors.MessageNotFound,
|
||||
errors.ImportInProgress,
|
||||
jsonrpc.UnknownError,
|
||||
jsonrpc.ParseError,
|
||||
jsonrpc.InvalidRequest,
|
||||
jsonrpc.MethodNotFound,
|
||||
jsonrpc.InvalidParams,
|
||||
jsonrpc.Timeout,
|
||||
jsonrpc.Aborted,
|
||||
])
|
||||
def test_set_arbitrary_error_message(error):
|
||||
arbitrary_messages = [[], {}, (), 1, None]
|
||||
|
||||
for msg in arbitrary_messages:
|
||||
error_json = error(msg).json()
|
||||
assert error_json["message"] == str(msg)
|
||||
@@ -18,7 +18,9 @@ async def test_get_friends_success(plugin, read, write):
|
||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
||||
plugin.get_friends.return_value = async_return_value([
|
||||
UserInfo("3", "Jan", "https://avatar.url/u3", None),
|
||||
UserInfo("5", "Ola", None, "https://profile.url/u5")
|
||||
UserInfo("5", "Ola", None, "https://profile.url/u5"),
|
||||
UserInfo("6", "Ola2", None),
|
||||
UserInfo("7", "Ola3"),
|
||||
])
|
||||
await plugin.run()
|
||||
plugin.get_friends.assert_called_with()
|
||||
@@ -30,7 +32,9 @@ async def test_get_friends_success(plugin, read, write):
|
||||
"result": {
|
||||
"friend_info_list": [
|
||||
{"user_id": "3", "user_name": "Jan", "avatar_url": "https://avatar.url/u3"},
|
||||
{"user_id": "5", "user_name": "Ola", "profile_url": "https://profile.url/u5"}
|
||||
{"user_id": "5", "user_name": "Ola", "profile_url": "https://profile.url/u5"},
|
||||
{"user_id": "6", "user_name": "Ola2"},
|
||||
{"user_id": "7", "user_name": "Ola3"},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -57,6 +61,7 @@ async def test_get_friends_failure(plugin, read, write):
|
||||
"error": {
|
||||
"code": 0,
|
||||
"message": "Unknown error",
|
||||
"data": {"internal_type": "UnknownError"}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -79,11 +79,11 @@ async def test_get_library_settings_success(plugin, read, write):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("exception,code,message", [
|
||||
(BackendError, 4, "Backend error"),
|
||||
(KeyError, 0, "Unknown error")
|
||||
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||
(BackendError, 4, "Backend error", "BackendError"),
|
||||
(KeyError, 0, "Unknown error", "UnknownError")
|
||||
])
|
||||
async def test_get_game_library_settings_error(exception, code, message, plugin, read, write):
|
||||
async def test_get_game_library_settings_error(exception, code, message, internal_type, plugin, read, write):
|
||||
plugin.prepare_game_library_settings_context.return_value = async_return_value(None)
|
||||
request = {
|
||||
"jsonrpc": "2.0",
|
||||
@@ -112,7 +112,8 @@ async def test_get_game_library_settings_error(exception, code, message, plugin,
|
||||
"game_id": "6",
|
||||
"error": {
|
||||
"code": code,
|
||||
"message": message
|
||||
"message": message,
|
||||
"data": {"internal_type": internal_type}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -144,7 +145,8 @@ async def test_prepare_get_game_library_settings_context_error(plugin, read, wri
|
||||
"id": "3",
|
||||
"error": {
|
||||
"code": 4,
|
||||
"message": "Backend error"
|
||||
"message": "Backend error",
|
||||
"data": {"internal_type": "BackendError"}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -190,7 +192,8 @@ async def test_import_in_progress(plugin, read, write):
|
||||
"id": "4",
|
||||
"error": {
|
||||
"code": 600,
|
||||
"message": "Import already in progress"
|
||||
"message": "Import already in progress",
|
||||
"data": {"internal_type": "ImportInProgress"}
|
||||
}
|
||||
} in messages
|
||||
|
||||
|
||||
@@ -79,11 +79,11 @@ async def test_get_game_time_success(plugin, read, write):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("exception,code,message", [
|
||||
(BackendError, 4, "Backend error"),
|
||||
(KeyError, 0, "Unknown error")
|
||||
@pytest.mark.parametrize("exception,code,message, internal_type", [
|
||||
(BackendError, 4, "Backend error", "BackendError"),
|
||||
(KeyError, 0, "Unknown error", "UnknownError")
|
||||
])
|
||||
async def test_get_game_time_error(exception, code, message, plugin, read, write):
|
||||
async def test_get_game_time_error(exception, code, message, internal_type, plugin, read, write):
|
||||
plugin.prepare_game_times_context.return_value = async_return_value(None)
|
||||
request = {
|
||||
"jsonrpc": "2.0",
|
||||
@@ -112,7 +112,8 @@ async def test_get_game_time_error(exception, code, message, plugin, read, write
|
||||
"game_id": "6",
|
||||
"error": {
|
||||
"code": code,
|
||||
"message": message
|
||||
"message": message,
|
||||
"data" : {"internal_type" : internal_type}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -144,7 +145,8 @@ async def test_prepare_get_game_time_context_error(plugin, read, write):
|
||||
"id": "3",
|
||||
"error": {
|
||||
"code": 4,
|
||||
"message": "Backend error"
|
||||
"message": "Backend error",
|
||||
"data": {"internal_type": "BackendError"}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -190,7 +192,8 @@ async def test_import_in_progress(plugin, read, write):
|
||||
"id": "4",
|
||||
"error": {
|
||||
"code": 600,
|
||||
"message": "Import already in progress"
|
||||
"message": "Import already in progress",
|
||||
"data": {"internal_type": "ImportInProgress"}
|
||||
}
|
||||
} in messages
|
||||
|
||||
|
||||
@@ -51,13 +51,13 @@ async def test_success(plugin, read, write):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"error,code,message",
|
||||
"error,code,message, internal_type",
|
||||
[
|
||||
pytest.param(UnknownError, 0, "Unknown error", id="unknown_error"),
|
||||
pytest.param(FailedParsingManifest, 200, "Failed parsing manifest", id="failed_parsing")
|
||||
pytest.param(UnknownError, 0, "Unknown error", "UnknownError", id="unknown_error"),
|
||||
pytest.param(FailedParsingManifest, 200, "Failed parsing manifest", "FailedParsingManifest", id="failed_parsing")
|
||||
],
|
||||
)
|
||||
async def test_failure(plugin, read, write, error, code, message):
|
||||
async def test_failure(plugin, read, write, error, code, message, internal_type):
|
||||
request = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": "3",
|
||||
@@ -74,7 +74,8 @@ async def test_failure(plugin, read, write, error, code, message):
|
||||
"id": "3",
|
||||
"error": {
|
||||
"code": code,
|
||||
"message": message
|
||||
"message": message,
|
||||
"data" : {"internal_type" : internal_type}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -19,7 +19,7 @@ async def test_get_local_size_success(plugin, read, write):
|
||||
}
|
||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
||||
plugin.get_local_size.side_effect = [
|
||||
async_return_value(100000000000),
|
||||
async_return_value(100000000000, 1),
|
||||
async_return_value(None),
|
||||
async_return_value(3333333)
|
||||
]
|
||||
@@ -69,11 +69,11 @@ async def test_get_local_size_success(plugin, read, write):
|
||||
]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("exception,code,message", [
|
||||
(FailedParsingManifest, 200, "Failed parsing manifest"),
|
||||
(KeyError, 0, "Unknown error")
|
||||
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||
(FailedParsingManifest, 200, "Failed parsing manifest", "FailedParsingManifest"),
|
||||
(KeyError, 0, "Unknown error", "UnknownError")
|
||||
])
|
||||
async def test_get_local_size_error(exception, code, message, plugin, read, write):
|
||||
async def test_get_local_size_error(exception, code, message, internal_type, plugin, read, write):
|
||||
game_id = "6"
|
||||
request_id = "55"
|
||||
plugin.prepare_local_size_context.return_value = async_return_value(None)
|
||||
@@ -89,12 +89,15 @@ async def test_get_local_size_error(exception, code, message, plugin, read, writ
|
||||
plugin.get_local_size.assert_called()
|
||||
plugin.local_size_import_complete.assert_called_once_with()
|
||||
|
||||
assert get_messages(write) == [
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": request_id,
|
||||
"result": None
|
||||
},
|
||||
direct_response = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": request_id,
|
||||
"result": None
|
||||
}
|
||||
responses = get_messages(write)
|
||||
assert direct_response in responses
|
||||
responses.remove(direct_response)
|
||||
assert responses == [
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "local_size_import_failure",
|
||||
@@ -102,7 +105,10 @@ async def test_get_local_size_error(exception, code, message, plugin, read, writ
|
||||
"game_id": game_id,
|
||||
"error": {
|
||||
"code": code,
|
||||
"message": message
|
||||
"message": message,
|
||||
"data": {
|
||||
"internal_type": internal_type
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -117,9 +123,9 @@ async def test_get_local_size_error(exception, code, message, plugin, read, writ
|
||||
@pytest.mark.asyncio
|
||||
async def test_prepare_get_local_size_context_error(plugin, read, write):
|
||||
request_id = "31415"
|
||||
error_details = "Unexpected syntax"
|
||||
error_details = {"Details": "Unexpected syntax"}
|
||||
error_message, error_code = FailedParsingManifest().message, FailedParsingManifest().code
|
||||
plugin.prepare_local_size_context.side_effect = FailedParsingManifest(error_details)
|
||||
plugin.prepare_local_size_context.side_effect = FailedParsingManifest(data=error_details)
|
||||
request = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": request_id,
|
||||
@@ -128,7 +134,6 @@ async def test_prepare_get_local_size_context_error(plugin, read, write):
|
||||
}
|
||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
||||
await plugin.run()
|
||||
|
||||
assert get_messages(write) == [
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
@@ -136,7 +141,10 @@ async def test_prepare_get_local_size_context_error(plugin, read, write):
|
||||
"error": {
|
||||
"code": error_code,
|
||||
"message": error_message,
|
||||
"data": error_details
|
||||
"data": {
|
||||
"internal_type": "FailedParsingManifest",
|
||||
"Details": "Unexpected syntax"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -145,6 +153,7 @@ async def test_prepare_get_local_size_context_error(plugin, read, write):
|
||||
@pytest.mark.asyncio
|
||||
async def test_import_already_in_progress_error(plugin, read, write):
|
||||
plugin.prepare_local_size_context.return_value = async_return_value(None)
|
||||
plugin.get_local_size.return_value = async_return_value(100, 5)
|
||||
requests = [
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
@@ -182,7 +191,7 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
||||
"id": "4",
|
||||
"error": {
|
||||
"code": 600,
|
||||
"message": "Import already in progress"
|
||||
"message": "Import already in progress",
|
||||
"data": {"internal_type": "ImportInProgress"}
|
||||
}
|
||||
} in responses
|
||||
|
||||
|
||||
@@ -71,11 +71,11 @@ async def test_get_os_compatibility_success(plugin, read, write):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("exception,code,message", [
|
||||
(BackendError, 4, "Backend error"),
|
||||
(KeyError, 0, "Unknown error")
|
||||
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||
(BackendError, 4, "Backend error", "BackendError"),
|
||||
(KeyError, 0, "Unknown error", "UnknownError")
|
||||
])
|
||||
async def test_get_os_compatibility_error(exception, code, message, plugin, read, write):
|
||||
async def test_get_os_compatibility_error(exception, code, message, internal_type, plugin, read, write):
|
||||
game_id = "6"
|
||||
request_id = "55"
|
||||
plugin.prepare_os_compatibility_context.return_value = async_return_value(None)
|
||||
@@ -104,7 +104,8 @@ async def test_get_os_compatibility_error(exception, code, message, plugin, read
|
||||
"game_id": game_id,
|
||||
"error": {
|
||||
"code": code,
|
||||
"message": message
|
||||
"message": message,
|
||||
"data": {"internal_type": internal_type}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -135,7 +136,8 @@ async def test_prepare_get_os_compatibility_context_error(plugin, read, write):
|
||||
"id": request_id,
|
||||
"error": {
|
||||
"code": 4,
|
||||
"message": "Backend error"
|
||||
"message": "Backend error",
|
||||
"data": {"internal_type": "BackendError"}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -181,7 +183,8 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
||||
"id": "4",
|
||||
"error": {
|
||||
"code": 600,
|
||||
"message": "Import already in progress"
|
||||
"message": "Import already in progress",
|
||||
"data": {"internal_type": "ImportInProgress"}
|
||||
}
|
||||
} in responses
|
||||
|
||||
|
||||
@@ -90,7 +90,8 @@ async def test_failure(plugin, read, write):
|
||||
"id": "3",
|
||||
"error": {
|
||||
"code": 0,
|
||||
"message": "Unknown error"
|
||||
"message": "Unknown error",
|
||||
"data": {"internal_type": "UnknownError"}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,6 +7,8 @@ from galaxy.api.errors import (
|
||||
BackendNotAvailable, BackendTimeout, BackendError, InvalidCredentials, NetworkError, AccessDenied, UnknownError
|
||||
)
|
||||
from galaxy.api.jsonrpc import JsonRpcError
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_refresh_credentials_success(plugin, read, write):
|
||||
|
||||
@@ -58,7 +60,8 @@ async def test_refresh_credentials_failure(exception, plugin, read, write):
|
||||
with pytest.raises(JsonRpcError) as e:
|
||||
await plugin.refresh_credentials({}, False)
|
||||
|
||||
assert error == e.value
|
||||
# Go back to comparing error == e.value, after fixing current always raising JsonRpcError when handling a response with an error
|
||||
assert error.code == e.value.code
|
||||
assert get_messages(write) == [
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
|
||||
@@ -53,13 +53,13 @@ async def test_get_subscriptions_success(plugin, read, write):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"error,code,message",
|
||||
"error,code,message,internal_type",
|
||||
[
|
||||
pytest.param(UnknownError, 0, "Unknown error", id="unknown_error"),
|
||||
pytest.param(FailedParsingManifest, 200, "Failed parsing manifest", id="failed_parsing")
|
||||
pytest.param(UnknownError, 0, "Unknown error", "UnknownError", id="unknown_error"),
|
||||
pytest.param(FailedParsingManifest, 200, "Failed parsing manifest", "FailedParsingManifest", id="failed_parsing")
|
||||
],
|
||||
)
|
||||
async def test_get_subscriptions_failure_generic(plugin, read, write, error, code, message):
|
||||
async def test_get_subscriptions_failure_generic(plugin, read, write, error, code, message, internal_type):
|
||||
request = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": "3",
|
||||
@@ -76,6 +76,7 @@ async def test_get_subscriptions_failure_generic(plugin, read, write, error, cod
|
||||
"id": "3",
|
||||
"error": {
|
||||
"code": code,
|
||||
"data": {"internal_type": internal_type},
|
||||
"message": message
|
||||
}
|
||||
}
|
||||
@@ -212,11 +213,11 @@ async def test_get_subscription_games_success_empty(plugin, read, write):
|
||||
]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("exception,code,message", [
|
||||
(BackendError, 4, "Backend error"),
|
||||
(KeyError, 0, "Unknown error")
|
||||
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||
(BackendError, 4, "Backend error", "BackendError"),
|
||||
(KeyError, 0, "Unknown error", "UnknownError")
|
||||
])
|
||||
async def test_get_subscription_games_error(exception, code, message, plugin, read, write):
|
||||
async def test_get_subscription_games_error(exception, code, message, internal_type, plugin, read, write):
|
||||
plugin.prepare_subscription_games_context.return_value = async_return_value(None)
|
||||
request = {
|
||||
"jsonrpc": "2.0",
|
||||
@@ -246,7 +247,8 @@ async def test_get_subscription_games_error(exception, code, message, plugin, re
|
||||
"subscription_name": "sub_a",
|
||||
"error": {
|
||||
"code": code,
|
||||
"message": message
|
||||
"message": message,
|
||||
"data": {"internal_type": internal_type}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -269,9 +271,9 @@ async def test_get_subscription_games_error(exception, code, message, plugin, re
|
||||
@pytest.mark.asyncio
|
||||
async def test_prepare_get_subscription_games_context_error(plugin, read, write):
|
||||
request_id = "31415"
|
||||
error_details = "Unexpected backend error"
|
||||
error_details = {"Details": "Unexpected backend error"}
|
||||
error_message, error_code = BackendError().message, BackendError().code
|
||||
plugin.prepare_subscription_games_context.side_effect = BackendError(error_details)
|
||||
plugin.prepare_subscription_games_context.side_effect = BackendError(data=error_details)
|
||||
request = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": request_id,
|
||||
@@ -280,7 +282,6 @@ async def test_prepare_get_subscription_games_context_error(plugin, read, write)
|
||||
}
|
||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
||||
await plugin.run()
|
||||
|
||||
assert get_messages(write) == [
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
@@ -288,7 +289,10 @@ async def test_prepare_get_subscription_games_context_error(plugin, read, write)
|
||||
"error": {
|
||||
"code": error_code,
|
||||
"message": error_message,
|
||||
"data": error_details
|
||||
"data": {
|
||||
"internal_type": "BackendError",
|
||||
"Details": "Unexpected backend error"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -334,7 +338,8 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
||||
"id": "4",
|
||||
"error": {
|
||||
"code": 600,
|
||||
"message": "Import already in progress"
|
||||
"message": "Import already in progress",
|
||||
"data": {"internal_type": "ImportInProgress"}
|
||||
}
|
||||
} in responses
|
||||
|
||||
|
||||
@@ -139,11 +139,11 @@ async def test_get_user_presence_success(plugin, read, write):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("exception,code,message", [
|
||||
(BackendError, 4, "Backend error"),
|
||||
(KeyError, 0, "Unknown error")
|
||||
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||
(BackendError, 4, "Backend error", "BackendError"),
|
||||
(KeyError, 0, "Unknown error", "UnknownError")
|
||||
])
|
||||
async def test_get_user_presence_error(exception, code, message, plugin, read, write):
|
||||
async def test_get_user_presence_error(exception, code, message, internal_type, plugin, read, write):
|
||||
user_id = "69"
|
||||
request_id = "55"
|
||||
plugin.prepare_user_presence_context.return_value = async_return_value(None)
|
||||
@@ -172,7 +172,10 @@ async def test_get_user_presence_error(exception, code, message, plugin, read, w
|
||||
"user_id": user_id,
|
||||
"error": {
|
||||
"code": code,
|
||||
"message": message
|
||||
"message": message,
|
||||
"data": {
|
||||
"internal_type": internal_type
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -203,7 +206,10 @@ async def test_prepare_get_user_presence_context_error(plugin, read, write):
|
||||
"id": request_id,
|
||||
"error": {
|
||||
"code": 4,
|
||||
"message": "Backend error"
|
||||
"message": "Backend error",
|
||||
"data": {
|
||||
"internal_type": "BackendError"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -249,7 +255,8 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
||||
"id": "4",
|
||||
"error": {
|
||||
"code": 600,
|
||||
"message": "Import already in progress"
|
||||
"message": "Import already in progress",
|
||||
"data": {"internal_type": "ImportInProgress"}
|
||||
}
|
||||
} in responses
|
||||
|
||||
|
||||
Reference in New Issue
Block a user