Skip to content

Commit

Permalink
Add mail check
Browse files Browse the repository at this point in the history
  • Loading branch information
TheSuperiorStanislav committed Sep 18, 2024
1 parent b0e2c4c commit 3d8bf8d
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 0 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The following health checks are bundled with this project:
- Celery ping
- RabbitMQ
- Migrations
- Mail

Writing your own custom health checks is also very quick and easy.

Expand Down Expand Up @@ -74,6 +75,7 @@ Add the `health_check` applications to your `INSTALLED_APPS`:
'health_check.contrib.s3boto3_storage', # requires boto3 and S3BotoStorage backend
'health_check.contrib.rabbitmq', # requires RabbitMQ broker
'health_check.contrib.redis', # requires Redis broker
'health_check.contrib.mail',
]
```

Expand All @@ -90,6 +92,15 @@ one of these checks, set its value to `None`.
}
```

(Optional) If using the `mail` app, you can configure timeout
threshold settings; otherwise below defaults are assumed.

```python
HEALTH_CHECK = {
'MAIL_TIMEOUT': 15, # seconds
}
```

To use Health Check Subsets, Specify a subset name and associate it with the relevant health check services to utilize Health Check Subsets.
```python
HEALTH_CHECK = {
Expand Down
4 changes: 4 additions & 0 deletions health_check/contrib/mail/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import django

if django.VERSION < (3, 2):
default_app_config = "health_check.contrib.mail.apps.HealthCheckConfig"
12 changes: 12 additions & 0 deletions health_check/contrib/mail/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.apps import AppConfig

from health_check.plugins import plugin_dir


class HealthCheckConfig(AppConfig):
name = "health_check.contrib.mail"

def ready(self):
from .backends import MailHealthCheck

plugin_dir.register(MailHealthCheck)
28 changes: 28 additions & 0 deletions health_check/contrib/mail/backends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import logging

from django.core.mail import get_connection

from health_check.backends import BaseHealthCheckBackend
from health_check.conf import HEALTH_CHECK
from health_check.exceptions import ServiceUnavailable

logger = logging.getLogger(__name__)


class MailHealthCheck(BaseHealthCheckBackend):
"""Check that mail backend is working."""

def check_status(self) -> None:
"""Open and close connection email server."""
try:
connection = get_connection(fail_silently=False)
connection.timeout = HEALTH_CHECK.get("MAIL_TIMEOUT", 15)
logger.debug("Trying to open connection to mail backend.")
connection.open()
connection.close()
logger.debug("Connection established. Mail backend is healthy.")
except Exception as error:
self.add_error(
error=ServiceUnavailable(error),
cause=error,
)
44 changes: 44 additions & 0 deletions tests/test_mail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from unittest import mock

from health_check.contrib.mail.backends import MailHealthCheck


class TestMailHealthCheck:
"""Test mail health check."""

@mock.patch("health_check.contrib.mail.backends.get_connection")
def test_mail_conn_ok(self, mocked_backend):
"""Test everything is OK."""

# instantiates the class
mail_health_checker = MailHealthCheck()

# invokes the method check_status()
mail_health_checker.check_status()
assert len(mail_health_checker.errors) == 0, mail_health_checker.errors

# mock assertions
assert mocked_backend.return_value.timeout == 15
mocked_backend.return_value.open.assert_called_once()
mocked_backend.return_value.close.assert_called_once()

@mock.patch("health_check.contrib.mail.backends.get_connection")
def test_mail_conn_refused(self, mocked_backend):
"""Test case then connection refused."""

mocked_backend.return_value.open.side_effect = ConnectionRefusedError(
"Refused connection"
)
# instantiates the class
mail_health_checker = MailHealthCheck()

# invokes the method check_status()
mail_health_checker.check_status()
assert len(mail_health_checker.errors) == 1, mail_health_checker.errors
assert (
mail_health_checker.errors[0].message
== mocked_backend.return_value.open.side_effect
)

# mock assertions
mocked_backend.return_value.open.assert_called_once()
1 change: 1 addition & 0 deletions tests/testapp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"health_check.contrib.migrations",
"health_check.contrib.celery_ping",
"health_check.contrib.s3boto_storage",
"health_check.contrib.mail",
"tests",
)

Expand Down

0 comments on commit 3d8bf8d

Please sign in to comment.