Skip to content
Merged
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
28 changes: 18 additions & 10 deletions cms/djangoapps/contentstore/views/tests/test_assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from xmodule.modulestore import ModuleStoreEnum # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.xml_importer import import_course_from_xml # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE

TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT

Expand All @@ -41,6 +42,9 @@ class AssetsTestCase(CourseTestCase):
"""
Parent class for all asset tests.
"""

MODULESTORE = TEST_DATA_SPLIT_MODULESTORE

def setUp(self):
super().setUp()
self.url = reverse_course_url('assets_handler', self.course.id)
Expand Down Expand Up @@ -96,15 +100,16 @@ def test_pdf_asset(self):
TEST_DATA_DIR,
['toy'],
static_content_store=contentstore(),
create_if_not_present=True,
verbose=True
)
course = course_items[0]
url = reverse_course_url('assets_handler', course.id)

# Test valid contentType for pdf asset (textbook.pdf)
resp = self.client.get(url, HTTP_ACCEPT='application/json')
self.assertContains(resp, "/c4x/edX/toy/asset/textbook.pdf")
asset_location = AssetKey.from_string('/c4x/edX/toy/asset/textbook.pdf')
self.assertContains(resp, "/asset-v1:edX+toy+2012_Fall+type@asset+block@textbook.pdf")
asset_location = AssetKey.from_string('asset-v1:edX+toy+2012_Fall+type@asset+block@textbook.pdf')
content = contentstore().find(asset_location)
# Check after import textbook.pdf has valid contentType ('application/pdf')

Expand Down Expand Up @@ -450,7 +455,8 @@ def test_locking(self):
"""
def verify_asset_locked_state(locked):
""" Helper method to verify lock state in the contentstore """
asset_location = StaticContent.get_location_from_path('/c4x/edX/toy/asset/sample_static.html')
asset_location = StaticContent.get_location_from_path(
'asset-v1:edX+toy+2012_Fall+type@asset+block@sample_static.html')
content = contentstore().find(asset_location)
self.assertEqual(content.locked, locked)

Expand Down Expand Up @@ -483,6 +489,7 @@ def post_asset_update(lock, course):
TEST_DATA_DIR,
['toy'],
static_content_store=contentstore(),
create_if_not_present=True,
verbose=True
)
course = course_items[0]
Expand Down Expand Up @@ -513,15 +520,15 @@ def setUp(self):

response = self.client.post(self.url, {"name": self.asset_name, "file": self.asset})
self.assertEqual(response.status_code, 200)
self.uploaded_url = json.loads(response.content.decode('utf-8'))['asset']['url']
self.uploaded_id = json.loads(response.content.decode('utf-8'))['asset']['id']

self.asset_location = AssetKey.from_string(self.uploaded_url)
self.asset_location = AssetKey.from_string(self.uploaded_id)
self.content = contentstore().find(self.asset_location)

def test_delete_asset(self):
""" Tests the happy path :) """
test_url = reverse_course_url(
'assets_handler', self.course.id, kwargs={'asset_key_string': str(self.uploaded_url)})
'assets_handler', self.course.id, kwargs={'asset_key_string': self.uploaded_id})
resp = self.client.delete(test_url, HTTP_ACCEPT="application/json")
self.assertEqual(resp.status_code, 204)

Expand All @@ -533,7 +540,7 @@ def test_delete_image_type_asset(self):
# upload image
response = self.client.post(self.url, {"name": "delete_image_test", "file": image_asset})
self.assertEqual(response.status_code, 200)
uploaded_image_url = json.loads(response.content.decode('utf-8'))['asset']['url']
uploaded_image_url = json.loads(response.content.decode('utf-8'))['asset']['id']

# upload image thumbnail
response = self.client.post(self.url, {"name": "delete_image_thumb_test", "file": thumbnail_image_asset})
Expand All @@ -558,16 +565,17 @@ def test_delete_asset_with_invalid_asset(self):
""" Tests the sad path :( """
test_url = reverse_course_url(
'assets_handler',
self.course.id, kwargs={'asset_key_string': "/c4x/edX/toy/asset/invalid.pdf"}
self.course.id, kwargs={'asset_key_string': "asset-v1:edX+toy+2012_Fall+type@asset+block@invalid.pdf"}
)
resp = self.client.delete(test_url, HTTP_ACCEPT="application/json")
self.assertEqual(resp.status_code, 404)

def test_delete_asset_with_invalid_thumbnail(self):
""" Tests the sad path :( """
test_url = reverse_course_url(
'assets_handler', self.course.id, kwargs={'asset_key_string': str(self.uploaded_url)})
self.content.thumbnail_location = StaticContent.get_location_from_path('/c4x/edX/toy/asset/invalid')
'assets_handler', self.course.id, kwargs={'asset_key_string': self.uploaded_id})
self.content.thumbnail_location = StaticContent.get_location_from_path(
'/asset-v1:edX+toy+2012_Fall+type@asset+block@invalid.pdf')
contentstore().save(self.content)
resp = self.client.delete(test_url, HTTP_ACCEPT="application/json")
self.assertEqual(resp.status_code, 204)
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

import pytest
import ddt
from pytz import UTC

from xmodule.data import CertificatesDisplayBehaviors
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_AMNESTY_MODULESTORE, ModuleStoreTestCase
from xmodule.modulestore.tests.django_utils import TEST_DATA_ONLY_SPLIT_MODULESTORE_DRAFT_PREFERRED, ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls

from ..models import CourseOverview
Expand All @@ -23,13 +24,12 @@ class CourseOverviewSignalsTestCase(ModuleStoreTestCase):
"""
Tests for CourseOverview signals.
"""
MODULESTORE = TEST_DATA_MONGO_AMNESTY_MODULESTORE
MODULESTORE = TEST_DATA_ONLY_SPLIT_MODULESTORE_DRAFT_PREFERRED
ENABLED_SIGNALS = ['course_deleted', 'course_published']
TODAY = datetime.datetime.utcnow()
TODAY = datetime.datetime.utcnow().replace(tzinfo=UTC)
NEXT_WEEK = TODAY + datetime.timedelta(days=7)

@ddt.data(ModuleStoreEnum.Type.split)
def test_caching(self, modulestore_type):
def test_caching(self):
"""
Tests that CourseOverview structures are actually getting cached.

Expand All @@ -38,14 +38,13 @@ def test_caching(self, modulestore_type):
course in.
"""
# Creating a new course will trigger a publish event and the course will be cached
course = CourseFactory.create(default_store=modulestore_type, emit_signals=True)
course = CourseFactory.create(emit_signals=True)

# The cache will be hit and mongo will not be queried
with check_mongo_calls(0):
CourseOverview.get_from_id(course.id)

@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
def test_cache_invalidation(self, modulestore_type):
def test_cache_invalidation(self):
"""
Tests that when a course is published or deleted, the corresponding
course_overview is removed from the cache.
Expand All @@ -54,28 +53,26 @@ def test_cache_invalidation(self, modulestore_type):
modulestore_type (ModuleStoreEnum.Type): type of store to create the
course in.
"""
with self.store.default_store(modulestore_type):

# Create a course where mobile_available is True.
course = CourseFactory.create(mobile_available=True, default_store=modulestore_type)
course_overview_1 = CourseOverview.get_from_id(course.id)
assert course_overview_1.mobile_available

# Set mobile_available to False and update the course.
# This fires a course_published signal, which should be caught in signals.py, which should in turn
# delete the corresponding CourseOverview from the cache.
course.mobile_available = False
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
self.store.update_item(course, ModuleStoreEnum.UserID.test)
# Create a course where mobile_available is True.
course = CourseFactory.create(mobile_available=True)
course_overview_1 = CourseOverview.get_from_id(course.id)
assert course_overview_1.mobile_available

# Set mobile_available to False and update the course.
# This fires a course_published signal, which should be caught in signals.py, which should in turn
# delete the corresponding CourseOverview from the cache.
course.mobile_available = False
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
self.store.update_item(course, ModuleStoreEnum.UserID.test)

# Make sure that when we load the CourseOverview again, mobile_available is updated.
course_overview_2 = CourseOverview.get_from_id(course.id)
assert not course_overview_2.mobile_available
# Make sure that when we load the CourseOverview again, mobile_available is updated.
course_overview_2 = CourseOverview.get_from_id(course.id)
assert not course_overview_2.mobile_available

# Verify that when the course is deleted, the corresponding CourseOverview is deleted as well.
with pytest.raises(CourseOverview.DoesNotExist):
self.store.delete_course(course.id, ModuleStoreEnum.UserID.test)
CourseOverview.get_from_id(course.id)
# Verify that when the course is deleted, the corresponding CourseOverview is deleted as well.
with pytest.raises(CourseOverview.DoesNotExist):
self.store.delete_course(course.id, ModuleStoreEnum.UserID.test)
CourseOverview.get_from_id(course.id)

def assert_changed_signal_sent(self, changes, mock_signal): # lint-amnesty, pylint: disable=missing-function-docstring
course = CourseFactory.create(
Expand All @@ -86,7 +83,7 @@ def assert_changed_signal_sent(self, changes, mock_signal): # lint-amnesty, pyl
# changing display name doesn't fire the signal
with self.captureOnCommitCallbacks(execute=True) as callbacks:
course.display_name = course.display_name + 'changed'
self.store.update_item(course, ModuleStoreEnum.UserID.test)
course = self.store.update_item(course, ModuleStoreEnum.UserID.test)
assert not mock_signal.called

# changing the given field fires the signal
Expand Down