test: adding test cases for the export course metadata export storage

This commit is contained in:
Daniel Wong
2025-05-20 15:40:53 -06:00
parent 49864105cd
commit 835b74bb4f
2 changed files with 86 additions and 5 deletions

View File

@@ -3,11 +3,15 @@ Tests for signals.py
"""
from unittest.mock import patch
from django.test.utils import override_settings
from django.conf import settings
from edx_toggles.toggles.testutils import override_waffle_flag
from xmodule.modulestore.django import SignalHandler
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, BlockFactory
from common.djangoapps.util.storage import resolve_storage_backend
from storages.backends.s3boto3 import S3Boto3Storage
from .signals import export_course_metadata
from .toggles import EXPORT_COURSE_METADATA_FLAG
@@ -53,3 +57,66 @@ class TestExportCourseMetadata(SharedModuleStoreTestCase):
patched_storage.save.assert_called_once_with(
f'course_metadata_export/{self.course_key}.json', patched_content.return_value
)
@override_settings(
COURSE_METADATA_EXPORT_STORAGE="cms.djangoapps.export_course_metadata.storage.CourseMetadataExportS3Storage",
DEFAULT_FILE_STORAGE="django.core.files.storage.FileSystemStorage"
)
def test_resolve_default_storage(self):
""" Ensure the default storage is invoked, even if course export storage is configured """
storage = resolve_storage_backend("default")
self.assertEqual(storage.__class__.__name__, "FileSystemStorage")
@override_settings(
COURSE_METADATA_EXPORT_STORAGE="cms.djangoapps.export_course_metadata.storage.CourseMetadataExportS3Storage",
DEFAULT_FILE_STORAGE="django.core.files.storage.FileSystemStorage",
COURSE_METADATA_EXPORT_BUCKET="bucket_name_test"
)
def test_resolve_happy_path_storage(self):
""" Make sure that the correct course export storage is being used """
storage = resolve_storage_backend("COURSE_METADATA_EXPORT_STORAGE")
self.assertEqual(storage.__class__.__name__, "CourseMetadataExportS3Storage")
self.assertEqual(storage.bucket_name, "bucket_name_test")
def test_resolve_storage_with_no_config(self):
""" If no storage setup is defined, we get FileSystemStorage by default """
del settings.DEFAULT_FILE_STORAGE
del settings.COURSE_METADATA_EXPORT_STORAGE
del settings.COURSE_METADATA_EXPORT_BUCKET
storage = resolve_storage_backend("COURSE_METADATA_EXPORT_STORAGE")
self.assertEqual(storage.__class__.__name__, "FileSystemStorage")
@override_settings(
COURSE_METADATA_EXPORT_STORAGE=None,
COURSE_METADATA_EXPORT_BUCKET="bucket_name_test",
STORAGES={
'COURSE_METADATA_EXPORT_STORAGE': {
'BACKEND': 'cms.djangoapps.export_course_metadata.storage.CourseMetadataExportS3Storage',
'OPTIONS': {}
}
}
)
def test_resolve_storage_using_django5_settings(self):
""" Simulating a Django 4 environment using Django 5 Storages configuration """
storage = resolve_storage_backend("COURSE_METADATA_EXPORT_STORAGE")
self.assertEqual(storage.__class__.__name__, "CourseMetadataExportS3Storage")
self.assertEqual(storage.bucket_name, "bucket_name_test")
@override_settings(
STORAGES={
'COURSE_METADATA_EXPORT_STORAGE': {
'BACKEND': 'storages.backends.s3boto3.S3Boto3Storage',
'OPTIONS': {
'bucket_name': 'bucket_name_test'
}
}
}
)
def test_resolve_storage_using_django5_settings_with_options(self):
""" Ensure we call the storage class with the correct parameters and Django 5 setup """
del settings.DEFAULT_FILE_STORAGE
del settings.COURSE_METADATA_EXPORT_STORAGE
del settings.COURSE_METADATA_EXPORT_BUCKET
storage = resolve_storage_backend("COURSE_METADATA_EXPORT_STORAGE")
self.assertEqual(storage.__class__.__name__, S3Boto3Storage.__name__)
self.assertEqual(storage.bucket_name, "bucket_name_test")

View File

@@ -6,14 +6,27 @@ from django.core.files.storage import default_storage
from django.utils.module_loading import import_string
if django.VERSION >= (5, 0):
from django.core.files.storage import storages
def resolve_storage_backend(storage_key, options=None):
"""
Configures and returns a Django `Storage` instance, compatible with both Django 4 and Django 5.
Main goal:
Deprecate the use of `django.core.files.storage.get_storage_class`.
How:
Replace `get_storage_class` with direct configuration logic,
ensuring backward compatibility with both Django 4 and Django 5 storage settings.
Returns:
An instance of the configured storage backend.
Raises:
ImportError: If the specified storage class cannot be imported.
"""
def resolve_storage_backend(storage_key, options={}):
storage_path = getattr(settings, storage_key)
storage_path = getattr(settings, storage_key, None)
storages_config = getattr(settings, 'STORAGES', {})
if options is None:
options = {}
if storage_key == "default":
# Use case 1: Default storage
# Works consistently across Django 4.2 and 5.x
@@ -29,6 +42,7 @@ def resolve_storage_backend(storage_key, options={}):
# "custom": {"BACKEND": "...", "OPTIONS": {...}},
# }
# See: https://docs.djangoproject.com/en/5.2/ref/settings/#std-setting-STORAGES
from django.core.files.storage import storages
return storages[storage_key]
if not storage_path and storage_key in storages_config:
@@ -37,7 +51,7 @@ def resolve_storage_backend(storage_key, options={}):
# Manually load the backend and options
storage_path = storages_config.get(storage_key, {}).get("BACKEND")
options = storages_config.get(storage_key, {}).get("OPTIONS", {})
if not storage_path:
# if no specific storage was resolved, use the default storage
return default_storage