mirror of
https://github.com/gogcom/galaxy-integrations-python-api.git
synced 2026-01-30 09:31:27 -05:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e483edd92 | ||
|
|
8a39496a11 | ||
|
|
2c18ac4ffa | ||
|
|
6a1d2763c3 | ||
|
|
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.13
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r requirements-dev.txt
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
pytest
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
image: registry-gitlab.gog.com/docker/python:3.7.3
|
image: registry-gitlab.gog.com/docker/python:3.13
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- test
|
- test
|
||||||
@@ -7,7 +7,7 @@ stages:
|
|||||||
test_package:
|
test_package:
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
- pip install -r requirements.txt
|
- pip install -r requirements-dev.txt
|
||||||
- pytest
|
- pytest
|
||||||
except:
|
except:
|
||||||
- tags
|
- tags
|
||||||
@@ -18,10 +18,10 @@ deploy_package:
|
|||||||
TWINE_USERNAME: $PYPI_USERNAME
|
TWINE_USERNAME: $PYPI_USERNAME
|
||||||
TWINE_PASSWORD: $PYPI_PASSWORD
|
TWINE_PASSWORD: $PYPI_PASSWORD
|
||||||
script:
|
script:
|
||||||
- pip install twine wheel
|
- pip install twine wheel build
|
||||||
- rm -rf dist
|
- rm -rf dist
|
||||||
- export VERSION=$(python setup.py --version)
|
- export VERSION=$(python setup.py --version)
|
||||||
- python setup.py sdist --formats=gztar bdist_wheel
|
- python -m build --sdist --wheel
|
||||||
- twine upload dist/*
|
- twine upload dist/*
|
||||||
- curl -X POST --silent --show-error --fail
|
- curl -X POST --silent --show-error --fail
|
||||||
"https://gitlab.gog.com/api/v4/projects/${CI_PROJECT_ID}/repository/tags?tag_name=${VERSION}&ref=${CI_COMMIT_REF_NAME}&private_token=${PACKAGE_DEPLOYER_API_TOKEN}"
|
"https://gitlab.gog.com/api/v4/projects/${CI_PROJECT_ID}/repository/tags?tag_name=${VERSION}&ref=${CI_COMMIT_REF_NAME}&private_token=${PACKAGE_DEPLOYER_API_TOKEN}"
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
dist: xenial # required for Python >= 3.7
|
|
||||||
language: python
|
|
||||||
python:
|
|
||||||
- "3.7"
|
|
||||||
install:
|
|
||||||
- pip install -r requirements.txt
|
|
||||||
script:
|
|
||||||
- pytest
|
|
||||||
32
README.md
32
README.md
@@ -1,17 +1,19 @@
|
|||||||
# GOG Galaxy Integrations Python API
|
# GOG GALAXY Integrations Python API
|
||||||
|
|
||||||
This Python library allows developers to easily build community integrations for various gaming platforms with GOG Galaxy 2.0.
|
This Python library allows developers to easily build community integrations for various gaming platforms with GOG GALAXY **2.1**.
|
||||||
|
|
||||||
- refer to our <a href='https://galaxy-integrations-python-api.readthedocs.io'>documentation</a>
|
- refer to our <a href='https://galaxy-integrations-python-api.readthedocs.io'>documentation</a>
|
||||||
|
|
||||||
|
Note: For integrations targeting GOG GALAXY the **below 2.1.0 version**, please refer to [this version](https://github.com/gogcom/galaxy-integrations-python-api/tree/0.69).
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
Each integration in GOG Galaxy 2.0 comes as a separate Python script and is launched as a separate process that needs to communicate with the main instance of GOG Galaxy 2.0.
|
Each integration in GOG GALAXY 2.1 comes as a separate Python script and is launched as a separate process that needs to communicate with the main instance of GOG GALAXY 2.1.
|
||||||
|
|
||||||
The provided features are:
|
The provided features are:
|
||||||
|
|
||||||
- multistep authorization using a browser built into GOG Galaxy 2.0
|
- multistep authorization using a browser built into GOG GALAXY 2.1
|
||||||
- support for GOG Galaxy 2.0 features:
|
- support for GOG GALAXY 2.1 features:
|
||||||
- importing owned and detecting installed games
|
- importing owned and detecting installed games
|
||||||
- installing and launching games
|
- installing and launching games
|
||||||
- importing achievements and game time
|
- importing achievements and game time
|
||||||
@@ -28,9 +30,11 @@ Each integration can implement only one platform. Each integration must declare
|
|||||||
|
|
||||||
## Basic usage
|
## Basic usage
|
||||||
|
|
||||||
Each integration should inherit from the :class:`~galaxy.api.plugin.Plugin` class. Supported methods like :meth:`~galaxy.api.plugin.Plugin.get_owned_games` should be overwritten - they are called from the GOG Galaxy client at the appropriate times.
|
Each integration should inherit from the `galaxy.api.plugin.Plugin` class. Supported methods like `galaxy.api.plugin.Plugin.get_owned_games` should be overwritten - they are called from the GOG GALAXY client at the appropriate times.
|
||||||
Each of those methods can raise exceptions inherited from the :exc:`~galaxy.api.jsonrpc.ApplicationError`.
|
Each of those methods can raise exceptions inherited from the `galaxy.api.jsonrpc.ApplicationError`.
|
||||||
Communication between an integration and the client is also possible with the use of notifications, for example: :meth:`~galaxy.api.plugin.Plugin.update_local_game_status`.
|
Communication between an integration and the client is also possible with the use of notifications, for example: `galaxy.api.plugin.Plugin.update_local_game_status`.
|
||||||
|
|
||||||
|
The minimum implementation requires to override `galaxy.api.plugin.Plugin.authenticate` and `galaxy.api.plugin.Plugin.get_owned_games` methods.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import sys
|
import sys
|
||||||
@@ -72,8 +76,8 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
The client has a built-in Python 3.7 interpreter, so integrations are delivered as Python modules.
|
The client has a built-in Python 3.13 interpreter, so integrations are delivered as Python modules.
|
||||||
In order to be found by GOG Galaxy 2.0 an integration folder should be placed in [lookup directory](#deploy-location). Beside all the Python files, the integration folder must contain [manifest.json](#deploy-manifest) and all third-party dependencies. See an [exemplary structure](#deploy-structure-example).
|
In order to be found by GOG GALAXY 2.1 an integration folder should be placed in [lookup directory](#deploy-location). Beside all the Python files, the integration folder must contain [manifest.json](#deploy-manifest) and all third-party dependencies. See an [exemplary structure](#deploy-structure-example).
|
||||||
|
|
||||||
### Lookup directory
|
### Lookup directory
|
||||||
|
|
||||||
@@ -88,7 +92,7 @@ In order to be found by GOG Galaxy 2.0 an integration folder should be placed in
|
|||||||
`~/Library/Application Support/GOG.com/Galaxy/plugins/installed`
|
`~/Library/Application Support/GOG.com/Galaxy/plugins/installed`
|
||||||
|
|
||||||
### Logging
|
### Logging
|
||||||
<a href='https://docs.python.org/3.7/howto/logging.html'>Root logger</a> is already setup by GOG Galaxy to store rotated log files in:
|
<a href='https://docs.python.org/3.13/howto/logging.html'>Root logger</a> is already setup by GOG GALAXY to store rotated log files in:
|
||||||
|
|
||||||
- Windows:
|
- Windows:
|
||||||
|
|
||||||
@@ -128,9 +132,9 @@ Obligatory JSON file to be placed in an integration folder.
|
|||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
All third-party packages (packages not included in the Python 3.7 standard library) should be deployed along with plugin files. Use the following command structure:
|
All third-party packages (packages not included in the Python 3.13 standard library) should be deployed along with plugin files. Use the following command structure:
|
||||||
|
|
||||||
```pip install DEP --target DIR --implementation cp --python-version 37```
|
```pip install DEP --target DIR --implementation cp --python-version 313```
|
||||||
|
|
||||||
For example, a plugin that uses *requests* could have the following structure:
|
For example, a plugin that uses *requests* could have the following structure:
|
||||||
|
|
||||||
@@ -149,4 +153,4 @@ installed
|
|||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
By integrating or attempting to integrate any applications or content with or into GOG Galaxy 2.0 you represent that such application or content is your original creation (other than any software made available by GOG) and/or that you have all necessary rights to grant such applicable rights to the relevant community integration to GOG and to GOG Galaxy 2.0 end users for the purpose of use of such community integration and that such community integration comply with any third party license and other requirements including compliance with applicable laws.
|
By integrating or attempting to integrate any applications or content with or into GOG GALAXY 2.1 you represent that such application or content is your original creation (other than any software made available by GOG) and/or that you have all necessary rights to grant such applicable rights to the relevant community integration to GOG and to GOG GALAXY 2.1 end users for the purpose of use of such community integration and that such community integration comply with any third party license and other requirements including compliance with applicable laws.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
Sphinx==2.0.1
|
Sphinx==4.2.0
|
||||||
sphinx-rtd-theme==0.4.3
|
sphinx-rtd-theme==1.0.0
|
||||||
sphinx-autodoc-typehints==1.6.0
|
sphinx-autodoc-typehints==1.12.0
|
||||||
sphinxcontrib-asyncio==0.2.0
|
sphinxcontrib-asyncio==0.3.0
|
||||||
m2r==0.2.1
|
m2r2==0.3.1
|
||||||
|
typing-extensions==3.10.0.2
|
||||||
@@ -34,7 +34,7 @@ extensions = [
|
|||||||
'sphinx.ext.autodoc',
|
'sphinx.ext.autodoc',
|
||||||
'sphinxcontrib.asyncio',
|
'sphinxcontrib.asyncio',
|
||||||
'sphinx_autodoc_typehints',
|
'sphinx_autodoc_typehints',
|
||||||
'm2r' # mdinclude directive for makrdown files
|
'm2r2' # mdinclude directive for makrdown files
|
||||||
]
|
]
|
||||||
autodoc_member_order = 'bysource'
|
autodoc_member_order = 'bysource'
|
||||||
autodoc_inherit_docstrings = False
|
autodoc_inherit_docstrings = False
|
||||||
@@ -70,6 +70,6 @@ html_theme_options = {
|
|||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ['_static']
|
# html_static_path = ["_static"]
|
||||||
|
|
||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ plugin
|
|||||||
.. automodule:: galaxy.api.plugin
|
.. automodule:: galaxy.api.plugin
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:exclude-members: JSONEncoder, features, achievements_import_finished, game_times_import_finished, start_achievements_import, start_game_times_import, get_game_times, get_unlocked_achievements
|
:exclude-members: JSONEncoder, features
|
||||||
|
|
||||||
types
|
types
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|||||||
69
pyproject.toml
Normal file
69
pyproject.toml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=61.0", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "galaxy.plugin.api"
|
||||||
|
version = "0.71"
|
||||||
|
description = "GOG Galaxy Integrations Python API"
|
||||||
|
authors = [
|
||||||
|
{name = "Galaxy team", email = "galaxy@gog.com"}
|
||||||
|
]
|
||||||
|
readme = "README.md"
|
||||||
|
license-files = ["LICENSE"]
|
||||||
|
requires-python = "~=3.13.0"
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 4 - Beta",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
"aiohttp>=3.12.15",
|
||||||
|
"certifi>=2026.1.4",
|
||||||
|
"psutil>=5.6.6; sys_platform == 'darwin'"
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = [
|
||||||
|
"pytest==8.4.1",
|
||||||
|
"pytest-asyncio==1.1.0",
|
||||||
|
"pytest-mock==3.14.1",
|
||||||
|
"pytest-mypy==1.0.1",
|
||||||
|
"pytest-flakes==4.0.5",
|
||||||
|
"types-certifi==2021.10.8.3",
|
||||||
|
"setuptools==80.9.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
package-dir = {"" = "src"}
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["src"]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
testpaths = ["tests"]
|
||||||
|
python_files = ["test_*.py"]
|
||||||
|
python_classes = ["Test*"]
|
||||||
|
python_functions = ["test_*"]
|
||||||
|
addopts = [
|
||||||
|
"--strict-markers",
|
||||||
|
"--strict-config",
|
||||||
|
"--verbose",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
python_version = "3.13"
|
||||||
|
warn_return_any = true
|
||||||
|
warn_unused_configs = true
|
||||||
|
disallow_untyped_defs = true
|
||||||
|
disallow_incomplete_defs = true
|
||||||
|
check_untyped_defs = true
|
||||||
|
disallow_untyped_decorators = true
|
||||||
|
no_implicit_optional = true
|
||||||
|
warn_redundant_casts = true
|
||||||
|
warn_unused_ignores = true
|
||||||
|
warn_no_return = true
|
||||||
|
warn_unreachable = true
|
||||||
|
strict_equality = true
|
||||||
8
requirements-dev.txt
Normal file
8
requirements-dev.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
-r requirements.txt
|
||||||
|
pytest==8.4.1
|
||||||
|
pytest-asyncio==1.1.0
|
||||||
|
pytest-mock==3.14.1
|
||||||
|
pytest-mypy==1.0.1
|
||||||
|
pytest-flakes==4.0.5
|
||||||
|
types-certifi==2021.10.8.3
|
||||||
|
setuptools==80.9.0
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
-e .
|
-e .
|
||||||
pytest==5.2.2
|
# Copied from setup.py because of a pip bug
|
||||||
pytest-asyncio==0.10.0
|
# see https://github.com/pypa/pip/issues/4780
|
||||||
pytest-mock==1.10.3
|
aiohttp==3.12.15
|
||||||
pytest-mypy==0.4.1
|
certifi==2026.1.4
|
||||||
pytest-flakes==4.0.0
|
|
||||||
# because of pip bug https://github.com/pypa/pip/issues/4780
|
|
||||||
aiohttp==3.5.4
|
|
||||||
certifi==2019.3.9
|
|
||||||
psutil==5.6.6; sys_platform == 'darwin'
|
psutil==5.6.6; sys_platform == 'darwin'
|
||||||
|
# End of copy from setup.py
|
||||||
|
|||||||
17
setup.py
17
setup.py
@@ -1,16 +1,3 @@
|
|||||||
from setuptools import setup, find_packages
|
from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup()
|
||||||
name="galaxy.plugin.api",
|
|
||||||
version="0.66.0",
|
|
||||||
description="GOG Galaxy Integrations Python API",
|
|
||||||
author='Galaxy team',
|
|
||||||
author_email='galaxy@gog.com',
|
|
||||||
packages=find_packages("src"),
|
|
||||||
package_dir={'': 'src'},
|
|
||||||
install_requires=[
|
|
||||||
"aiohttp>=3.5.4",
|
|
||||||
"certifi>=2019.3.9",
|
|
||||||
"psutil>=5.6.6; sys_platform == 'darwin'"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ sphinx:
|
|||||||
formats: all
|
formats: all
|
||||||
|
|
||||||
python:
|
python:
|
||||||
version: 3.7
|
version: 3.13
|
||||||
install:
|
install:
|
||||||
- requirements: requirements.txt
|
- requirements: requirements.txt
|
||||||
- requirements: docs/requirements.txt
|
- requirements: docs/requirements.txt
|
||||||
|
|||||||
@@ -1 +1,6 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
logging.getLogger(__name__).setLevel(logging.INFO)
|
||||||
|
|
||||||
__path__: str = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore
|
__path__: str = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore
|
||||||
|
|||||||
@@ -1,75 +1,88 @@
|
|||||||
from galaxy.api.jsonrpc import ApplicationError, UnknownError
|
from galaxy.api.jsonrpc import ApplicationError, UnknownError
|
||||||
|
|
||||||
assert UnknownError
|
|
||||||
|
assert UnknownError is not None # UnknownError not used directly in errors.py, but we want to ensure it's defined
|
||||||
|
|
||||||
class AuthenticationRequired(ApplicationError):
|
class AuthenticationRequired(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Authentication required", data=None):
|
||||||
super().__init__(1, "Authentication required", data)
|
super().__init__(1, message, data)
|
||||||
|
|
||||||
|
|
||||||
class BackendNotAvailable(ApplicationError):
|
class BackendNotAvailable(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Backend not available", data=None):
|
||||||
super().__init__(2, "Backend not available", data)
|
super().__init__(2, message, data)
|
||||||
|
|
||||||
|
|
||||||
class BackendTimeout(ApplicationError):
|
class BackendTimeout(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Backend timed out", data=None):
|
||||||
super().__init__(3, "Backend timed out", data)
|
super().__init__(3, message, data)
|
||||||
|
|
||||||
|
|
||||||
class BackendError(ApplicationError):
|
class BackendError(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Backend error", data=None):
|
||||||
super().__init__(4, "Backend error", data)
|
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):
|
class TooManyRequests(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Too many requests. Try again later", data=None):
|
||||||
super().__init__(5, "Too many requests. Try again later", data)
|
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):
|
class InvalidCredentials(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Invalid credentials", data=None):
|
||||||
super().__init__(100, "Invalid credentials", data)
|
super().__init__(100, message, data)
|
||||||
|
|
||||||
|
|
||||||
class NetworkError(ApplicationError):
|
class NetworkError(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Network error", data=None):
|
||||||
super().__init__(101, "Network error", data)
|
super().__init__(101, message, data)
|
||||||
|
|
||||||
class LoggedInElsewhere(ApplicationError):
|
|
||||||
def __init__(self, data=None):
|
|
||||||
super().__init__(102, "Logged in elsewhere", data)
|
|
||||||
|
|
||||||
class ProtocolError(ApplicationError):
|
class ProtocolError(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Protocol error", data=None):
|
||||||
super().__init__(103, "Protocol error", data)
|
super().__init__(103, message, data)
|
||||||
|
|
||||||
|
|
||||||
class TemporaryBlocked(ApplicationError):
|
class TemporaryBlocked(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Temporary blocked", data=None):
|
||||||
super().__init__(104, "Temporary blocked", data)
|
super().__init__(104, message, data)
|
||||||
|
|
||||||
|
|
||||||
class Banned(ApplicationError):
|
class Banned(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Banned", data=None):
|
||||||
super().__init__(105, "Banned", data)
|
super().__init__(105, message, data)
|
||||||
|
|
||||||
|
|
||||||
class AccessDenied(ApplicationError):
|
class AccessDenied(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Access denied", data=None):
|
||||||
super().__init__(106, "Access denied", data)
|
super().__init__(106, message, data)
|
||||||
|
|
||||||
|
|
||||||
class FailedParsingManifest(ApplicationError):
|
class FailedParsingManifest(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Failed parsing manifest", data=None):
|
||||||
super().__init__(200, "Failed parsing manifest", data)
|
super().__init__(200, message, data)
|
||||||
|
|
||||||
|
|
||||||
class TooManyMessagesSent(ApplicationError):
|
class TooManyMessagesSent(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Too many messages sent", data=None):
|
||||||
super().__init__(300, "Too many messages sent", data)
|
super().__init__(300, message, data)
|
||||||
|
|
||||||
|
|
||||||
class IncoherentLastMessage(ApplicationError):
|
class IncoherentLastMessage(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Different last message id on backend", data=None):
|
||||||
super().__init__(400, "Different last message id on backend", data)
|
super().__init__(400, message, data)
|
||||||
|
|
||||||
|
|
||||||
class MessageNotFound(ApplicationError):
|
class MessageNotFound(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Message not found", data=None):
|
||||||
super().__init__(500, "Message not found", data)
|
super().__init__(500, message, data)
|
||||||
|
|
||||||
|
|
||||||
class ImportInProgress(ApplicationError):
|
class ImportInProgress(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Import already in progress", data=None):
|
||||||
super().__init__(600, "Import already in progress", data)
|
super().__init__(600, message, data)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class Importer:
|
|||||||
context = await self._prepare_context(ids)
|
context = await self._prepare_context(ids)
|
||||||
self._task_manager.create_task(
|
self._task_manager.create_task(
|
||||||
self._import_elements(ids, context),
|
self._import_elements(ids, context),
|
||||||
"{} import".format(self._name),
|
f"{self._name} import",
|
||||||
handle_exceptions=False
|
handle_exceptions=False
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
@@ -76,7 +76,7 @@ class CollectionImporter(Importer):
|
|||||||
|
|
||||||
async def _import_element(self, id_, context_):
|
async def _import_element(self, id_, context_):
|
||||||
try:
|
try:
|
||||||
async for element in self._get(id_, context_):
|
async for element in await self._get(id_, context_):
|
||||||
self._notification_success(id_, element)
|
self._notification_success(id_, element)
|
||||||
except ApplicationError as error:
|
except ApplicationError as error:
|
||||||
self._notification_failure(id_, error)
|
self._notification_failure(id_, error)
|
||||||
@@ -87,3 +87,16 @@ class CollectionImporter(Importer):
|
|||||||
self._notification_failure(id_, UnknownError())
|
self._notification_failure(id_, UnknownError())
|
||||||
finally:
|
finally:
|
||||||
self._notification_partially_finished(id_)
|
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
|
import asyncio
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable, Mapping
|
||||||
import logging
|
import logging
|
||||||
import inspect
|
import inspect
|
||||||
import json
|
import json
|
||||||
@@ -15,8 +15,13 @@ logger = logging.getLogger(__name__)
|
|||||||
class JsonRpcError(Exception):
|
class JsonRpcError(Exception):
|
||||||
def __init__(self, code, message, data=None):
|
def __init__(self, code, message, data=None):
|
||||||
self.code = code
|
self.code = code
|
||||||
self.message = message
|
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 = data
|
||||||
|
self.data.update({"internal_type": type(self).__name__})
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
@@ -25,37 +30,42 @@ class JsonRpcError(Exception):
|
|||||||
def json(self):
|
def json(self):
|
||||||
obj = {
|
obj = {
|
||||||
"code": self.code,
|
"code": self.code,
|
||||||
"message": self.message
|
"message": self.message,
|
||||||
|
"data": self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.data is not None:
|
|
||||||
obj["data"] = self.data
|
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
class ParseError(JsonRpcError):
|
class ParseError(JsonRpcError):
|
||||||
def __init__(self):
|
def __init__(self, message="Parse error", data=None):
|
||||||
super().__init__(-32700, "Parse error")
|
super().__init__(-32700, message, data)
|
||||||
|
|
||||||
|
|
||||||
class InvalidRequest(JsonRpcError):
|
class InvalidRequest(JsonRpcError):
|
||||||
def __init__(self):
|
def __init__(self, message="Invalid Request", data=None):
|
||||||
super().__init__(-32600, "Invalid Request")
|
super().__init__(-32600, message, data)
|
||||||
|
|
||||||
|
|
||||||
class MethodNotFound(JsonRpcError):
|
class MethodNotFound(JsonRpcError):
|
||||||
def __init__(self):
|
def __init__(self, message="Method not found", data=None):
|
||||||
super().__init__(-32601, "Method not found")
|
super().__init__(-32601, message, data)
|
||||||
|
|
||||||
|
|
||||||
class InvalidParams(JsonRpcError):
|
class InvalidParams(JsonRpcError):
|
||||||
def __init__(self):
|
def __init__(self, message="Invalid params", data=None):
|
||||||
super().__init__(-32602, "Invalid params")
|
super().__init__(-32602, message, data)
|
||||||
|
|
||||||
|
|
||||||
class Timeout(JsonRpcError):
|
class Timeout(JsonRpcError):
|
||||||
def __init__(self):
|
def __init__(self, message="Method timed out", data=None):
|
||||||
super().__init__(-32000, "Method timed out")
|
super().__init__(-32000, message, data)
|
||||||
|
|
||||||
|
|
||||||
class Aborted(JsonRpcError):
|
class Aborted(JsonRpcError):
|
||||||
def __init__(self):
|
def __init__(self, message="Method aborted", data=None):
|
||||||
super().__init__(-32001, "Method aborted")
|
super().__init__(-32001, message, data)
|
||||||
|
|
||||||
|
|
||||||
class ApplicationError(JsonRpcError):
|
class ApplicationError(JsonRpcError):
|
||||||
def __init__(self, code, message, data):
|
def __init__(self, code, message, data):
|
||||||
@@ -63,9 +73,11 @@ class ApplicationError(JsonRpcError):
|
|||||||
raise ValueError("The error code in reserved range")
|
raise ValueError("The error code in reserved range")
|
||||||
super().__init__(code, message, data)
|
super().__init__(code, message, data)
|
||||||
|
|
||||||
|
|
||||||
class UnknownError(ApplicationError):
|
class UnknownError(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, message="Unknown error", data=None):
|
||||||
super().__init__(0, "Unknown error", data)
|
super().__init__(0, message, data)
|
||||||
|
|
||||||
|
|
||||||
Request = namedtuple("Request", ["method", "params", "id"], defaults=[{}, None])
|
Request = namedtuple("Request", ["method", "params", "id"], defaults=[{}, None])
|
||||||
Response = namedtuple("Response", ["id", "result", "error"], defaults=[None, {}, {}])
|
Response = namedtuple("Response", ["id", "result", "error"], defaults=[None, {}, {}])
|
||||||
@@ -285,7 +297,7 @@ class Connection():
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_message(data):
|
def _parse_message(data):
|
||||||
try:
|
try:
|
||||||
jsonrpc_message = json.loads(data, encoding="utf-8")
|
jsonrpc_message = json.loads(data)
|
||||||
if jsonrpc_message.get("jsonrpc") != "2.0":
|
if jsonrpc_message.get("jsonrpc") != "2.0":
|
||||||
raise InvalidRequest()
|
raise InvalidRequest()
|
||||||
del jsonrpc_message["jsonrpc"]
|
del jsonrpc_message["jsonrpc"]
|
||||||
@@ -299,14 +311,11 @@ class Connection():
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
raise InvalidRequest()
|
raise InvalidRequest()
|
||||||
|
|
||||||
def _send(self, data, sensitive=True):
|
def _send(self, data, log_level=logging.DEBUG):
|
||||||
try:
|
try:
|
||||||
line = self._encoder.encode(data)
|
line = self._encoder.encode(data)
|
||||||
|
logger.log(log_level, "Sending data: %s", line)
|
||||||
data = (line + "\n").encode("utf-8")
|
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)
|
self._writer.write(data)
|
||||||
except TypeError as error:
|
except TypeError as error:
|
||||||
logger.error(str(error))
|
logger.error(str(error))
|
||||||
@@ -317,7 +326,7 @@ class Connection():
|
|||||||
"id": request_id,
|
"id": request_id,
|
||||||
"result": result
|
"result": result
|
||||||
}
|
}
|
||||||
self._send(response, sensitive=False)
|
self._send(response, logging.INFO)
|
||||||
|
|
||||||
def _send_error(self, request_id, error):
|
def _send_error(self, request_id, error):
|
||||||
response = {
|
response = {
|
||||||
@@ -325,8 +334,7 @@ class Connection():
|
|||||||
"id": request_id,
|
"id": request_id,
|
||||||
"error": error.json()
|
"error": error.json()
|
||||||
}
|
}
|
||||||
|
self._send(response, logging.ERROR)
|
||||||
self._send(response, sensitive=False)
|
|
||||||
|
|
||||||
def _send_request(self, request_id, method, params):
|
def _send_request(self, request_id, method, params):
|
||||||
request = {
|
request = {
|
||||||
@@ -335,7 +343,7 @@ class Connection():
|
|||||||
"id": request_id,
|
"id": request_id,
|
||||||
"params": params
|
"params": params
|
||||||
}
|
}
|
||||||
self._send(request, sensitive=True)
|
self._send(request, logging.NOTSET)
|
||||||
|
|
||||||
def _send_notification(self, method, params):
|
def _send_notification(self, method, params):
|
||||||
notification = {
|
notification = {
|
||||||
@@ -343,7 +351,7 @@ class Connection():
|
|||||||
"method": method,
|
"method": method,
|
||||||
"params": params
|
"params": params
|
||||||
}
|
}
|
||||||
self._send(notification, sensitive=True)
|
self._send(notification, logging.NOTSET)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _log_request(request, sensitive_params):
|
def _log_request(request, sensitive_params):
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from galaxy.api.types import (
|
|||||||
Subscription, SubscriptionGame
|
Subscription, SubscriptionGame
|
||||||
)
|
)
|
||||||
from galaxy.task_manager import TaskManager
|
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__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -104,7 +104,7 @@ class Plugin:
|
|||||||
self._user_presence_import_finished,
|
self._user_presence_import_finished,
|
||||||
self.user_presence_import_complete
|
self.user_presence_import_complete
|
||||||
)
|
)
|
||||||
self._local_size_importer = Importer(
|
self._local_size_importer = SynchroneousImporter(
|
||||||
self._external_task_manager,
|
self._external_task_manager,
|
||||||
"local size",
|
"local size",
|
||||||
self.get_local_size,
|
self.get_local_size,
|
||||||
@@ -292,14 +292,14 @@ class Plugin:
|
|||||||
await self._external_task_manager.wait()
|
await self._external_task_manager.wait()
|
||||||
await self._internal_task_manager.wait()
|
await self._internal_task_manager.wait()
|
||||||
await self._connection.wait_closed()
|
await self._connection.wait_closed()
|
||||||
logger.debug("Plugin closed")
|
logger.info("Plugin closed")
|
||||||
|
|
||||||
def create_task(self, coro, description):
|
def create_task(self, coro, description):
|
||||||
"""Wrapper around asyncio.create_task - takes care of canceling tasks on shutdown"""
|
"""Wrapper around asyncio.create_task - takes care of canceling tasks on shutdown"""
|
||||||
return self._external_task_manager.create_task(coro, description)
|
return self._external_task_manager.create_task(coro, description)
|
||||||
|
|
||||||
async def _pass_control(self):
|
async def _pass_control(self):
|
||||||
while self._active:
|
while self._active and self._connection._active:
|
||||||
try:
|
try:
|
||||||
self.tick()
|
self.tick()
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -1063,7 +1063,7 @@ class Plugin:
|
|||||||
This method will only be used if :meth:`get_subscriptions` has been implemented.
|
This method will only be used if :meth:`get_subscriptions` has been implemented.
|
||||||
|
|
||||||
:param context: the value returned from :meth:`prepare_subscription_games_context`
|
: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
|
.. code-block:: python
|
||||||
:linenos:
|
:linenos:
|
||||||
@@ -1129,8 +1129,11 @@ def create_and_run_plugin(plugin_class, argv):
|
|||||||
async with plugin_class(reader, writer, token) as plugin:
|
async with plugin_class(reader, writer, token) as plugin:
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
finally:
|
finally:
|
||||||
|
try:
|
||||||
writer.close()
|
writer.close()
|
||||||
await writer.wait_closed()
|
await writer.wait_closed()
|
||||||
|
except (ConnectionAbortedError, ConnectionResetError):
|
||||||
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class Cookie:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class NextStep:
|
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:
|
For example:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -166,8 +166,8 @@ class UserInfo:
|
|||||||
"""
|
"""
|
||||||
user_id: str
|
user_id: str
|
||||||
user_name: str
|
user_name: str
|
||||||
avatar_url: Optional[str]
|
avatar_url: Optional[str] = None
|
||||||
profile_url: Optional[str]
|
profile_url: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -37,3 +37,21 @@ async def async_raise(error, loop_iterations_delay=0):
|
|||||||
if loop_iterations_delay > 0:
|
if loop_iterations_delay > 0:
|
||||||
await skip_loop(loop_iterations_delay)
|
await skip_loop(loop_iterations_delay)
|
||||||
raise error
|
raise error
|
||||||
|
|
||||||
|
|
||||||
|
def delayed_return_value(return_value, loop_iterations_delay=0):
|
||||||
|
async def return_fn(*args, **kwargs):
|
||||||
|
for _ in range(loop_iterations_delay):
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
return return_value
|
||||||
|
return return_fn
|
||||||
|
|
||||||
|
|
||||||
|
def delayed_return_value_iterable(return_value, loop_iterations_delay=0):
|
||||||
|
iterable = iter(return_value)
|
||||||
|
async def return_fn(*args, **kwargs):
|
||||||
|
for _ in range(loop_iterations_delay):
|
||||||
|
await asyncio.sleep(0.001)
|
||||||
|
last_value = next(iterable)
|
||||||
|
return last_value
|
||||||
|
return return_fn
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
from contextlib import ExitStack
|
from contextlib import ExitStack
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -12,12 +12,12 @@ from galaxy.unittest.mock import async_return_value
|
|||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def reader():
|
def reader():
|
||||||
stream = MagicMock(name="stream_reader")
|
stream = MagicMock(name="stream_reader")
|
||||||
stream.read = MagicMock()
|
stream.read = AsyncMock()
|
||||||
yield stream
|
yield stream
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
async def writer():
|
def writer():
|
||||||
stream = MagicMock(name="stream_writer")
|
stream = MagicMock(name="stream_writer")
|
||||||
stream.drain.side_effect = lambda: async_return_value(None)
|
stream.drain.side_effect = lambda: async_return_value(None)
|
||||||
yield stream
|
yield stream
|
||||||
@@ -34,7 +34,7 @@ def write(writer):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
async def plugin(reader, writer):
|
def plugin(reader, writer):
|
||||||
"""Return plugin instance with all feature methods mocked"""
|
"""Return plugin instance with all feature methods mocked"""
|
||||||
methods = (
|
methods = (
|
||||||
"handshake_complete",
|
"handshake_complete",
|
||||||
@@ -73,12 +73,14 @@ async def plugin(reader, writer):
|
|||||||
"subscription_games_import_complete"
|
"subscription_games_import_complete"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Patch the class methods BEFORE creating the instance
|
||||||
with ExitStack() as stack:
|
with ExitStack() as stack:
|
||||||
for method in methods:
|
for method in methods:
|
||||||
stack.enter_context(patch.object(Plugin, method))
|
stack.enter_context(patch.object(Plugin, method))
|
||||||
|
|
||||||
async with Plugin(Platform.Generic, "0.1", reader, writer, "token") as plugin:
|
# Now create the plugin instance
|
||||||
plugin.shutdown.return_value = async_return_value(None)
|
plugin = Plugin(Platform.Generic, "0.1", reader, writer, "token")
|
||||||
|
plugin.shutdown.return_value = None
|
||||||
yield plugin
|
yield plugin
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from pytest import raises
|
|||||||
|
|
||||||
from galaxy.api.types import Achievement
|
from galaxy.api.types import Achievement
|
||||||
from galaxy.api.errors import BackendError
|
from galaxy.api.errors import BackendError
|
||||||
from galaxy.unittest.mock import async_return_value, skip_loop
|
from galaxy.unittest.mock import skip_loop
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ def test_initialization_no_id_nor_name():
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_unlocked_achievements_success(plugin, read, write):
|
async def test_get_unlocked_achievements_success(plugin, read, write):
|
||||||
plugin.prepare_achievements_context.return_value = async_return_value(5)
|
plugin.prepare_achievements_context.return_value = 5
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
@@ -31,16 +31,17 @@ async def test_get_unlocked_achievements_success(plugin, read, write):
|
|||||||
"game_ids": ["14"]
|
"game_ids": ["14"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_unlocked_achievements.return_value = async_return_value([
|
plugin.get_unlocked_achievements.return_value = [
|
||||||
Achievement(achievement_id="lvl10", unlock_time=1548421241),
|
Achievement(achievement_id="lvl10", unlock_time=1548421241),
|
||||||
Achievement(achievement_name="Got level 20", unlock_time=1548422395),
|
Achievement(achievement_name="Got level 20", unlock_time=1548422395),
|
||||||
Achievement(achievement_id="lvl30", achievement_name="Got level 30", unlock_time=1548495633)
|
Achievement(achievement_id="lvl30", achievement_name="Got level 30", unlock_time=1548495633)
|
||||||
])
|
]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.prepare_achievements_context.assert_called_with(["14"])
|
plugin.prepare_achievements_context.assert_called_with(["14"])
|
||||||
plugin.get_unlocked_achievements.assert_called_with("14", 5)
|
plugin.get_unlocked_achievements.assert_called_with("14", 5)
|
||||||
plugin.achievements_import_complete.asert_called_with()
|
plugin.achievements_import_complete.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -79,12 +80,12 @@ async def test_get_unlocked_achievements_success(plugin, read, write):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize("exception,code,message", [
|
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||||
(BackendError, 4, "Backend error"),
|
(BackendError, 4, "Backend error", "BackendError"),
|
||||||
(KeyError, 0, "Unknown error")
|
(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)
|
plugin.prepare_achievements_context.return_value = None
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
@@ -94,11 +95,12 @@ async def test_get_unlocked_achievements_error(exception, code, message, plugin,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_unlocked_achievements.side_effect = exception
|
plugin.get_unlocked_achievements.side_effect = exception
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_unlocked_achievements.assert_called()
|
plugin.get_unlocked_achievements.assert_called()
|
||||||
plugin.achievements_import_complete.asert_called_with()
|
plugin.achievements_import_complete.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -113,7 +115,8 @@ async def test_get_unlocked_achievements_error(exception, code, message, plugin,
|
|||||||
"game_id": "14",
|
"game_id": "14",
|
||||||
"error": {
|
"error": {
|
||||||
"code": code,
|
"code": code,
|
||||||
"message": message
|
"message": message,
|
||||||
|
"data": {"internal_type" : internal_type}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -135,9 +138,10 @@ async def test_prepare_get_unlocked_achievements_context_error(plugin, read, wri
|
|||||||
"game_ids": ["14"]
|
"game_ids": ["14"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
|
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -145,7 +149,8 @@ async def test_prepare_get_unlocked_achievements_context_error(plugin, read, wri
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 4,
|
"code": 4,
|
||||||
"message": "Backend error"
|
"message": "Backend error",
|
||||||
|
"data": {"internal_type": "BackendError"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -153,8 +158,8 @@ async def test_prepare_get_unlocked_achievements_context_error(plugin, read, wri
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_import_in_progress(plugin, read, write):
|
async def test_import_in_progress(plugin, read, write):
|
||||||
plugin.prepare_achievements_context.return_value = async_return_value(None)
|
plugin.prepare_achievements_context.return_value = None
|
||||||
plugin.get_unlocked_achievements.return_value = async_return_value([])
|
plugin.get_unlocked_achievements.return_value = []
|
||||||
requests = [
|
requests = [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -174,12 +179,13 @@ async def test_import_in_progress(plugin, read, write):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
read.side_effect = [
|
read.side_effect = [
|
||||||
async_return_value(create_message(requests[0])),
|
create_message(requests[0]),
|
||||||
async_return_value(create_message(requests[1])),
|
create_message(requests[1]),
|
||||||
async_return_value(b"", 10)
|
b""
|
||||||
]
|
]
|
||||||
|
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
|
|
||||||
messages = get_messages(write)
|
messages = get_messages(write)
|
||||||
assert {
|
assert {
|
||||||
@@ -192,7 +198,8 @@ async def test_import_in_progress(plugin, read, write):
|
|||||||
"id": "4",
|
"id": "4",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 600,
|
"code": 600,
|
||||||
"message": "Import already in progress"
|
"message": "Import already in progress",
|
||||||
|
"data": {"internal_type": "ImportInProgress"}
|
||||||
}
|
}
|
||||||
} in messages
|
} in messages
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,18 @@ import pytest
|
|||||||
|
|
||||||
from galaxy.api.types import Authentication
|
from galaxy.api.types import Authentication
|
||||||
from galaxy.api.errors import (
|
from galaxy.api.errors import (
|
||||||
UnknownError, InvalidCredentials, NetworkError, LoggedInElsewhere, ProtocolError,
|
UnknownError,
|
||||||
BackendNotAvailable, BackendTimeout, BackendError, TemporaryBlocked, Banned, AccessDenied
|
BackendNotAvailable,
|
||||||
|
BackendTimeout,
|
||||||
|
BackendError,
|
||||||
|
InvalidCredentials,
|
||||||
|
NetworkError,
|
||||||
|
ProtocolError,
|
||||||
|
TemporaryBlocked,
|
||||||
|
Banned,
|
||||||
|
AccessDenied,
|
||||||
)
|
)
|
||||||
from galaxy.unittest.mock import async_return_value, skip_loop
|
from galaxy.unittest.mock import skip_loop
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
@@ -17,9 +25,10 @@ async def test_success(plugin, read, write):
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"method": "init_authentication"
|
"method": "init_authentication"
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.authenticate.return_value = async_return_value(Authentication("132", "Zenek"))
|
plugin.authenticate.return_value = Authentication("132", "Zenek")
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.authenticate.assert_called_with()
|
plugin.authenticate.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
@@ -35,29 +44,29 @@ async def test_success(plugin, read, write):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize("error,code,message", [
|
@pytest.mark.parametrize("error,code,message, internal_type", [
|
||||||
pytest.param(UnknownError, 0, "Unknown error", id="unknown_error"),
|
pytest.param(UnknownError, 0, "Unknown error", "UnknownError"),
|
||||||
pytest.param(BackendNotAvailable, 2, "Backend not available", id="backend_not_available"),
|
pytest.param(BackendNotAvailable, 2, "Backend not available", "BackendNotAvailable"),
|
||||||
pytest.param(BackendTimeout, 3, "Backend timed out", id="backend_timeout"),
|
pytest.param(BackendTimeout, 3, "Backend timed out", "BackendTimeout"),
|
||||||
pytest.param(BackendError, 4, "Backend error", id="backend_error"),
|
pytest.param(BackendError, 4, "Backend error", "BackendError"),
|
||||||
pytest.param(InvalidCredentials, 100, "Invalid credentials", id="invalid_credentials"),
|
pytest.param(InvalidCredentials, 100, "Invalid credentials", "InvalidCredentials"),
|
||||||
pytest.param(NetworkError, 101, "Network error", id="network_error"),
|
pytest.param(NetworkError, 101, "Network error", "NetworkError"),
|
||||||
pytest.param(LoggedInElsewhere, 102, "Logged in elsewhere", id="logged_elsewhere"),
|
pytest.param(ProtocolError, 103, "Protocol error", "ProtocolError"),
|
||||||
pytest.param(ProtocolError, 103, "Protocol error", id="protocol_error"),
|
pytest.param(TemporaryBlocked, 104, "Temporary blocked", "TemporaryBlocked"),
|
||||||
pytest.param(TemporaryBlocked, 104, "Temporary blocked", id="temporary_blocked"),
|
pytest.param(Banned, 105, "Banned", "Banned"),
|
||||||
pytest.param(Banned, 105, "Banned", id="banned"),
|
pytest.param(AccessDenied, 106, "Access denied", "AccessDenied"),
|
||||||
pytest.param(AccessDenied, 106, "Access denied", id="access_denied"),
|
|
||||||
])
|
])
|
||||||
async def test_failure(plugin, read, write, error, code, message):
|
async def test_failure(plugin, read, write, error, code, message, internal_type):
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
"method": "init_authentication"
|
"method": "init_authentication"
|
||||||
}
|
}
|
||||||
|
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.authenticate.side_effect = error()
|
plugin.authenticate.side_effect = error()
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.authenticate.assert_called_with()
|
plugin.authenticate.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
@@ -66,7 +75,8 @@ async def test_failure(plugin, read, write, error, code, message):
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"error": {
|
"error": {
|
||||||
"code": code,
|
"code": code,
|
||||||
"message": message
|
"message": message,
|
||||||
|
"data" : {"internal_type" : internal_type}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -84,9 +94,10 @@ async def test_stored_credentials(plugin, read, write):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.authenticate.return_value = async_return_value(Authentication("132", "Zenek"))
|
plugin.authenticate.return_value = Authentication("132", "Zenek")
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.authenticate.assert_called_with(stored_credentials={"token": "ABC"})
|
plugin.authenticate.assert_called_with(stored_credentials={"token": "ABC"})
|
||||||
write.assert_called()
|
write.assert_called()
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import json
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_chunked_messages(plugin, read):
|
async def test_chunked_messages(plugin, read):
|
||||||
@@ -16,8 +14,9 @@ async def test_chunked_messages(plugin, read):
|
|||||||
}
|
}
|
||||||
|
|
||||||
message = json.dumps(request).encode() + b"\n"
|
message = json.dumps(request).encode() + b"\n"
|
||||||
read.side_effect = [async_return_value(message[:5]), async_return_value(message[5:]), async_return_value(b"")]
|
read.side_effect = [message[:5], message[5:], b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.install_game.assert_called_with(game_id="3")
|
plugin.install_game.assert_called_with(game_id="3")
|
||||||
|
|
||||||
|
|
||||||
@@ -41,8 +40,9 @@ async def test_joined_messages(plugin, read):
|
|||||||
]
|
]
|
||||||
data = b"".join([json.dumps(request).encode() + b"\n" for request in requests])
|
data = b"".join([json.dumps(request).encode() + b"\n" for request in requests])
|
||||||
|
|
||||||
read.side_effect = [async_return_value(data), async_return_value(b"")]
|
read.side_effect = [data, b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.install_game.assert_called_with(game_id="3")
|
plugin.install_game.assert_called_with(game_id="3")
|
||||||
plugin.launch_game.assert_called_with(game_id="3")
|
plugin.launch_game.assert_called_with(game_id="3")
|
||||||
|
|
||||||
@@ -58,6 +58,7 @@ async def test_not_finished(plugin, read):
|
|||||||
}
|
}
|
||||||
|
|
||||||
message = json.dumps(request).encode() # no new line
|
message = json.dumps(request).encode() # no new line
|
||||||
read.side_effect = [async_return_value(message), async_return_value(b"")]
|
read.side_effect = [message, b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.install_game.assert_not_called()
|
plugin.install_game.assert_not_called()
|
||||||
|
|||||||
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)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
from galaxy.api.types import UserInfo
|
from galaxy.api.types import UserInfo
|
||||||
from galaxy.api.errors import UnknownError
|
from galaxy.api.errors import UnknownError
|
||||||
from galaxy.unittest.mock import async_return_value, skip_loop
|
from galaxy.unittest.mock import skip_loop
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -15,12 +15,15 @@ async def test_get_friends_success(plugin, read, write):
|
|||||||
"method": "import_friends"
|
"method": "import_friends"
|
||||||
}
|
}
|
||||||
|
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_friends.return_value = async_return_value([
|
plugin.get_friends.return_value = [
|
||||||
UserInfo("3", "Jan", "https://avatar.url/u3", None),
|
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()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_friends.assert_called_with()
|
plugin.get_friends.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
@@ -30,7 +33,9 @@ async def test_get_friends_success(plugin, read, write):
|
|||||||
"result": {
|
"result": {
|
||||||
"friend_info_list": [
|
"friend_info_list": [
|
||||||
{"user_id": "3", "user_name": "Jan", "avatar_url": "https://avatar.url/u3"},
|
{"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"},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,9 +50,10 @@ async def test_get_friends_failure(plugin, read, write):
|
|||||||
"method": "import_friends"
|
"method": "import_friends"
|
||||||
}
|
}
|
||||||
|
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_friends.side_effect = UnknownError()
|
plugin.get_friends.side_effect = UnknownError()
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_friends.assert_called_with()
|
plugin.get_friends.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
@@ -57,6 +63,7 @@ async def test_get_friends_failure(plugin, read, write):
|
|||||||
"error": {
|
"error": {
|
||||||
"code": 0,
|
"code": 0,
|
||||||
"message": "Unknown error",
|
"message": "Unknown error",
|
||||||
|
"data": {"internal_type": "UnknownError"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -68,6 +75,7 @@ async def test_add_friend(plugin, write):
|
|||||||
|
|
||||||
plugin.add_friend(friend)
|
plugin.add_friend(friend)
|
||||||
await skip_loop()
|
await skip_loop()
|
||||||
|
await plugin.wait_closed()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -89,7 +97,7 @@ async def test_add_friend(plugin, write):
|
|||||||
async def test_remove_friend(plugin, write):
|
async def test_remove_friend(plugin, write):
|
||||||
plugin.remove_friend("5")
|
plugin.remove_friend("5")
|
||||||
await skip_loop()
|
await skip_loop()
|
||||||
|
await plugin.wait_closed()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -107,7 +115,7 @@ async def test_update_friend_info(plugin, write):
|
|||||||
UserInfo("7", "Jakub", avatar_url="https://new-avatar.url/kuba2.jpg", profile_url="https://profile.url/kuba")
|
UserInfo("7", "Jakub", avatar_url="https://new-avatar.url/kuba2.jpg", profile_url="https://profile.url/kuba")
|
||||||
)
|
)
|
||||||
await skip_loop()
|
await skip_loop()
|
||||||
|
await plugin.wait_closed()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ from unittest.mock import call
|
|||||||
import pytest
|
import pytest
|
||||||
from galaxy.api.types import GameLibrarySettings
|
from galaxy.api.types import GameLibrarySettings
|
||||||
from galaxy.api.errors import BackendError
|
from galaxy.api.errors import BackendError
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_library_settings_success(plugin, read, write):
|
async def test_get_library_settings_success(plugin, read, write):
|
||||||
plugin.prepare_game_library_settings_context.return_value = async_return_value("abc")
|
plugin.prepare_game_library_settings_context.return_value = "abc"
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
@@ -19,13 +18,14 @@ async def test_get_library_settings_success(plugin, read, write):
|
|||||||
"game_ids": ["3", "5", "7"]
|
"game_ids": ["3", "5", "7"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_game_library_settings.side_effect = [
|
plugin.get_game_library_settings.side_effect = [
|
||||||
async_return_value(GameLibrarySettings("3", None, True)),
|
GameLibrarySettings("3", None, True),
|
||||||
async_return_value(GameLibrarySettings("5", [], False)),
|
GameLibrarySettings("5", [], False),
|
||||||
async_return_value(GameLibrarySettings("7", ["tag1", "tag2", "tag3"], None)),
|
GameLibrarySettings("7", ["tag1", "tag2", "tag3"], None),
|
||||||
]
|
]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_game_library_settings.assert_has_calls([
|
plugin.get_game_library_settings.assert_has_calls([
|
||||||
call("3", "abc"),
|
call("3", "abc"),
|
||||||
call("5", "abc"),
|
call("5", "abc"),
|
||||||
@@ -79,12 +79,12 @@ async def test_get_library_settings_success(plugin, read, write):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize("exception,code,message", [
|
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||||
(BackendError, 4, "Backend error"),
|
(BackendError, 4, "Backend error", "BackendError"),
|
||||||
(KeyError, 0, "Unknown error")
|
(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)
|
plugin.prepare_game_library_settings_context.return_value = None
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
@@ -93,9 +93,10 @@ async def test_get_game_library_settings_error(exception, code, message, plugin,
|
|||||||
"game_ids": ["6"]
|
"game_ids": ["6"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_game_library_settings.side_effect = exception
|
plugin.get_game_library_settings.side_effect = exception
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_game_library_settings.assert_called()
|
plugin.get_game_library_settings.assert_called()
|
||||||
plugin.game_library_settings_import_complete.assert_called_once_with()
|
plugin.game_library_settings_import_complete.assert_called_once_with()
|
||||||
|
|
||||||
@@ -112,7 +113,8 @@ async def test_get_game_library_settings_error(exception, code, message, plugin,
|
|||||||
"game_id": "6",
|
"game_id": "6",
|
||||||
"error": {
|
"error": {
|
||||||
"code": code,
|
"code": code,
|
||||||
"message": message
|
"message": message,
|
||||||
|
"data": {"internal_type": internal_type}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -135,8 +137,9 @@ async def test_prepare_get_game_library_settings_context_error(plugin, read, wri
|
|||||||
"game_ids": ["6"]
|
"game_ids": ["6"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -144,7 +147,8 @@ async def test_prepare_get_game_library_settings_context_error(plugin, read, wri
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 4,
|
"code": 4,
|
||||||
"message": "Backend error"
|
"message": "Backend error",
|
||||||
|
"data": {"internal_type": "BackendError"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -152,7 +156,7 @@ async def test_prepare_get_game_library_settings_context_error(plugin, read, wri
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_import_in_progress(plugin, read, write):
|
async def test_import_in_progress(plugin, read, write):
|
||||||
plugin.prepare_game_library_settings_context.return_value = async_return_value(None)
|
plugin.prepare_game_library_settings_context.return_value = None
|
||||||
requests = [
|
requests = [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -172,12 +176,13 @@ async def test_import_in_progress(plugin, read, write):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
read.side_effect = [
|
read.side_effect = [
|
||||||
async_return_value(create_message(requests[0])),
|
create_message(requests[0]),
|
||||||
async_return_value(create_message(requests[1])),
|
create_message(requests[1]),
|
||||||
async_return_value(b"", 10)
|
b""
|
||||||
]
|
]
|
||||||
|
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
|
|
||||||
messages = get_messages(write)
|
messages = get_messages(write)
|
||||||
assert {
|
assert {
|
||||||
@@ -190,7 +195,8 @@ async def test_import_in_progress(plugin, read, write):
|
|||||||
"id": "4",
|
"id": "4",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 600,
|
"code": 600,
|
||||||
"message": "Import already in progress"
|
"message": "Import already in progress",
|
||||||
|
"data": {"internal_type": "ImportInProgress"}
|
||||||
}
|
}
|
||||||
} in messages
|
} in messages
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ from unittest.mock import call
|
|||||||
import pytest
|
import pytest
|
||||||
from galaxy.api.types import GameTime
|
from galaxy.api.types import GameTime
|
||||||
from galaxy.api.errors import BackendError
|
from galaxy.api.errors import BackendError
|
||||||
from galaxy.unittest.mock import async_return_value, skip_loop
|
from galaxy.unittest.mock import skip_loop
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_game_time_success(plugin, read, write):
|
async def test_get_game_time_success(plugin, read, write):
|
||||||
plugin.prepare_game_times_context.return_value = async_return_value("abc")
|
plugin.prepare_game_times_context.return_value = "abc"
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
@@ -19,13 +19,14 @@ async def test_get_game_time_success(plugin, read, write):
|
|||||||
"game_ids": ["3", "5", "7"]
|
"game_ids": ["3", "5", "7"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_game_time.side_effect = [
|
plugin.get_game_time.side_effect = [
|
||||||
async_return_value(GameTime("3", 60, 1549550504)),
|
GameTime("3", 60, 1549550504),
|
||||||
async_return_value(GameTime("5", 10, None)),
|
GameTime("5", 10, None),
|
||||||
async_return_value(GameTime("7", None, 1549550502)),
|
GameTime("7", None, 1549550502),
|
||||||
]
|
]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_game_time.assert_has_calls([
|
plugin.get_game_time.assert_has_calls([
|
||||||
call("3", "abc"),
|
call("3", "abc"),
|
||||||
call("5", "abc"),
|
call("5", "abc"),
|
||||||
@@ -79,12 +80,12 @@ async def test_get_game_time_success(plugin, read, write):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize("exception,code,message", [
|
@pytest.mark.parametrize("exception,code,message, internal_type", [
|
||||||
(BackendError, 4, "Backend error"),
|
(BackendError, 4, "Backend error", "BackendError"),
|
||||||
(KeyError, 0, "Unknown error")
|
(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)
|
plugin.prepare_game_times_context.return_value = None
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
@@ -93,9 +94,10 @@ async def test_get_game_time_error(exception, code, message, plugin, read, write
|
|||||||
"game_ids": ["6"]
|
"game_ids": ["6"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_game_time.side_effect = exception
|
plugin.get_game_time.side_effect = exception
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_game_time.assert_called()
|
plugin.get_game_time.assert_called()
|
||||||
plugin.game_times_import_complete.assert_called_once_with()
|
plugin.game_times_import_complete.assert_called_once_with()
|
||||||
|
|
||||||
@@ -112,7 +114,8 @@ async def test_get_game_time_error(exception, code, message, plugin, read, write
|
|||||||
"game_id": "6",
|
"game_id": "6",
|
||||||
"error": {
|
"error": {
|
||||||
"code": code,
|
"code": code,
|
||||||
"message": message
|
"message": message,
|
||||||
|
"data" : {"internal_type" : internal_type}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -135,16 +138,17 @@ async def test_prepare_get_game_time_context_error(plugin, read, write):
|
|||||||
"game_ids": ["6"]
|
"game_ids": ["6"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 4,
|
"code": 4,
|
||||||
"message": "Backend error"
|
"message": "Backend error",
|
||||||
|
"data": {"internal_type": "BackendError"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -152,7 +156,7 @@ async def test_prepare_get_game_time_context_error(plugin, read, write):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_import_in_progress(plugin, read, write):
|
async def test_import_in_progress(plugin, read, write):
|
||||||
plugin.prepare_game_times_context.return_value = async_return_value(None)
|
plugin.prepare_game_times_context.return_value = None
|
||||||
requests = [
|
requests = [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -172,12 +176,13 @@ async def test_import_in_progress(plugin, read, write):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
read.side_effect = [
|
read.side_effect = [
|
||||||
async_return_value(create_message(requests[0])),
|
create_message(requests[0]),
|
||||||
async_return_value(create_message(requests[1])),
|
create_message(requests[1]),
|
||||||
async_return_value(b"", 10)
|
b""
|
||||||
]
|
]
|
||||||
|
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
|
|
||||||
messages = get_messages(write)
|
messages = get_messages(write)
|
||||||
assert {
|
assert {
|
||||||
@@ -190,7 +195,8 @@ async def test_import_in_progress(plugin, read, write):
|
|||||||
"id": "4",
|
"id": "4",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 600,
|
"code": 600,
|
||||||
"message": "Import already in progress"
|
"message": "Import already in progress",
|
||||||
|
"data": {"internal_type": "ImportInProgress"}
|
||||||
}
|
}
|
||||||
} in messages
|
} in messages
|
||||||
|
|
||||||
@@ -200,7 +206,7 @@ async def test_update_game(plugin, write):
|
|||||||
game_time = GameTime("3", 60, 1549550504)
|
game_time = GameTime("3", 60, 1549550504)
|
||||||
plugin.update_game_time(game_time)
|
plugin.update_game_time(game_time)
|
||||||
await skip_loop()
|
await skip_loop()
|
||||||
|
await plugin.wait_closed()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
|
|
||||||
from tests import create_message
|
from tests import create_message
|
||||||
|
|
||||||
|
|
||||||
@@ -15,6 +13,7 @@ async def test_success(plugin, read):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"")]
|
read.side_effect = [create_message(request), b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.install_game.assert_called_with(game_id="3")
|
plugin.install_game.assert_called_with(game_id="3")
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import pytest
|
|||||||
|
|
||||||
from galaxy.api.plugin import Plugin
|
from galaxy.api.plugin import Plugin
|
||||||
from galaxy.api.consts import Platform
|
from galaxy.api.consts import Platform
|
||||||
from galaxy.unittest.mock import async_return_value
|
from galaxy.unittest.mock import delayed_return_value_iterable
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
@@ -20,8 +20,9 @@ async def test_get_capabilities(reader, writer, read, write):
|
|||||||
}
|
}
|
||||||
token = "token"
|
token = "token"
|
||||||
plugin = PluginImpl(Platform.Generic, "0.1", reader, writer, token)
|
plugin = PluginImpl(Platform.Generic, "0.1", reader, writer, token)
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"")]
|
read.side_effect = [create_message(request), b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -44,7 +45,7 @@ async def test_shutdown(plugin, read, write):
|
|||||||
"id": "5",
|
"id": "5",
|
||||||
"method": "shutdown"
|
"method": "shutdown"
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request))]
|
read.side_effect = [create_message(request)]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
await plugin.wait_closed()
|
await plugin.wait_closed()
|
||||||
plugin.shutdown.assert_called_with()
|
plugin.shutdown.assert_called_with()
|
||||||
@@ -64,8 +65,9 @@ async def test_ping(plugin, read, write):
|
|||||||
"id": "7",
|
"id": "7",
|
||||||
"method": "ping"
|
"method": "ping"
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"")]
|
read.side_effect = [create_message(request), b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -77,8 +79,9 @@ async def test_ping(plugin, read, write):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_tick_before_handshake(plugin, read):
|
async def test_tick_before_handshake(plugin, read):
|
||||||
read.side_effect = [async_return_value(b"")]
|
read.side_effect = [b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.tick.assert_not_called()
|
plugin.tick.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
@@ -90,6 +93,7 @@ async def test_tick_after_handshake(plugin, read):
|
|||||||
"method": "initialize_cache",
|
"method": "initialize_cache",
|
||||||
"params": {"data": {}}
|
"params": {"data": {}}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"")]
|
read.side_effect = delayed_return_value_iterable([create_message(request), b""], 1)
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.tick.assert_called_with()
|
plugin.tick.assert_called_with()
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
|
|
||||||
from tests import create_message
|
from tests import create_message
|
||||||
|
|
||||||
|
|
||||||
@@ -15,6 +13,7 @@ async def test_success(plugin, read):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"")]
|
read.side_effect = [create_message(request), b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.launch_game.assert_called_with(game_id="3")
|
plugin.launch_game.assert_called_with(game_id="3")
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
|
|
||||||
from tests import create_message
|
from tests import create_message
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -11,7 +9,8 @@ async def test_success(plugin, read):
|
|||||||
"method": "launch_platform_client"
|
"method": "launch_platform_client"
|
||||||
}
|
}
|
||||||
|
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"")]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.launch_platform_client.return_value = async_return_value(None)
|
plugin.launch_platform_client.return_value = None
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.launch_platform_client.assert_called_with()
|
plugin.launch_platform_client.assert_called_with()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import pytest
|
|||||||
from galaxy.api.types import LocalGame
|
from galaxy.api.types import LocalGame
|
||||||
from galaxy.api.consts import LocalGameState
|
from galaxy.api.consts import LocalGameState
|
||||||
from galaxy.api.errors import UnknownError, FailedParsingManifest
|
from galaxy.api.errors import UnknownError, FailedParsingManifest
|
||||||
from galaxy.unittest.mock import async_return_value, skip_loop
|
from galaxy.unittest.mock import skip_loop
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
@@ -15,14 +15,15 @@ async def test_success(plugin, read, write):
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"method": "import_local_games"
|
"method": "import_local_games"
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
|
|
||||||
plugin.get_local_games.return_value = async_return_value([
|
plugin.get_local_games.return_value = [
|
||||||
LocalGame("1", LocalGameState.Running),
|
LocalGame("1", LocalGameState.Running),
|
||||||
LocalGame("2", LocalGameState.Installed),
|
LocalGame("2", LocalGameState.Installed),
|
||||||
LocalGame("3", LocalGameState.Installed | LocalGameState.Running)
|
LocalGame("3", LocalGameState.Installed | LocalGameState.Running)
|
||||||
])
|
]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_local_games.assert_called_with()
|
plugin.get_local_games.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
@@ -51,21 +52,22 @@ async def test_success(plugin, read, write):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"error,code,message",
|
"error,code,message, internal_type",
|
||||||
[
|
[
|
||||||
pytest.param(UnknownError, 0, "Unknown error", id="unknown_error"),
|
pytest.param(UnknownError, 0, "Unknown error", "UnknownError", id="unknown_error"),
|
||||||
pytest.param(FailedParsingManifest, 200, "Failed parsing manifest", id="failed_parsing")
|
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 = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
"method": "import_local_games"
|
"method": "import_local_games"
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_local_games.side_effect = error()
|
plugin.get_local_games.side_effect = error()
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_local_games.assert_called_with()
|
plugin.get_local_games.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
@@ -74,7 +76,8 @@ async def test_failure(plugin, read, write, error, code, message):
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"error": {
|
"error": {
|
||||||
"code": code,
|
"code": code,
|
||||||
"message": message
|
"message": message,
|
||||||
|
"data" : {"internal_type" : internal_type}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,29 +1,30 @@
|
|||||||
from unittest.mock import call
|
from unittest.mock import call
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from galaxy.api.errors import FailedParsingManifest
|
from galaxy.api.errors import FailedParsingManifest
|
||||||
from galaxy.unittest.mock import async_return_value
|
from galaxy.unittest.mock import delayed_return_value
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_local_size_success(plugin, read, write):
|
async def test_get_local_size_success(plugin, read, write):
|
||||||
context = {'abc': 'def'}
|
context = {'abc': 'def'}
|
||||||
plugin.prepare_local_size_context.return_value = async_return_value(context)
|
plugin.prepare_local_size_context.return_value = context
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "11",
|
"id": "11",
|
||||||
"method": "start_local_size_import",
|
"method": "start_local_size_import",
|
||||||
"params": {"game_ids": ["777", "13", "42"]}
|
"params": {"game_ids": ["777", "13", "42"]}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_local_size.side_effect = [
|
plugin.get_local_size.side_effect = [
|
||||||
async_return_value(100000000000),
|
100000000000,
|
||||||
async_return_value(None),
|
None,
|
||||||
async_return_value(3333333)
|
3333333
|
||||||
]
|
]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_local_size.assert_has_calls([
|
plugin.get_local_size.assert_has_calls([
|
||||||
call("777", context),
|
call("777", context),
|
||||||
call("13", context),
|
call("13", context),
|
||||||
@@ -31,12 +32,17 @@ async def test_get_local_size_success(plugin, read, write):
|
|||||||
])
|
])
|
||||||
plugin.local_size_import_complete.assert_called_once_with()
|
plugin.local_size_import_complete.assert_called_once_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
messages = get_messages(write)
|
||||||
{
|
prepare_local_size_context_response = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "11",
|
"id": "11",
|
||||||
"result": None
|
"result": None
|
||||||
},
|
}
|
||||||
|
# response for prepare_local_size_context may be returned before or after
|
||||||
|
# notifications about import success
|
||||||
|
assert prepare_local_size_context_response in messages
|
||||||
|
messages.remove(prepare_local_size_context_response)
|
||||||
|
assert messages == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "local_size_import_success",
|
"method": "local_size_import_success",
|
||||||
@@ -69,32 +75,36 @@ async def test_get_local_size_success(plugin, read, write):
|
|||||||
]
|
]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize("exception,code,message", [
|
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||||
(FailedParsingManifest, 200, "Failed parsing manifest"),
|
(FailedParsingManifest, 200, "Failed parsing manifest", "FailedParsingManifest"),
|
||||||
(KeyError, 0, "Unknown error")
|
(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"
|
game_id = "6"
|
||||||
request_id = "55"
|
request_id = "55"
|
||||||
plugin.prepare_local_size_context.return_value = async_return_value(None)
|
plugin.prepare_local_size_context.return_value = None
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": request_id,
|
"id": request_id,
|
||||||
"method": "start_local_size_import",
|
"method": "start_local_size_import",
|
||||||
"params": {"game_ids": [game_id]}
|
"params": {"game_ids": [game_id]}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_local_size.side_effect = exception
|
plugin.get_local_size.side_effect = exception
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_local_size.assert_called()
|
plugin.get_local_size.assert_called()
|
||||||
plugin.local_size_import_complete.assert_called_once_with()
|
plugin.local_size_import_complete.assert_called_once_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
direct_response = {
|
||||||
{
|
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": request_id,
|
"id": request_id,
|
||||||
"result": None
|
"result": None
|
||||||
},
|
}
|
||||||
|
responses = get_messages(write)
|
||||||
|
assert direct_response in responses
|
||||||
|
responses.remove(direct_response)
|
||||||
|
assert responses == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "local_size_import_failure",
|
"method": "local_size_import_failure",
|
||||||
@@ -102,7 +112,10 @@ async def test_get_local_size_error(exception, code, message, plugin, read, writ
|
|||||||
"game_id": game_id,
|
"game_id": game_id,
|
||||||
"error": {
|
"error": {
|
||||||
"code": code,
|
"code": code,
|
||||||
"message": message
|
"message": message,
|
||||||
|
"data": {
|
||||||
|
"internal_type": internal_type
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -117,18 +130,18 @@ async def test_get_local_size_error(exception, code, message, plugin, read, writ
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_prepare_get_local_size_context_error(plugin, read, write):
|
async def test_prepare_get_local_size_context_error(plugin, read, write):
|
||||||
request_id = "31415"
|
request_id = "31415"
|
||||||
error_details = "Unexpected syntax"
|
error_details = {"Details": "Unexpected syntax"}
|
||||||
error_message, error_code = FailedParsingManifest().message, FailedParsingManifest().code
|
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 = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": request_id,
|
"id": request_id,
|
||||||
"method": "start_local_size_import",
|
"method": "start_local_size_import",
|
||||||
"params": {"game_ids": ["6"]}
|
"params": {"game_ids": ["6"]}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -136,7 +149,10 @@ async def test_prepare_get_local_size_context_error(plugin, read, write):
|
|||||||
"error": {
|
"error": {
|
||||||
"code": error_code,
|
"code": error_code,
|
||||||
"message": error_message,
|
"message": error_message,
|
||||||
"data": error_details
|
"data": {
|
||||||
|
"internal_type": "FailedParsingManifest",
|
||||||
|
"Details": "Unexpected syntax"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -144,7 +160,10 @@ async def test_prepare_get_local_size_context_error(plugin, read, write):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_import_already_in_progress_error(plugin, read, write):
|
async def test_import_already_in_progress_error(plugin, read, write):
|
||||||
plugin.prepare_local_size_context.return_value = async_return_value(None)
|
plugin.prepare_local_size_context.return_value = None
|
||||||
|
print("******", plugin.get_local_size)
|
||||||
|
|
||||||
|
plugin.get_local_size.side_effect = delayed_return_value(100, 5)
|
||||||
requests = [
|
requests = [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -164,12 +183,13 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
read.side_effect = [
|
read.side_effect = [
|
||||||
async_return_value(create_message(requests[0])),
|
create_message(requests[0]),
|
||||||
async_return_value(create_message(requests[1])),
|
create_message(requests[1]),
|
||||||
async_return_value(b"", 10)
|
b""
|
||||||
]
|
]
|
||||||
|
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
|
|
||||||
responses = get_messages(write)
|
responses = get_messages(write)
|
||||||
assert {
|
assert {
|
||||||
@@ -182,7 +202,7 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
|||||||
"id": "4",
|
"id": "4",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 600,
|
"code": 600,
|
||||||
"message": "Import already in progress"
|
"message": "Import already in progress",
|
||||||
|
"data": {"internal_type": "ImportInProgress"}
|
||||||
}
|
}
|
||||||
} in responses
|
} in responses
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from unittest.mock import call
|
|||||||
import pytest
|
import pytest
|
||||||
from galaxy.api.consts import OSCompatibility
|
from galaxy.api.consts import OSCompatibility
|
||||||
from galaxy.api.errors import BackendError
|
from galaxy.api.errors import BackendError
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
@@ -11,20 +10,21 @@ from tests import create_message, get_messages
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_os_compatibility_success(plugin, read, write):
|
async def test_get_os_compatibility_success(plugin, read, write):
|
||||||
context = "abc"
|
context = "abc"
|
||||||
plugin.prepare_os_compatibility_context.return_value = async_return_value(context)
|
plugin.prepare_os_compatibility_context.return_value = context
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "11",
|
"id": "11",
|
||||||
"method": "start_os_compatibility_import",
|
"method": "start_os_compatibility_import",
|
||||||
"params": {"game_ids": ["666", "13", "42"]}
|
"params": {"game_ids": ["666", "13", "42"]}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_os_compatibility.side_effect = [
|
plugin.get_os_compatibility.side_effect = [
|
||||||
async_return_value(OSCompatibility.Linux),
|
OSCompatibility.Linux,
|
||||||
async_return_value(None),
|
None,
|
||||||
async_return_value(OSCompatibility.Windows | OSCompatibility.MacOS),
|
OSCompatibility.Windows | OSCompatibility.MacOS,
|
||||||
]
|
]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_os_compatibility.assert_has_calls([
|
plugin.get_os_compatibility.assert_has_calls([
|
||||||
call("666", context),
|
call("666", context),
|
||||||
call("13", context),
|
call("13", context),
|
||||||
@@ -71,23 +71,24 @@ async def test_get_os_compatibility_success(plugin, read, write):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize("exception,code,message", [
|
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||||
(BackendError, 4, "Backend error"),
|
(BackendError, 4, "Backend error", "BackendError"),
|
||||||
(KeyError, 0, "Unknown error")
|
(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"
|
game_id = "6"
|
||||||
request_id = "55"
|
request_id = "55"
|
||||||
plugin.prepare_os_compatibility_context.return_value = async_return_value(None)
|
plugin.prepare_os_compatibility_context.return_value = None
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": request_id,
|
"id": request_id,
|
||||||
"method": "start_os_compatibility_import",
|
"method": "start_os_compatibility_import",
|
||||||
"params": {"game_ids": [game_id]}
|
"params": {"game_ids": [game_id]}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_os_compatibility.side_effect = exception
|
plugin.get_os_compatibility.side_effect = exception
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_os_compatibility.assert_called()
|
plugin.get_os_compatibility.assert_called()
|
||||||
plugin.os_compatibility_import_complete.assert_called_once_with()
|
plugin.os_compatibility_import_complete.assert_called_once_with()
|
||||||
|
|
||||||
@@ -104,7 +105,8 @@ async def test_get_os_compatibility_error(exception, code, message, plugin, read
|
|||||||
"game_id": game_id,
|
"game_id": game_id,
|
||||||
"error": {
|
"error": {
|
||||||
"code": code,
|
"code": code,
|
||||||
"message": message
|
"message": message,
|
||||||
|
"data": {"internal_type": internal_type}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -126,8 +128,9 @@ async def test_prepare_get_os_compatibility_context_error(plugin, read, write):
|
|||||||
"method": "start_os_compatibility_import",
|
"method": "start_os_compatibility_import",
|
||||||
"params": {"game_ids": ["6"]}
|
"params": {"game_ids": ["6"]}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -135,7 +138,8 @@ async def test_prepare_get_os_compatibility_context_error(plugin, read, write):
|
|||||||
"id": request_id,
|
"id": request_id,
|
||||||
"error": {
|
"error": {
|
||||||
"code": 4,
|
"code": 4,
|
||||||
"message": "Backend error"
|
"message": "Backend error",
|
||||||
|
"data": {"internal_type": "BackendError"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -143,7 +147,7 @@ async def test_prepare_get_os_compatibility_context_error(plugin, read, write):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_import_already_in_progress_error(plugin, read, write):
|
async def test_import_already_in_progress_error(plugin, read, write):
|
||||||
plugin.prepare_os_compatibility_context.return_value = async_return_value(None)
|
plugin.prepare_os_compatibility_context.return_value = None
|
||||||
requests = [
|
requests = [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -163,12 +167,13 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
read.side_effect = [
|
read.side_effect = [
|
||||||
async_return_value(create_message(requests[0])),
|
create_message(requests[0]),
|
||||||
async_return_value(create_message(requests[1])),
|
create_message(requests[1]),
|
||||||
async_return_value(b"", 10)
|
b""
|
||||||
]
|
]
|
||||||
|
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
|
|
||||||
responses = get_messages(write)
|
responses = get_messages(write)
|
||||||
assert {
|
assert {
|
||||||
@@ -181,7 +186,8 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
|||||||
"id": "4",
|
"id": "4",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 600,
|
"code": 600,
|
||||||
"message": "Import already in progress"
|
"message": "Import already in progress",
|
||||||
|
"data": {"internal_type": "ImportInProgress"}
|
||||||
}
|
}
|
||||||
} in responses
|
} in responses
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import pytest
|
|||||||
from galaxy.api.types import Game, Dlc, LicenseInfo
|
from galaxy.api.types import Game, Dlc, LicenseInfo
|
||||||
from galaxy.api.consts import LicenseType
|
from galaxy.api.consts import LicenseType
|
||||||
from galaxy.api.errors import UnknownError
|
from galaxy.api.errors import UnknownError
|
||||||
from galaxy.unittest.mock import async_return_value, skip_loop
|
from galaxy.unittest.mock import skip_loop
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
@@ -15,9 +15,9 @@ async def test_success(plugin, read, write):
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"method": "import_owned_games"
|
"method": "import_owned_games"
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
|
|
||||||
plugin.get_owned_games.return_value = async_return_value([
|
plugin.get_owned_games.return_value = [
|
||||||
Game("3", "Doom", None, LicenseInfo(LicenseType.SinglePurchase, None)),
|
Game("3", "Doom", None, LicenseInfo(LicenseType.SinglePurchase, None)),
|
||||||
Game(
|
Game(
|
||||||
"5",
|
"5",
|
||||||
@@ -27,8 +27,9 @@ async def test_success(plugin, read, write):
|
|||||||
Dlc("8", "Temerian Armor Set", LicenseInfo(LicenseType.FreeToPlay, None)),
|
Dlc("8", "Temerian Armor Set", LicenseInfo(LicenseType.FreeToPlay, None)),
|
||||||
],
|
],
|
||||||
LicenseInfo(LicenseType.SinglePurchase, None))
|
LicenseInfo(LicenseType.SinglePurchase, None))
|
||||||
])
|
]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_owned_games.assert_called_with()
|
plugin.get_owned_games.assert_called_with()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -80,9 +81,10 @@ async def test_failure(plugin, read, write):
|
|||||||
"method": "import_owned_games"
|
"method": "import_owned_games"
|
||||||
}
|
}
|
||||||
|
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_owned_games.side_effect = UnknownError()
|
plugin.get_owned_games.side_effect = UnknownError()
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_owned_games.assert_called_with()
|
plugin.get_owned_games.assert_called_with()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -90,7 +92,8 @@ async def test_failure(plugin, read, write):
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 0,
|
"code": 0,
|
||||||
"message": "Unknown error"
|
"message": "Unknown error",
|
||||||
|
"data": {"internal_type": "UnknownError"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from galaxy.unittest.mock import async_return_value, skip_loop
|
from galaxy.unittest.mock import skip_loop
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
@@ -42,10 +42,11 @@ async def test_initialize_cache(plugin, read, write, cache_data):
|
|||||||
"method": "initialize_cache",
|
"method": "initialize_cache",
|
||||||
"params": {"data": cache_data}
|
"params": {"data": cache_data}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"")]
|
read.side_effect = [create_message(request), b""]
|
||||||
|
|
||||||
assert {} == plugin.persistent_cache
|
assert {} == plugin.persistent_cache
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.handshake_complete.assert_called_once_with()
|
plugin.handshake_complete.assert_called_once_with()
|
||||||
assert cache_data == plugin.persistent_cache
|
assert cache_data == plugin.persistent_cache
|
||||||
assert_rpc_response(write, response_id=request_id)
|
assert_rpc_response(write, response_id=request_id)
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
from galaxy.api.errors import (
|
from galaxy.api.errors import (
|
||||||
BackendNotAvailable, BackendTimeout, BackendError, InvalidCredentials, NetworkError, AccessDenied, UnknownError
|
BackendNotAvailable, BackendTimeout, BackendError, InvalidCredentials, NetworkError, AccessDenied, UnknownError
|
||||||
)
|
)
|
||||||
from galaxy.api.jsonrpc import JsonRpcError
|
from galaxy.api.jsonrpc import JsonRpcError
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_refresh_credentials_success(plugin, read, write):
|
async def test_refresh_credentials_success(plugin, read, write):
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ async def test_refresh_credentials_success(plugin, read, write):
|
|||||||
"result": refreshed_credentials
|
"result": refreshed_credentials
|
||||||
}
|
}
|
||||||
# 2 loop iterations delay is to force sending response after request has been sent
|
# 2 loop iterations delay is to force sending response after request has been sent
|
||||||
read.side_effect = [async_return_value(create_message(response), loop_iterations_delay=2)]
|
read.side_effect = [create_message(response), b""]
|
||||||
|
|
||||||
result = await plugin.refresh_credentials({}, False)
|
result = await plugin.refresh_credentials({}, False)
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
@@ -53,12 +54,13 @@ async def test_refresh_credentials_failure(exception, plugin, read, write):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# 2 loop iterations delay is to force sending response after request has been sent
|
# 2 loop iterations delay is to force sending response after request has been sent
|
||||||
read.side_effect = [async_return_value(create_message(response), loop_iterations_delay=2)]
|
read.side_effect = [create_message(response), b""]
|
||||||
|
|
||||||
with pytest.raises(JsonRpcError) as e:
|
with pytest.raises(JsonRpcError) as e:
|
||||||
await plugin.refresh_credentials({}, False)
|
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) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
|
|
||||||
from tests import create_message
|
from tests import create_message
|
||||||
|
|
||||||
@@ -11,7 +10,8 @@ async def test_success(plugin, read):
|
|||||||
"method": "shutdown_platform_client"
|
"method": "shutdown_platform_client"
|
||||||
}
|
}
|
||||||
|
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"")]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.shutdown_platform_client.return_value = async_return_value(None)
|
plugin.shutdown_platform_client.return_value = None
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.shutdown_platform_client.assert_called_with()
|
plugin.shutdown_platform_client.assert_called_with()
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from galaxy.reader import StreamLineReader
|
from galaxy.reader import StreamLineReader
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
@@ -11,14 +10,14 @@ def stream_line_reader(reader):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_message(stream_line_reader, read):
|
async def test_message(stream_line_reader, read):
|
||||||
read.return_value = async_return_value(b"a\n")
|
read.return_value = b"a\n"
|
||||||
assert await stream_line_reader.readline() == b"a"
|
assert await stream_line_reader.readline() == b"a"
|
||||||
read.assert_called_once()
|
read.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_separate_messages(stream_line_reader, read):
|
async def test_separate_messages(stream_line_reader, read):
|
||||||
read.side_effect = [async_return_value(b"a\n"), async_return_value(b"b\n")]
|
read.side_effect = [b"a\n", b"b\n"]
|
||||||
assert await stream_line_reader.readline() == b"a"
|
assert await stream_line_reader.readline() == b"a"
|
||||||
assert await stream_line_reader.readline() == b"b"
|
assert await stream_line_reader.readline() == b"b"
|
||||||
assert read.call_count == 2
|
assert read.call_count == 2
|
||||||
@@ -26,7 +25,7 @@ async def test_separate_messages(stream_line_reader, read):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_connected_messages(stream_line_reader, read):
|
async def test_connected_messages(stream_line_reader, read):
|
||||||
read.return_value = async_return_value(b"a\nb\n")
|
read.return_value = b"a\nb\n"
|
||||||
assert await stream_line_reader.readline() == b"a"
|
assert await stream_line_reader.readline() == b"a"
|
||||||
assert await stream_line_reader.readline() == b"b"
|
assert await stream_line_reader.readline() == b"b"
|
||||||
read.assert_called_once()
|
read.assert_called_once()
|
||||||
@@ -34,13 +33,13 @@ async def test_connected_messages(stream_line_reader, read):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_cut_message(stream_line_reader, read):
|
async def test_cut_message(stream_line_reader, read):
|
||||||
read.side_effect = [async_return_value(b"a"), async_return_value(b"b\n")]
|
read.side_effect = [b"a", b"b\n"]
|
||||||
assert await stream_line_reader.readline() == b"ab"
|
assert await stream_line_reader.readline() == b"ab"
|
||||||
assert read.call_count == 2
|
assert read.call_count == 2
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_half_message(stream_line_reader, read):
|
async def test_half_message(stream_line_reader, read):
|
||||||
read.side_effect = [async_return_value(b"a"), async_return_value(b"")]
|
read.side_effect = [b"a", b""]
|
||||||
assert await stream_line_reader.readline() == b""
|
assert await stream_line_reader.readline() == b""
|
||||||
assert read.call_count == 2
|
assert read.call_count == 2
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import pytest
|
|||||||
from galaxy.api.types import Subscription, SubscriptionGame
|
from galaxy.api.types import Subscription, SubscriptionGame
|
||||||
from galaxy.api.consts import SubscriptionDiscovery
|
from galaxy.api.consts import SubscriptionDiscovery
|
||||||
from galaxy.api.errors import FailedParsingManifest, BackendError, UnknownError
|
from galaxy.api.errors import FailedParsingManifest, BackendError, UnknownError
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
|
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
@@ -14,14 +13,15 @@ async def test_get_subscriptions_success(plugin, read, write):
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"method": "import_subscriptions"
|
"method": "import_subscriptions"
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
|
|
||||||
plugin.get_subscriptions.return_value = async_return_value([
|
plugin.get_subscriptions.return_value = [
|
||||||
Subscription("1"),
|
Subscription("1"),
|
||||||
Subscription("2", False, subscription_discovery=SubscriptionDiscovery.AUTOMATIC),
|
Subscription("2", False, subscription_discovery=SubscriptionDiscovery.AUTOMATIC),
|
||||||
Subscription("3", True, 1580899100, SubscriptionDiscovery.USER_ENABLED)
|
Subscription("3", True, 1580899100, SubscriptionDiscovery.USER_ENABLED)
|
||||||
])
|
]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_subscriptions.assert_called_with()
|
plugin.get_subscriptions.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
@@ -53,21 +53,22 @@ async def test_get_subscriptions_success(plugin, read, write):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"error,code,message",
|
"error,code,message,internal_type",
|
||||||
[
|
[
|
||||||
pytest.param(UnknownError, 0, "Unknown error", id="unknown_error"),
|
pytest.param(UnknownError, 0, "Unknown error", "UnknownError", id="unknown_error"),
|
||||||
pytest.param(FailedParsingManifest, 200, "Failed parsing manifest", id="failed_parsing")
|
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 = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
"method": "import_subscriptions"
|
"method": "import_subscriptions"
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_subscriptions.side_effect = error()
|
plugin.get_subscriptions.side_effect = error()
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_subscriptions.assert_called_with()
|
plugin.get_subscriptions.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
@@ -76,6 +77,7 @@ async def test_get_subscriptions_failure_generic(plugin, read, write, error, cod
|
|||||||
"id": "3",
|
"id": "3",
|
||||||
"error": {
|
"error": {
|
||||||
"code": code,
|
"code": code,
|
||||||
|
"data": {"internal_type": internal_type},
|
||||||
"message": message
|
"message": message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,7 +86,7 @@ async def test_get_subscriptions_failure_generic(plugin, read, write, error, cod
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_subscription_games_success(plugin, read, write):
|
async def test_get_subscription_games_success(plugin, read, write):
|
||||||
plugin.prepare_subscription_games_context.return_value = async_return_value(5)
|
plugin.prepare_subscription_games_context.return_value = 5
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
@@ -93,22 +95,28 @@ async def test_get_subscription_games_success(plugin, read, write):
|
|||||||
"subscription_names": ["sub_a"]
|
"subscription_names": ["sub_a"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
|
|
||||||
async def sub_games():
|
# Create an async generator that yields the games
|
||||||
|
async def mock_subscription_games_generator(subscription_name, context):
|
||||||
games = [
|
games = [
|
||||||
SubscriptionGame(game_title="game A", game_id="game_A"),
|
# first chunk of the games
|
||||||
|
[SubscriptionGame(game_title="game A", game_id="game_A"),
|
||||||
SubscriptionGame(game_title="game B", game_id="game_B", start_time=1548495632),
|
SubscriptionGame(game_title="game B", game_id="game_B", start_time=1548495632),
|
||||||
SubscriptionGame(game_title="game C", game_id="game_C", end_time=1548495633),
|
SubscriptionGame(game_title="game C", game_id="game_C", end_time=1548495633)],
|
||||||
SubscriptionGame(game_title="game D", game_id="game_D", start_time=1548495632, end_time=1548495633),
|
# second chunk of the games
|
||||||
|
[SubscriptionGame(game_title="game D", game_id="game_D", start_time=1548495632, end_time=1548495633)],
|
||||||
]
|
]
|
||||||
yield [game for game in games]
|
for game in games:
|
||||||
|
yield game
|
||||||
|
|
||||||
|
plugin.get_subscription_games.side_effect = mock_subscription_games_generator
|
||||||
|
|
||||||
plugin.get_subscription_games.return_value = sub_games()
|
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.prepare_subscription_games_context.assert_called_with(["sub_a"])
|
plugin.prepare_subscription_games_context.assert_called_with(["sub_a"])
|
||||||
plugin.get_subscription_games.assert_called_with("sub_a", 5)
|
plugin.get_subscription_games.assert_called_with("sub_a", 5)
|
||||||
plugin.subscription_games_import_complete.asert_called_with()
|
plugin.subscription_games_import_complete.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -136,6 +144,15 @@ async def test_get_subscription_games_success(plugin, read, write):
|
|||||||
"game_id": "game_C",
|
"game_id": "game_C",
|
||||||
"end_time": 1548495633
|
"end_time": 1548495633
|
||||||
},
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "subscription_games_import_success",
|
||||||
|
"params": {
|
||||||
|
"subscription_name": "sub_a",
|
||||||
|
"subscription_games": [
|
||||||
{
|
{
|
||||||
"game_title": "game D",
|
"game_title": "game D",
|
||||||
"game_id": "game_D",
|
"game_id": "game_D",
|
||||||
@@ -162,7 +179,7 @@ async def test_get_subscription_games_success(plugin, read, write):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_subscription_games_success_empty(plugin, read, write):
|
async def test_get_subscription_games_success_empty(plugin, read, write):
|
||||||
plugin.prepare_subscription_games_context.return_value = async_return_value(5)
|
plugin.prepare_subscription_games_context.return_value = 5
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
@@ -171,16 +188,17 @@ async def test_get_subscription_games_success_empty(plugin, read, write):
|
|||||||
"subscription_names": ["sub_a"]
|
"subscription_names": ["sub_a"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
|
|
||||||
async def sub_games():
|
async def sub_games():
|
||||||
yield None
|
yield None
|
||||||
|
|
||||||
plugin.get_subscription_games.return_value = sub_games()
|
plugin.get_subscription_games.return_value = sub_games()
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.prepare_subscription_games_context.assert_called_with(["sub_a"])
|
plugin.prepare_subscription_games_context.assert_called_with(["sub_a"])
|
||||||
plugin.get_subscription_games.assert_called_with("sub_a", 5)
|
plugin.get_subscription_games.assert_called_with("sub_a", 5)
|
||||||
plugin.subscription_games_import_complete.asert_called_with()
|
plugin.subscription_games_import_complete.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -212,12 +230,12 @@ async def test_get_subscription_games_success_empty(plugin, read, write):
|
|||||||
]
|
]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize("exception,code,message", [
|
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||||
(BackendError, 4, "Backend error"),
|
(BackendError, 4, "Backend error", "BackendError"),
|
||||||
(KeyError, 0, "Unknown error")
|
(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)
|
plugin.prepare_subscription_games_context.return_value = None
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "3",
|
"id": "3",
|
||||||
@@ -227,11 +245,12 @@ async def test_get_subscription_games_error(exception, code, message, plugin, re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_subscription_games.side_effect = exception
|
plugin.get_subscription_games.side_effect = exception
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_subscription_games.assert_called()
|
plugin.get_subscription_games.assert_called()
|
||||||
plugin.subscription_games_import_complete.asert_called_with()
|
plugin.subscription_games_import_complete.assert_called_with()
|
||||||
|
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
@@ -246,7 +265,8 @@ async def test_get_subscription_games_error(exception, code, message, plugin, re
|
|||||||
"subscription_name": "sub_a",
|
"subscription_name": "sub_a",
|
||||||
"error": {
|
"error": {
|
||||||
"code": code,
|
"code": code,
|
||||||
"message": message
|
"message": message,
|
||||||
|
"data": {"internal_type": internal_type}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -269,18 +289,18 @@ async def test_get_subscription_games_error(exception, code, message, plugin, re
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_prepare_get_subscription_games_context_error(plugin, read, write):
|
async def test_prepare_get_subscription_games_context_error(plugin, read, write):
|
||||||
request_id = "31415"
|
request_id = "31415"
|
||||||
error_details = "Unexpected backend error"
|
error_details = {"Details": "Unexpected backend error"}
|
||||||
error_message, error_code = BackendError().message, BackendError().code
|
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 = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": request_id,
|
"id": request_id,
|
||||||
"method": "start_subscription_games_import",
|
"method": "start_subscription_games_import",
|
||||||
"params": {"subscription_names": ["sub_a", "sub_b"]}
|
"params": {"subscription_names": ["sub_a", "sub_b"]}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -288,7 +308,10 @@ async def test_prepare_get_subscription_games_context_error(plugin, read, write)
|
|||||||
"error": {
|
"error": {
|
||||||
"code": error_code,
|
"code": error_code,
|
||||||
"message": error_message,
|
"message": error_message,
|
||||||
"data": error_details
|
"data": {
|
||||||
|
"internal_type": "BackendError",
|
||||||
|
"Details": "Unexpected backend error"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -296,7 +319,7 @@ async def test_prepare_get_subscription_games_context_error(plugin, read, write)
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_import_already_in_progress_error(plugin, read, write):
|
async def test_import_already_in_progress_error(plugin, read, write):
|
||||||
plugin.prepare_subscription_games_context.return_value = async_return_value(None)
|
plugin.prepare_subscription_games_context.return_value = None
|
||||||
requests = [
|
requests = [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -316,13 +339,13 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
read.side_effect = [
|
read.side_effect = [
|
||||||
async_return_value(create_message(requests[0])),
|
create_message(requests[0]),
|
||||||
async_return_value(create_message(requests[1])),
|
create_message(requests[1]),
|
||||||
async_return_value(b"", 10)
|
b""
|
||||||
]
|
]
|
||||||
|
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
responses = get_messages(write)
|
responses = get_messages(write)
|
||||||
assert {
|
assert {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -334,7 +357,8 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
|||||||
"id": "4",
|
"id": "4",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 600,
|
"code": 600,
|
||||||
"message": "Import already in progress"
|
"message": "Import already in progress",
|
||||||
|
"data": {"internal_type": "ImportInProgress"}
|
||||||
}
|
}
|
||||||
} in responses
|
} in responses
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from galaxy.unittest.mock import async_return_value
|
|
||||||
|
|
||||||
from tests import create_message
|
from tests import create_message
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -13,7 +11,8 @@ async def test_success(plugin, read):
|
|||||||
"game_id": "3"
|
"game_id": "3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"")]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_owned_games.return_value = None
|
plugin.get_owned_games.return_value = None
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.uninstall_game.assert_called_with(game_id="3")
|
plugin.uninstall_game.assert_called_with(game_id="3")
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import pytest
|
|||||||
from galaxy.api.consts import PresenceState
|
from galaxy.api.consts import PresenceState
|
||||||
from galaxy.api.errors import BackendError
|
from galaxy.api.errors import BackendError
|
||||||
from galaxy.api.types import UserPresence
|
from galaxy.api.types import UserPresence
|
||||||
from galaxy.unittest.mock import async_return_value, skip_loop
|
from galaxy.unittest.mock import skip_loop
|
||||||
from tests import create_message, get_messages
|
from tests import create_message, get_messages
|
||||||
|
|
||||||
|
|
||||||
@@ -13,52 +13,53 @@ from tests import create_message, get_messages
|
|||||||
async def test_get_user_presence_success(plugin, read, write):
|
async def test_get_user_presence_success(plugin, read, write):
|
||||||
context = "abc"
|
context = "abc"
|
||||||
user_id_list = ["666", "13", "42", "69", "22"]
|
user_id_list = ["666", "13", "42", "69", "22"]
|
||||||
plugin.prepare_user_presence_context.return_value = async_return_value(context)
|
plugin.prepare_user_presence_context.return_value = context
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": "11",
|
"id": "11",
|
||||||
"method": "start_user_presence_import",
|
"method": "start_user_presence_import",
|
||||||
"params": {"user_id_list": user_id_list}
|
"params": {"user_id_list": user_id_list}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_user_presence.side_effect = [
|
plugin.get_user_presence.side_effect = [
|
||||||
async_return_value(UserPresence(
|
UserPresence(
|
||||||
PresenceState.Unknown,
|
PresenceState.Unknown,
|
||||||
"game-id1",
|
"game-id1",
|
||||||
None,
|
None,
|
||||||
"unknown state",
|
"unknown state",
|
||||||
None
|
None
|
||||||
)),
|
),
|
||||||
async_return_value(UserPresence(
|
UserPresence(
|
||||||
PresenceState.Offline,
|
PresenceState.Offline,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
"Going to grandma's house",
|
"Going to grandma's house",
|
||||||
None
|
None
|
||||||
)),
|
),
|
||||||
async_return_value(UserPresence(
|
UserPresence(
|
||||||
PresenceState.Online,
|
PresenceState.Online,
|
||||||
"game-id3",
|
"game-id3",
|
||||||
"game-title3",
|
"game-title3",
|
||||||
"Pew pew",
|
"Pew pew",
|
||||||
None
|
None
|
||||||
)),
|
),
|
||||||
async_return_value(UserPresence(
|
UserPresence(
|
||||||
PresenceState.Away,
|
PresenceState.Away,
|
||||||
None,
|
None,
|
||||||
"game-title4",
|
"game-title4",
|
||||||
"AFKKTHXBY",
|
"AFKKTHXBY",
|
||||||
None
|
None
|
||||||
)),
|
),
|
||||||
async_return_value(UserPresence(
|
UserPresence(
|
||||||
PresenceState.Away,
|
PresenceState.Away,
|
||||||
None,
|
None,
|
||||||
"game-title5",
|
"game-title5",
|
||||||
None,
|
None,
|
||||||
"Playing game-title5: In Menu"
|
"Playing game-title5: In Menu"
|
||||||
)),
|
),
|
||||||
]
|
]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_user_presence.assert_has_calls([
|
plugin.get_user_presence.assert_has_calls([
|
||||||
call(user_id, context) for user_id in user_id_list
|
call(user_id, context) for user_id in user_id_list
|
||||||
])
|
])
|
||||||
@@ -139,23 +140,24 @@ async def test_get_user_presence_success(plugin, read, write):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize("exception,code,message", [
|
@pytest.mark.parametrize("exception,code,message,internal_type", [
|
||||||
(BackendError, 4, "Backend error"),
|
(BackendError, 4, "Backend error", "BackendError"),
|
||||||
(KeyError, 0, "Unknown error")
|
(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"
|
user_id = "69"
|
||||||
request_id = "55"
|
request_id = "55"
|
||||||
plugin.prepare_user_presence_context.return_value = async_return_value(None)
|
plugin.prepare_user_presence_context.return_value = None
|
||||||
request = {
|
request = {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": request_id,
|
"id": request_id,
|
||||||
"method": "start_user_presence_import",
|
"method": "start_user_presence_import",
|
||||||
"params": {"user_id_list": [user_id]}
|
"params": {"user_id_list": [user_id]}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
plugin.get_user_presence.side_effect = exception
|
plugin.get_user_presence.side_effect = exception
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
plugin.get_user_presence.assert_called()
|
plugin.get_user_presence.assert_called()
|
||||||
plugin.user_presence_import_complete.assert_called_once_with()
|
plugin.user_presence_import_complete.assert_called_once_with()
|
||||||
|
|
||||||
@@ -172,7 +174,10 @@ async def test_get_user_presence_error(exception, code, message, plugin, read, w
|
|||||||
"user_id": user_id,
|
"user_id": user_id,
|
||||||
"error": {
|
"error": {
|
||||||
"code": code,
|
"code": code,
|
||||||
"message": message
|
"message": message,
|
||||||
|
"data": {
|
||||||
|
"internal_type": internal_type
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -194,16 +199,19 @@ async def test_prepare_get_user_presence_context_error(plugin, read, write):
|
|||||||
"method": "start_user_presence_import",
|
"method": "start_user_presence_import",
|
||||||
"params": {"user_id_list": ["6"]}
|
"params": {"user_id_list": ["6"]}
|
||||||
}
|
}
|
||||||
read.side_effect = [async_return_value(create_message(request)), async_return_value(b"", 10)]
|
read.side_effect = [create_message(request), b""]
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
assert get_messages(write) == [
|
assert get_messages(write) == [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": request_id,
|
"id": request_id,
|
||||||
"error": {
|
"error": {
|
||||||
"code": 4,
|
"code": 4,
|
||||||
"message": "Backend error"
|
"message": "Backend error",
|
||||||
|
"data": {
|
||||||
|
"internal_type": "BackendError"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -211,7 +219,7 @@ async def test_prepare_get_user_presence_context_error(plugin, read, write):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_import_already_in_progress_error(plugin, read, write):
|
async def test_import_already_in_progress_error(plugin, read, write):
|
||||||
plugin.prepare_user_presence_context.return_value = async_return_value(None)
|
plugin.prepare_user_presence_context.return_value = None
|
||||||
requests = [
|
requests = [
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -231,13 +239,13 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
read.side_effect = [
|
read.side_effect = [
|
||||||
async_return_value(create_message(requests[0])),
|
create_message(requests[0]),
|
||||||
async_return_value(create_message(requests[1])),
|
create_message(requests[1]),
|
||||||
async_return_value(b"", 10)
|
b""
|
||||||
]
|
]
|
||||||
|
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
await plugin.wait_closed()
|
||||||
responses = get_messages(write)
|
responses = get_messages(write)
|
||||||
assert {
|
assert {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@@ -249,7 +257,8 @@ async def test_import_already_in_progress_error(plugin, read, write):
|
|||||||
"id": "4",
|
"id": "4",
|
||||||
"error": {
|
"error": {
|
||||||
"code": 600,
|
"code": 600,
|
||||||
"message": "Import already in progress"
|
"message": "Import already in progress",
|
||||||
|
"data": {"internal_type": "ImportInProgress"}
|
||||||
}
|
}
|
||||||
} in responses
|
} in responses
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user