Skip to content

Commit

Permalink
Add support for Sanic 21+
Browse files Browse the repository at this point in the history
  • Loading branch information
relud committed Aug 17, 2022
1 parent e316f0c commit 98effe6
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 36 deletions.
7 changes: 6 additions & 1 deletion src/dockerflow/sanic/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,17 @@ async def check_redis_connected(redis):
"""
import aioredis

if aioredis.__version__.startswith("1."):
RedisConnectionError = aioredis.ConnectionClosedError
else:
RedisConnectionError = aioredis.ConnectionError

errors = []

try:
with await redis.conn as r:
result = await r.ping()
except aioredis.ConnectionClosedError as e:
except RedisConnectionError as e:
msg = "Could not connect to redis: {!s}".format(e)
errors.append(Error(msg, id=health.ERROR_CANNOT_CONNECT_REDIS))
except aioredis.RedisError as e:
Expand Down
4 changes: 3 additions & 1 deletion tests/constraints/sanic-20.txt
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
Sanic<21
Sanic>=20,<21
aioredis<2
sanic_redis<0.3.0
1 change: 1 addition & 0 deletions tests/constraints/sanic-21.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Sanic>=21,<22
1 change: 1 addition & 0 deletions tests/constraints/sanic-22.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Sanic>=22,<23
7 changes: 7 additions & 0 deletions tests/requirements/sanic-20.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# these are constrained by the files in tests/constraints/*.txt
# to support a triple stack Django/Flask/Sanic
aiohttp
aioredis
Sanic
sanic_redis
uvloop>=0.14.0rc1
5 changes: 3 additions & 2 deletions tests/requirements/sanic.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# these are constrained by the files in tests/constraints/*.txt
# to support a triple stack Django/Flask/Sanic
aiohttp
aioredis<2.0.0
aioredis
Sanic
sanic_redis<0.3.0
sanic_redis
sanic-testing
uvloop>=0.14.0rc1
72 changes: 43 additions & 29 deletions tests/sanic/test_sanic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,26 @@
# file, you can obtain one at http://mozilla.org/MPL/2.0/.
import functools
import logging
import socket
import uuid

import aioredis
import pytest
import sanic.testing
import sanic
import sanic_redis.core
from sanic import Sanic, response
from sanic_redis import SanicRedis

from dockerflow import health
from dockerflow.sanic import Dockerflow, checks

if sanic.__version__.startswith("20."):
from sanic.testing import SanicTestClient
else:
from sanic_testing.testing import SanicTestClient


class FakeRedis:
def __init__(self, error=None, **kw):
def __init__(self, *args, error=None, **kw):
self.error = error

def __await__(self):
Expand All @@ -30,15 +35,19 @@ def __enter__(self):
def __exit__(self, *exc_info):
pass

def close(self):
async def close(self):
pass

async def wait_closed(self):
pass

async def ping(self):
if self.error == "connection":
raise aioredis.ConnectionClosedError("fake")
if aioredis.__version__.startswith("1."):
RedisConnectionError = aioredis.ConnectionClosedError
else:
RedisConnectionError = aioredis.ConnectionError
raise RedisConnectionError("fake")
elif self.error == "redis":
raise aioredis.RedisError("fake")
elif self.error == "malformed":
Expand All @@ -47,13 +56,20 @@ async def ping(self):
return b"PONG"


async def fake_redis(**kw):
return FakeRedis(**kw)
class FakeRedis1(FakeRedis):
def close(self):
pass


async def fake_redis(*args, **kw):
if aioredis.__version__.startswith("1."):
return FakeRedis1(*args, **kw)
return FakeRedis(*args, **kw)


@pytest.fixture(scope="function")
def app():
app = Sanic("dockerflow")
app = Sanic(f"dockerflow-{uuid.uuid4().hex}")

@app.route("/")
async def root(request):
Expand All @@ -77,28 +93,20 @@ def dockerflow_redis(app):

@pytest.fixture
def test_client(app):
# Create SanicTestClient manually and provide a socket object instead of host
# and port when calling Sanic.run in order to avoid parallel test failures
# caused by Sanic.test_client bindngs to a static port
s = socket.socket()
s.bind((sanic.testing.HOST, 0))
try:
# initialize test_client with socket's port
test_client = sanic.testing.SanicTestClient(app, s.getsockname()[1])
# override app.run to drop host and port in favor of socket
run = app.run
app.run = lambda host, port, **kw: run(sock=s, **kw)
# yield test_client
yield test_client
finally:
s.close()
return SanicTestClient(app)


def test_instantiating(app):
dockerflow = Dockerflow()
assert "dockerflow.heartbeat" not in app.router.routes_names
dockerflow.init_app(app)
assert "dockerflow.heartbeat" in app.router.routes_names
Dockerflow()
if sanic.__version__.startswith("20."):
assert "dockerflow.heartbeat" not in app.router.routes_names
else:
assert ("__heartbeat__",) not in app.router.routes_all
Dockerflow(app)
if sanic.__version__.startswith("20."):
assert "dockerflow.heartbeat" in app.router.routes_names
else:
assert ("__heartbeat__",) in app.router.routes_all


def test_version_exists(dockerflow, mocker, test_client, version_content):
Expand Down Expand Up @@ -178,7 +186,10 @@ async def warning_check2():

def test_redis_check(dockerflow_redis, mocker, test_client):
assert "check_redis_connected" in dockerflow_redis.checks
mocker.patch.object(sanic_redis.core, "create_redis_pool", fake_redis)
if aioredis.__version__.startswith("1."):
mocker.patch.object(sanic_redis.core, "create_redis_pool", fake_redis)
else:
mocker.patch.object(sanic_redis.core, "from_url", fake_redis)
_, response = test_client.get("/__heartbeat__")
assert response.status == 200
assert response.json["status"] == "ok"
Expand All @@ -198,7 +209,10 @@ def test_redis_check(dockerflow_redis, mocker, test_client):
def test_redis_check_error(dockerflow_redis, mocker, test_client, error, messages):
assert "check_redis_connected" in dockerflow_redis.checks
fake_redis_error = functools.partial(fake_redis, error=error)
mocker.patch.object(sanic_redis.core, "create_redis_pool", fake_redis_error)
if aioredis.__version__.startswith("1."):
mocker.patch.object(sanic_redis.core, "create_redis_pool", fake_redis_error)
else:
mocker.patch.object(sanic_redis.core, "from_url", fake_redis_error)
_, response = test_client.get("/__heartbeat__")
assert response.status == 500
assert response.json["status"] == "error"
Expand Down
10 changes: 7 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ envlist =
py{37,38,39,310}-dj32
py{38,39,310}-dj{40}
py{37,38,39,310}-fl{012,10,11,20,21}
py{37,38,39}-s{20}
py{37,38,39}-s20
py{37,38,39,310}-s{21,22}

[gh-actions]
python =
Expand All @@ -26,7 +27,8 @@ deps =
-rtests/requirements/default.txt
dj{32,40}: -rtests/requirements/django.txt
fl{012,10,11,20,21}: -rtests/requirements/flask.txt
s{20}: -rtests/requirements/sanic.txt
s20: -rtests/requirements/sanic-20.txt
s{21,22}: -rtests/requirements/sanic.txt
dj32: -ctests/constraints/django-3.2.txt
dj40: -ctests/constraints/django-4.0.txt
fl012: -ctests/constraints/flask-0.12.txt
Expand All @@ -35,11 +37,13 @@ deps =
fl20: -ctests/constraints/flask-2.0.txt
fl21: -ctests/constraints/flask-2.0.txt
s20: -ctests/constraints/sanic-20.txt
s21: -ctests/constraints/sanic-21.txt
s22: -ctests/constraints/sanic-22.txt
commands =
python --version
dj{32,40}: pytest tests/core/ tests/django --nomigrations {posargs:}
fl{012,10,11,20,21}: pytest tests/core/ tests/flask/ {posargs:}
s{20}: pytest tests/core/ tests/sanic/ {posargs:}
s{20,21,22}: pytest tests/core/ tests/sanic/ {posargs:}

[testenv:py38-docs]
basepython = python3.8
Expand Down

0 comments on commit 98effe6

Please sign in to comment.