Skip to content

Commit

Permalink
added first test need to clean it up tho
Browse files Browse the repository at this point in the history
  • Loading branch information
Darkflame72 committed Oct 4, 2020
1 parent 74ede1a commit deb6f1e
Show file tree
Hide file tree
Showing 8 changed files with 406 additions and 5 deletions.
6 changes: 5 additions & 1 deletion mcsrvstats/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Main functions for mcsrvstats."""
from typing import Optional

import aiohttp
from bs4 import BeautifulSoup
Expand All @@ -9,8 +10,11 @@
class Client:
"""Client class."""

def __init__(self) -> None:
def __init__(self, session: Optional[aiohttp.ClientSession] = None) -> None:
"""Initialises class and creates aiohttp session."""
if session:
self.session = session
return
self.session = aiohttp.ClientSession()

async def close(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[mypy]

[mypy-aiohttp.*,nox.*,bs4.*]
[mypy-aiohttp.*,nox.*,bs4.*,pytest.*]
ignore_missing_imports = True
7 changes: 6 additions & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,12 @@ def tests(session: Session) -> None:
args = session.posargs or ["--cov", "-m", "not e2e"]
session.run("poetry", "install", "--no-dev", external=True)
install_with_constraints(
session, "coverage[toml]", "pytest", "pytest-cov", "pytest-mock"
session,
"coverage[toml]",
"pytest",
"pytest-cov",
"pytest-mock",
"pytest-asyncio",
)
session.run("pytest", *args)

Expand Down
124 changes: 123 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ python = "^3.7"
black = "^20.8b1"
codecov = "^2.1.9"
coverage = {extras = ["toml"], version = "^5.3"}
cryptography = "^3.1.1"
darglint = "^1.5.4"
flake8 = "^3.8.3"
flake8-annotations = "^2.4.0"
Expand All @@ -37,6 +38,7 @@ flake8-docstrings = "^1.5.0"
flake8-import-order = "^0.18.1"
mypy = "^0.782"
pytest = "^5.0"
pytest-asyncio = "^0.14.0"
pytest-cov = "^2.10.1"
pytest-mock = "^3.3.1"
pytype = {version = "^2020.9.29", python = "3.8"}
Expand All @@ -63,6 +65,7 @@ exclude = '''
include = '\.pyi?$'
line-length = 88
target-version = ['py36', 'py37', 'py38']

[tool.coverage.paths]
source = ["src", "*/site-packages"]

Expand All @@ -73,6 +76,7 @@ source = ["mcsrvstats"]
[tool.coverage.report]
show_missing = true
#fail_under = 100

[build-system]
build-backend = "poetry.masonry.api"
requires = ["poetry>=0.12"]
Expand Down
108 changes: 108 additions & 0 deletions tests/aiohttp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import aiohttp
import aiohttp.test_utils
import aiohttp.web
import asyncio
import collections
import pytest
import socket

# ----------------------------------------------------------------------------

_RedirectContext = collections.namedtuple("RedirectContext", "add_server session")


@pytest.fixture
async def http_redirect(ssl_certificate):
""" An HTTP ClientSession fixture that redirects requests to local test servers """
resolver = FakeResolver()
connector = aiohttp.TCPConnector(
resolver=resolver,
ssl=ssl_certificate.client_context(),
use_dns_cache=False,
)
async with aiohttp.ClientSession(connector=connector) as session:
yield _RedirectContext(add_server=resolver.add, session=session)


class FakeResolver:
"""aiohttp resolver that hijacks a set of uris
:param servers: a mapping of remote host:port to redirect to local servers.
:type servers: dict(tuple(str, int), int)
"""

__slots__ = ("_servers",)

def __init__(self, servers=None):
self._servers = servers or {}

def add(self, host, port, target):
""" Add an entry to the resolver """
self._servers[host, port] = target

async def resolve(self, host, port=0, family=socket.AF_INET):
""" Resolve a host:port pair into a connectable address """
try:
fake_port = self._servers[host, port]
except KeyError:
raise OSError("Fake DNS lookup failed: no fake server known for %s" % host)
return [
{
"hostname": host,
"host": "127.0.0.1",
"port": fake_port,
"family": socket.AF_INET,
"proto": 0,
"flags": socket.AI_NUMERICHOST,
}
]


# ----------------------------------------------------------------------------


class CaseControlledTestServer(aiohttp.test_utils.RawTestServer):
""" Test server that relies on test case to supply responses and control timing """

def __init__(self, *, ssl=None, **kwargs):
super().__init__(self._handle_request, **kwargs)
self._ssl = ssl
self._requests = asyncio.Queue()
self._responses = {}

async def start_server(self, **kwargs):
kwargs.setdefault("ssl", self._ssl)
await super().start_server(**kwargs)

async def close(self):
for future in self._responses.values():
future.cancel()
await super().close()

async def _handle_request(self, request):
self._responses[id(request)] = response = asyncio.Future()
self._requests.put_nowait(request)
try:
return await response
finally:
del self._responses[id(request)]

@property
def awaiting_request_count(self):
return self._requests.qsize()

async def receive_request(self, *, timeout=None):
"""Wait until the test server receives a request
:param float timeout: Bail out after that many seconds.
:return: received request, not yet serviced.
:rtype: aiohttp.web.BaseRequest
:see: :meth:`send_response`
"""
return await asyncio.wait_for(self._requests.get(), timeout=timeout)

def send_response(self, request, *args, **kwargs):
"""Reply to a received request.
:param request: the request to respond to.
:param args: forwarded to :class:`aiohttp.web.Response`.
:param kwargs: forwarded to :class:`aiohttp.web.Response`.
"""
self._responses[id(request)].set_result(aiohttp.web.Response(*args, **kwargs))

0 comments on commit deb6f1e

Please sign in to comment.