mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-06-25 06:26:40 +00:00
Merge pull request #1343 from NotAFile/add-tests
Add example unit test and config for testing
This commit is contained in:
commit
ccbc1c669c
8
.coveragerc
Normal file
8
.coveragerc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[run]
|
||||||
|
branch = true
|
||||||
|
parallel = true
|
||||||
|
source =
|
||||||
|
telethon
|
||||||
|
|
||||||
|
[report]
|
||||||
|
precision = 2
|
28
.github/workflows/python.yml
vendored
Normal file
28
.github/workflows/python.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: Python Library
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version: ["3.5", "3.6", "3.7", "3.8"]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v1
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
- name: Set up env
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install tox
|
||||||
|
- name: Lint with flake8
|
||||||
|
run: |
|
||||||
|
tox -e flake
|
||||||
|
- name: Test with pytest
|
||||||
|
run: |
|
||||||
|
# use "py", which is the default python version
|
||||||
|
tox -e py
|
3
dev-requirements.txt
Normal file
3
dev-requirements.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pytest
|
||||||
|
pytest-cov
|
||||||
|
pytest-asyncio
|
@ -1,4 +1,4 @@
|
|||||||
cryptg
|
cryptg
|
||||||
pysocks
|
pysocks
|
||||||
hachoir3
|
hachoir
|
||||||
pillow
|
pillow
|
||||||
|
87
readthedocs/developing/testing.rst
Normal file
87
readthedocs/developing/testing.rst
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
=====
|
||||||
|
Tests
|
||||||
|
=====
|
||||||
|
|
||||||
|
Telethon uses `Pytest <https://pytest.org/>`__, for testing, `Tox
|
||||||
|
<https://tox.readthedocs.io/en/latest/>`__ for environment setup, and
|
||||||
|
`pytest-asyncio <https://pypi.org/project/pytest-asyncio/>`__ and `pytest-cov
|
||||||
|
<https://pytest-cov.readthedocs.io/en/latest/>`__ for asyncio and
|
||||||
|
`coverage <https://coverage.readthedocs.io/>`__ integration.
|
||||||
|
|
||||||
|
While reading the full documentation for these is probably a good idea, there
|
||||||
|
is a lot to read, so a brief summary of these tools is provided below for
|
||||||
|
convienience.
|
||||||
|
|
||||||
|
Brief Introduction to Pytest
|
||||||
|
============================
|
||||||
|
|
||||||
|
`Pytest <https://pytest.org/>`__ is a tool for discovering and running python
|
||||||
|
tests, as well as allowing modular reuse of test setup code using fixtures.
|
||||||
|
|
||||||
|
Most Pytest tests will look something like this::
|
||||||
|
|
||||||
|
from module import my_thing, my_other_thing
|
||||||
|
|
||||||
|
def test_my_thing(fixture):
|
||||||
|
assert my_thing(fixture) == 42
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_my_thing(event_loop):
|
||||||
|
assert await my_other_thing(loop=event_loop) == 42
|
||||||
|
|
||||||
|
Note here:
|
||||||
|
|
||||||
|
1. The test imports one specific function. The role of unit tests is to test
|
||||||
|
that the implementation of some unit, like a function or class, works.
|
||||||
|
It's role is not so much to test that components interact well with each
|
||||||
|
other. I/O, such as connecting to remote servers, should be avoided. This
|
||||||
|
helps with quickly identifying the source of an error, finding silent
|
||||||
|
breakage, and makes it easier to cover all possible code paths.
|
||||||
|
|
||||||
|
System or integration tests can also be useful, but are currently out of
|
||||||
|
scope of Telethon's automated testing.
|
||||||
|
|
||||||
|
2. A function ``test_my_thing`` is declared. Pytest searches for files
|
||||||
|
starting with ``test_``, classes starting with ``Test`` and executes any
|
||||||
|
functions or methods starting with ``test_`` it finds.
|
||||||
|
|
||||||
|
3. The function is declared with a parameter ``fixture``. Fixtures are used to
|
||||||
|
request things required to run the test, such as temporary directories,
|
||||||
|
free TCP ports, Connections, etc. Fixtures are declared by simply adding
|
||||||
|
the fixture name as parameter. A full list of available fixtures can be
|
||||||
|
found with the ``pytest --fixtures`` command.
|
||||||
|
|
||||||
|
4. The test uses a simple ``assert`` to test some condition is valid. Pytest
|
||||||
|
uses some magic to ensure that the errors from this are readable and easy
|
||||||
|
to debug.
|
||||||
|
|
||||||
|
5. The ``pytest.mark.asyncio`` fixture is provided by ``pytest-asyncio``. It
|
||||||
|
starts a loop and executes a test function as coroutine. This should be
|
||||||
|
used for testing asyncio code. It also declares the ``event_loop``
|
||||||
|
fixture, which will request an ``asyncio`` event loop.
|
||||||
|
|
||||||
|
Brief Introduction to Tox
|
||||||
|
=========================
|
||||||
|
|
||||||
|
`Tox <https://tox.readthedocs.io/en/latest/>`__ is a tool for automated setup
|
||||||
|
of virtual environments for testing. While the tests can be run directly by
|
||||||
|
just running ``pytest``, this only tests one specific python version in your
|
||||||
|
existing environment, which will not catch e.g. undeclared dependencies, or
|
||||||
|
version incompatabilities.
|
||||||
|
|
||||||
|
Tox environments are declared in the ``tox.ini`` file. The default
|
||||||
|
environments, declared at the top, can be simply run with ``tox``. The option
|
||||||
|
``tox -e py36,flake`` can be used to request specific environments to be run.
|
||||||
|
|
||||||
|
Brief Introduction to Pytest-cov
|
||||||
|
================================
|
||||||
|
|
||||||
|
Coverage is a useful metric for testing. It measures the lines of code and
|
||||||
|
branches that are exercised by the tests. The higher the coverage, the more
|
||||||
|
likely it is that any coding errors will be caught by the tests.
|
||||||
|
|
||||||
|
A brief coverage report can be generated with the ``--cov`` option to ``tox``,
|
||||||
|
which will be passed on to ``pytest``. Additionally, the very useful HTML
|
||||||
|
report can be generated with ``--cov --cov-report=html``, which contains a
|
||||||
|
browsable copy of the source code, annotated with coverage information for each
|
||||||
|
line.
|
@ -93,6 +93,7 @@ You can also use the menu on the left to quickly skip over sections.
|
|||||||
developing/test-servers.rst
|
developing/test-servers.rst
|
||||||
developing/project-structure.rst
|
developing/project-structure.rst
|
||||||
developing/coding-style.rst
|
developing/coding-style.rst
|
||||||
|
developing/testing.rst
|
||||||
developing/understanding-the-type-language.rst
|
developing/understanding-the-type-language.rst
|
||||||
developing/tips-for-porting-the-project.rst
|
developing/tips-for-porting-the-project.rst
|
||||||
developing/telegram-api-in-other-languages.rst
|
developing/telegram-api-in-other-languages.rst
|
||||||
|
@ -662,7 +662,7 @@ class TelegramBaseClient(abc.ABC):
|
|||||||
self._exported_sessions[cdn_redirect.dc_id] = session
|
self._exported_sessions[cdn_redirect.dc_id] = session
|
||||||
|
|
||||||
self._log[__name__].info('Creating new CDN client')
|
self._log[__name__].info('Creating new CDN client')
|
||||||
client = TelegramBareClient(
|
client = TelegramBaseClient(
|
||||||
session, self.api_id, self.api_hash,
|
session, self.api_id, self.api_hash,
|
||||||
proxy=self._sender.connection.conn.proxy,
|
proxy=self._sender.connection.conn.proxy,
|
||||||
timeout=self._sender.connection.get_timeout()
|
timeout=self._sender.connection.get_timeout()
|
||||||
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
0
tests/telethon/__init__.py
Normal file
0
tests/telethon/__init__.py
Normal file
37
tests/telethon/crypto/test_rsa.py
Normal file
37
tests/telethon/crypto/test_rsa.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
"""
|
||||||
|
tests for telethon.crypto.rsa
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from telethon.crypto import rsa
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def server_key_fp():
|
||||||
|
"""factory to return a key, old if so chosen"""
|
||||||
|
def _server_key_fp(old: bool):
|
||||||
|
for fp, data in rsa._server_keys.items():
|
||||||
|
_, old_key = data
|
||||||
|
if old_key == old:
|
||||||
|
return fp
|
||||||
|
|
||||||
|
return _server_key_fp
|
||||||
|
|
||||||
|
def test_encryption_inv_key():
|
||||||
|
"""test for #1324"""
|
||||||
|
assert rsa.encrypt("invalid", b"testdata") is None
|
||||||
|
|
||||||
|
def test_encryption_old_key(server_key_fp):
|
||||||
|
"""test for #1324"""
|
||||||
|
assert rsa.encrypt(server_key_fp(old=True), b"testdata") is None
|
||||||
|
|
||||||
|
def test_encryption_allowed_old_key(server_key_fp):
|
||||||
|
data = rsa.encrypt(server_key_fp(old=True), b"testdata", use_old=True)
|
||||||
|
# we can't verify the data is actually valid because we don't have
|
||||||
|
# the decryption keys
|
||||||
|
assert data is not None and len(data) == 256
|
||||||
|
|
||||||
|
def test_encryption_current_key(server_key_fp):
|
||||||
|
data = rsa.encrypt(server_key_fp(old=False), b"testdata")
|
||||||
|
# we can't verify the data is actually valid because we don't have
|
||||||
|
# the decryption keys
|
||||||
|
assert data is not None and len(data) == 256
|
59
tests/telethon/test_helpers.py
Normal file
59
tests/telethon/test_helpers.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
"""
|
||||||
|
tests for telethon.helpers
|
||||||
|
"""
|
||||||
|
|
||||||
|
from base64 import b64decode
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from telethon import helpers
|
||||||
|
|
||||||
|
|
||||||
|
def test_strip_text():
|
||||||
|
assert helpers.strip_text(" text ", []) == "text"
|
||||||
|
# I can't interpret the rest of the code well enough yet
|
||||||
|
|
||||||
|
|
||||||
|
class TestSyncifyAsyncContext:
|
||||||
|
class NoopContextManager:
|
||||||
|
def __init__(self, loop):
|
||||||
|
self.count = 0
|
||||||
|
self.loop = loop
|
||||||
|
|
||||||
|
async def __aenter__(self):
|
||||||
|
self.count += 1
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def __aexit__(self, exc_type, *args):
|
||||||
|
assert exc_type is None
|
||||||
|
self.count -= 1
|
||||||
|
|
||||||
|
__enter__ = helpers._sync_enter
|
||||||
|
__exit__ = helpers._sync_exit
|
||||||
|
|
||||||
|
def test_sync_acontext(self, event_loop):
|
||||||
|
contm = self.NoopContextManager(event_loop)
|
||||||
|
assert contm.count == 0
|
||||||
|
|
||||||
|
with contm:
|
||||||
|
assert contm.count == 1
|
||||||
|
|
||||||
|
assert contm.count == 0
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_async_acontext(self, event_loop):
|
||||||
|
contm = self.NoopContextManager(event_loop)
|
||||||
|
assert contm.count == 0
|
||||||
|
|
||||||
|
async with contm:
|
||||||
|
assert contm.count == 1
|
||||||
|
|
||||||
|
assert contm.count == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_key_data_from_nonce():
|
||||||
|
gkdfn = helpers.generate_key_data_from_nonce
|
||||||
|
|
||||||
|
key_expect = b64decode(b'NFwRFB8Knw/kAmvPWjtrQauWysHClVfQh0UOAaABqZA=')
|
||||||
|
nonce_expect = b64decode(b'1AgjhU9eDvJRjFik73bjR2zZEATzL/jLu9yodYfWEgA=')
|
||||||
|
assert gkdfn(123456789, 1234567) == (key_expect, nonce_expect)
|
24
tox.ini
Normal file
24
tox.ini
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py35,py36,py37,py38
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
deps =
|
||||||
|
-rrequirements.txt
|
||||||
|
-roptional-requirements.txt
|
||||||
|
-rdev-requirements.txt
|
||||||
|
commands =
|
||||||
|
# NOTE: you can run any command line tool here - not just tests
|
||||||
|
pytest {posargs}
|
||||||
|
|
||||||
|
# run with tox -e flake
|
||||||
|
[testenv:flake]
|
||||||
|
deps =
|
||||||
|
-rrequirements.txt
|
||||||
|
-roptional-requirements.txt
|
||||||
|
-rdev-requirements.txt
|
||||||
|
flake8
|
||||||
|
commands =
|
||||||
|
# stop the build if there are Python syntax errors or undefined names
|
||||||
|
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||||
|
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||||
|
flake8 . --count --exit-zero --exclude telethon/tl/,telethon/errors/rpcerrorlist.py --max-complexity=10 --max-line-length=127 --statistics
|
Loading…
Reference in New Issue
Block a user