Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ Add the `health_check` applications to your `INSTALLED_APPS`:

**Note:** If using `boto 2.x.x` use `health_check.contrib.s3boto_storage`

If you want to customize some settings, you can do so by adding a `HEALTH_CHECK` dictionary to your `settings.py` file:

```python
HEALTH_CHECK = {
'STORAGE_DIR': 'another-dir-under-my-project/', # needs to be in a permitted directory like MEDIA_ROOT
}
```

(Optional) If using the `psutil` app, you can configure disk and memory
threshold settings; otherwise below defaults are assumed. If you want to disable
one of these checks, set its value to `None`.
Expand Down
1 change: 1 addition & 0 deletions health_check/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
HEALTH_CHECK.setdefault("WARNINGS_AS_ERRORS", True)
HEALTH_CHECK.setdefault("SUBSETS", {})
HEALTH_CHECK.setdefault("DISABLE_THREADING", False)
HEALTH_CHECK.setdefault("STORAGE_DIR", "")
15 changes: 14 additions & 1 deletion health_check/storage/backends.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import os
import uuid

from django.conf import settings

from health_check.conf import HEALTH_CHECK
from django.core.files.base import ContentFile
from django.core.files.storage import InvalidStorageError, default_storage, storages

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

STORAGE_DIR = HEALTH_CHECK["STORAGE_DIR"]


class StorageHealthCheck(BaseHealthCheckBackend):
"""
Expand All @@ -31,7 +37,14 @@ def get_storage(self):
return None

def get_file_name(self):
return f"health_check_storage_test/test-{uuid.uuid4()}.txt"
"""Return a unique file name for the health check.

It needs to be a relative path to the storage directory to ensure
that the file can be created in the storage backend."""
relative_file_path = f"health_check_storage_test/test-{uuid.uuid4()}.txt"
if STORAGE_DIR:
return os.path.relpath(f"{STORAGE_DIR}/{relative_file_path}", settings.BASE_DIR)
return relative_file_path

def get_file_content(self):
return b"this is the healthtest file content"
Expand Down
28 changes: 26 additions & 2 deletions tests/test_storage.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import tempfile
import unittest
from io import BytesIO
from unittest import mock

import django
from django.conf import settings
from django.core.files.base import File
from django.core.files.storage import Storage
from django.test import TestCase, override_settings
Expand All @@ -14,6 +16,8 @@
StorageHealthCheck,
)

original_get_file_name = StorageHealthCheck.get_file_name


class CustomStorage(Storage):
pass
Expand Down Expand Up @@ -105,8 +109,7 @@ def exists(self, name):
return name in self.files


def get_file_name(*args, **kwargs):
return "mockfile.txt"
get_file_name = mock.MagicMock(return_value="mockfile.txt")


def get_file_content(*args, **kwargs):
Expand Down Expand Up @@ -167,6 +170,27 @@ def test_check_status_working(self):
):
self.assertTrue(default_storage_health.check_status())

def test_check_status_working_with_custom_dir(self):
default_storage = DefaultFileStorageHealthCheck()
# restore the original get_file_name method
get_file_name.side_effect = lambda *args, **kwargs: original_get_file_name(default_storage, *args, **kwargs)

# check that it will be stored in the relative path
self.assertTrue(default_storage.check_status())
expected_pattern = r"health_check_storage_test\/test.*\.txt"
self.assertRegex(original_get_file_name(default_storage), expected_pattern)

tmp_dir = tempfile.mkdtemp(dir=settings.MEDIA_ROOT)
with mock.patch("health_check.storage.backends.STORAGE_DIR", tmp_dir):
# check that it will be stored in the custom path
default_storage = DefaultFileStorageHealthCheck()
get_file_name.side_effect = lambda *args, **kwargs: original_get_file_name(default_storage, *args, **kwargs)
self.assertTrue(default_storage.check_status())

# relative path in media directory
expected_pattern = r"media\/.*\/health_check_storage_test\/test.*\.txt"
self.assertRegex(original_get_file_name(default_storage), expected_pattern)

@mock.patch(
"health_check.storage.backends.storages",
{"default": MockStorage(saves=False)},
Expand Down