Skip to content

Commit

Permalink
Edit tests with new library constraints in mind
Browse files Browse the repository at this point in the history
  • Loading branch information
grahamalama committed Aug 1, 2023
1 parent e562030 commit 804a6e0
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 98 deletions.
22 changes: 2 additions & 20 deletions src/dockerflow/django/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,10 @@
import time
import uuid

from django import VERSION
from django.utils.deprecation import MiddlewareMixin

from . import views

try:
from django.utils.deprecation import MiddlewareMixin
except ImportError: # pragma: no cover
MiddlewareMixin = object


# Computed once, reused in every request
_less_than_django_1_10 = VERSION < (1, 10)


def is_authenticated(user): # pragma: no cover
"""Check if the user is authenticated but do it in a way that
it doesnt' cause a DeprecationWarning in Django >=1.10"""
if _less_than_django_1_10:
# Prior to Django 1.10, user.is_authenticated was a method
return user.is_authenticated()
return user.is_authenticated


class DockerflowMiddleware(MiddlewareMixin):
"""
Expand Down Expand Up @@ -66,7 +48,7 @@ def _build_extra_meta(self, request):
# modified earlier, so be sure to check for existence of these
# attributes before trying to use them.
if hasattr(request, "user"):
out["uid"] = is_authenticated(request.user) and request.user.pk or ""
out["uid"] = request.user.is_authenticated and request.user.pk or ""
if hasattr(request, "_id"):
out["rid"] = request._id
if hasattr(request, "_start_timestamp"):
Expand Down
4 changes: 3 additions & 1 deletion src/dockerflow/flask/checks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"""
This module contains a few built-in checks for the Flask integration.
"""
from sqlalchemy import text

from ... import health
from ...checks import ( # noqa
CRITICAL,
Expand Down Expand Up @@ -47,7 +49,7 @@ def check_database_connected(db):
errors = []
try:
with db.engine.connect() as connection:
connection.execute("SELECT 1;")
connection.execute(text("SELECT 1;"))
except DBAPIError as e:
msg = "DB-API error: {!s}".format(e)
errors.append(Error(msg, id=health.ERROR_DB_API_EXCEPTION))
Expand Down
6 changes: 2 additions & 4 deletions src/dockerflow/sanic/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,8 @@ async def check_redis_connected(redis):
"""
import aioredis

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

RedisConnectionError = aioredis.ConnectionError

errors = []

Expand Down
6 changes: 2 additions & 4 deletions tests/django/test_django.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@
from dockerflow.django import checks
from dockerflow.django.middleware import DockerflowMiddleware

try:
from django.utils.deprecation import MiddlewareMixin
except ImportError: # pragma: no cover
MiddlewareMixin = object

from django.utils.deprecation import MiddlewareMixin


@pytest.fixture
Expand Down
133 changes: 64 additions & 69 deletions tests/flask/test_flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,18 @@ def load_user(user_id):
return MockUser(user_id)


def create_app():
@pytest.fixture
def app():
app = Flask("dockerflow")
app.secret_key = "super sekrit"
login_manager = LoginManager(app)
login_manager.user_loader(load_user)
return app


@pytest.fixture
def app():
return create_app()
@pytest.fixture()
def client(app):
return app.test_client()


@pytest.fixture
Expand Down Expand Up @@ -72,28 +73,23 @@ def test_instantiating(app):
assert "dockerflow.heartbeat" in app.view_functions


def test_version_exists(dockerflow, mocker, app, version_content):
def test_version_exists(dockerflow, mocker, version_content, client):
mocker.patch.object(dockerflow, "_version_callback", return_value=version_content)
response = app.test_client().get("/__version__")
response = client.get("/__version__")
assert response.status_code == 200
assert json.loads(response.data.decode()) == version_content


def test_version_path(mocker, version_content):
app = Flask("dockerflow")
app.secret_key = "super sekrit"
login_manager = LoginManager(app)
login_manager.user_loader(load_user)
def test_version_path(mocker, app, client, version_content):
custom_version_path = "/something/extra/ordinary"
dockerflow = Dockerflow(app, version_path=custom_version_path)
version_callback = mocker.patch.object(
dockerflow, "_version_callback", return_value=version_content
)
with app.test_client() as test_client:
response = test_client.get("/__version__")
assert response.status_code == 200
assert json.loads(response.data.decode()) == version_content
version_callback.assert_called_with(custom_version_path)
response = client.get("/__version__")
assert response.status_code == 200
assert json.loads(response.data.decode()) == version_content
version_callback.assert_called_with(custom_version_path)


def test_version_missing(dockerflow, mocker, app):
Expand Down Expand Up @@ -144,10 +140,11 @@ def warning_check2():


def test_lbheartbeat_makes_no_db_queries(dockerflow, app):
assert len(get_debug_queries()) == 0
response = app.test_client().get("/__lbheartbeat__")
assert response.status_code == 200
assert len(get_debug_queries()) == 0
with app.app_context():
assert len(get_debug_queries()) == 0
response = app.test_client().get("/__lbheartbeat__")
assert response.status_code == 200
assert len(get_debug_queries()) == 0


def test_full_redis_check(mocker):
Expand Down Expand Up @@ -177,37 +174,26 @@ def test_full_redis_check_error(mocker):
assert json.loads(response.data.decode())["status"] == "error"


def test_full_db_check(mocker):
app = Flask("db-check")
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
def test_full_db_check(mocker, app, db, client):
dockerflow = Dockerflow(app, db=db)
assert "check_database_connected" in dockerflow.checks

response = app.test_client().get("/__heartbeat__")
response = client.get("/__heartbeat__")
assert response.status_code == 200
assert json.loads(response.data.decode())["status"] == "ok"


def test_full_db_check_error(mocker):
app = Flask("db-check")
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)

engine_connect = mocker.patch.object(db.engine, "connect")
engine_connect.side_effect = SQLAlchemyError
dockerflow = Dockerflow(app, db=db)
assert "check_database_connected" in dockerflow.checks

with app.test_client() as test_client:
response = test_client.get("/__heartbeat__")
def test_full_db_check_error(mocker, app, db, client):
with app.app_context():
mocker.patch.object(db.engine, "connect", side_effect=SQLAlchemyError)
dockerflow = Dockerflow(app, db=db)
assert "check_database_connected" in dockerflow.checks
response = client.get("/__heartbeat__")
assert response.status_code == 500
assert json.loads(response.data.decode())["status"] == "error"


def assert_log_record(request, record, errno=0, level=logging.INFO):
def assert_log_record(record, errno=0, level=logging.INFO):
assert record.levelno == level
assert record.errno == errno
assert record.agent == "dockerflow/tests"
Expand All @@ -221,17 +207,18 @@ def assert_log_record(request, record, errno=0, level=logging.INFO):
headers = {"User-Agent": "dockerflow/tests", "Accept-Language": "tlh"}


def test_request_summary(caplog, dockerflow, app):
with app.test_client() as test_client:
test_client.get("/", headers=headers)
def test_request_summary(caplog, app, dockerflow, client):
caplog.set_level(logging.INFO)
with app.test_request_context("/"):
client.get("/", headers=headers)
assert getattr(g, "_request_id") is not None
assert getattr(g, "request_id") is not None
assert isinstance(getattr(g, "_start_timestamp"), float)

assert len(caplog.records) == 1
for record in caplog.records:
assert_log_record(request, record)
assert getattr(request, "uid", None) is None
record = caplog.records[0]
assert_log_record(record)
assert getattr(request, "uid", None) is None


def test_preserves_existing_request_id(dockerflow, app):
Expand All @@ -256,17 +243,19 @@ def assert_user(app, caplog, user, callback):
response = Response("")
response = app.process_response(response)
assert len(caplog.records) == 1
for record in caplog.records:
assert_log_record(request, record)
assert record.uid == callback(user)
record = caplog.records[0]
assert_log_record(record)
assert record.uid == callback(user)


def test_request_summary_user_success(caplog, dockerflow, mocker, app):
def test_request_summary_user_success(caplog, dockerflow, app):
caplog.set_level(logging.INFO)
user = MockUser(100)
assert_user(app, caplog, user, lambda user: user.get_id())


def test_request_summary_user_is_authenticated_missing(caplog, dockerflow, app):
caplog.set_level(logging.INFO)
class MissingIsAuthenticatedUser(object):
id = 0
is_active = True
Expand All @@ -278,6 +267,7 @@ def get_id(self):


def test_request_summary_user_is_authenticated_callable(caplog, dockerflow, app):
caplog.set_level(logging.INFO)
class CallableIsAuthenticatedUser(object):
id = 0
is_active = True
Expand All @@ -292,6 +282,7 @@ def is_authenticated(self):


def test_request_summary_user_flask_login_missing(caplog, dockerflow, app, monkeypatch):
caplog.set_level(logging.INFO)
monkeypatch.setattr("dockerflow.flask.app.has_flask_login", False)
user = MockUser(100)
assert_user(app, caplog, user, lambda user: "")
Expand All @@ -314,6 +305,7 @@ def test_request_summary_exception(caplog, app):


def test_request_summary_failed_request(caplog, dockerflow, app):
caplog.set_level(logging.INFO)
@app.before_request
def hostile_callback():
# simulating resetting request changes
Expand All @@ -327,25 +319,26 @@ def hostile_callback():
assert getattr(record, "t", None) is None


def test_db_check_sqlalchemy_error(mocker, db):
engine_connect = mocker.patch.object(db.engine, "connect")
engine_connect.side_effect = SQLAlchemyError
errors = checks.check_database_connected(db)
def test_db_check_sqlalchemy_error(app, mocker, db):
with app.app_context():
mocker.patch.object(db.engine, "connect", side_effect=SQLAlchemyError)
errors = checks.check_database_connected(db)
assert len(errors) == 1
assert errors[0].id == health.ERROR_SQLALCHEMY_EXCEPTION


def test_db_check_dbapi_error(mocker, db):
exception = DBAPIError.instance("", [], Exception(), Exception)
engine_connect = mocker.patch.object(db.engine, "connect")
engine_connect.side_effect = exception
errors = checks.check_database_connected(db)
def test_db_check_dbapi_error(app, mocker, db):
with app.app_context():
exception = DBAPIError.instance("", [], Exception(), Exception)
mocker.patch.object(db.engine, "connect", side_effect=exception)
errors = checks.check_database_connected(db)
assert len(errors) == 1
assert errors[0].id == health.ERROR_DB_API_EXCEPTION


def test_db_check_success(db):
errors = checks.check_database_connected(db)
def test_db_check_success(app, db):
with app.app_context():
errors = checks.check_database_connected(db)
assert errors == []


Expand Down Expand Up @@ -374,38 +367,40 @@ def test_check_message():
[SQLAlchemyError(), DBAPIError.instance("", [], Exception(), Exception)],
)
def test_check_migrations_applied_cannot_check_migrations(
exception, mocker, db, migrate
exception, mocker, app, db, migrate
):
engine_connect = mocker.patch.object(db.engine, "connect")
engine_connect.side_effect = exception
errors = checks.check_migrations_applied(migrate)
with app.app_context():
mocker.patch.object(db.engine, "connect", side_effect=exception)
errors = checks.check_migrations_applied(migrate)
assert len(errors) == 1
assert errors[0].id == health.INFO_CANT_CHECK_MIGRATIONS


def test_check_migrations_applied_success(mocker, db, migrate):
def test_check_migrations_applied_success(mocker, app, db, migrate):
get_heads = mocker.patch(
"alembic.script.ScriptDirectory.get_heads", return_value=("17164a7d1c2e",)
)
get_current_heads = mocker.patch(
"alembic.migration.MigrationContext.get_current_heads",
return_value=("17164a7d1c2e",),
)
errors = checks.check_migrations_applied(migrate)
with app.app_context():
errors = checks.check_migrations_applied(migrate)
assert get_heads.called
assert get_current_heads.called
assert len(errors) == 0


def test_check_migrations_applied_unapplied_migrations(mocker, db, migrate):
def test_check_migrations_applied_unapplied_migrations(mocker, app, db, migrate):
get_heads = mocker.patch(
"alembic.script.ScriptDirectory.get_heads", return_value=("7f447c94347a",)
)
get_current_heads = mocker.patch(
"alembic.migration.MigrationContext.get_current_heads",
return_value=("73d96d3120ff",),
)
errors = checks.check_migrations_applied(migrate)
with app.app_context():
errors = checks.check_migrations_applied(migrate)
assert get_heads.called
assert get_current_heads.called
assert len(errors) == 1
Expand Down

0 comments on commit 804a6e0

Please sign in to comment.