Commit 05cb13b1 by David Baumgold

Adding and fixing tests

parent 77db1f8a
""" Unit tests for checklist methods in views.py. """ """ Unit tests for checklist methods in views.py. """
from contentstore.utils import get_modulestore, get_url_reverse from contentstore.utils import get_modulestore, get_url_reverse
from contentstore.tests.test_course_settings import CourseTestCase
from xmodule.modulestore.inheritance import own_metadata from xmodule.modulestore.inheritance import own_metadata
from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.factories import CourseFactory
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
import json import json
from .utils import CourseTestCase
class ChecklistTestCase(CourseTestCase): class ChecklistTestCase(CourseTestCase):
......
...@@ -10,9 +10,9 @@ class CourseUpdateTest(CourseTestCase): ...@@ -10,9 +10,9 @@ class CourseUpdateTest(CourseTestCase):
'''Go through each interface and ensure it works.''' '''Go through each interface and ensure it works.'''
# first get the update to force the creation # first get the update to force the creation
url = reverse('course_info', url = reverse('course_info',
kwargs={'org': self.course_location.org, kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'name': self.course_location.name}) 'name': self.course.location.name})
self.client.get(url) self.client.get(url)
init_content = '<iframe width="560" height="315" src="http://www.youtube.com/embed/RocY-Jd93XU" frameborder="0">' init_content = '<iframe width="560" height="315" src="http://www.youtube.com/embed/RocY-Jd93XU" frameborder="0">'
...@@ -20,8 +20,8 @@ class CourseUpdateTest(CourseTestCase): ...@@ -20,8 +20,8 @@ class CourseUpdateTest(CourseTestCase):
payload = {'content': content, payload = {'content': content,
'date': 'January 8, 2013'} 'date': 'January 8, 2013'}
url = reverse('course_info_json', url = reverse('course_info_json',
kwargs={'org': self.course_location.org, kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': ''}) 'provided_id': ''})
resp = self.client.post(url, json.dumps(payload), "application/json") resp = self.client.post(url, json.dumps(payload), "application/json")
...@@ -31,8 +31,8 @@ class CourseUpdateTest(CourseTestCase): ...@@ -31,8 +31,8 @@ class CourseUpdateTest(CourseTestCase):
self.assertHTMLEqual(payload['content'], content) self.assertHTMLEqual(payload['content'], content)
first_update_url = reverse('course_info_json', first_update_url = reverse('course_info_json',
kwargs={'org': self.course_location.org, kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': payload['id']}) 'provided_id': payload['id']})
content += '<div>div <p>p<br/></p></div>' content += '<div>div <p>p<br/></p></div>'
payload['content'] = content payload['content'] = content
...@@ -47,8 +47,8 @@ class CourseUpdateTest(CourseTestCase): ...@@ -47,8 +47,8 @@ class CourseUpdateTest(CourseTestCase):
payload = {'content': content, payload = {'content': content,
'date': 'January 11, 2013'} 'date': 'January 11, 2013'}
url = reverse('course_info_json', url = reverse('course_info_json',
kwargs={'org': self.course_location.org, kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': ''}) 'provided_id': ''})
resp = self.client.post(url, json.dumps(payload), "application/json") resp = self.client.post(url, json.dumps(payload), "application/json")
...@@ -58,8 +58,8 @@ class CourseUpdateTest(CourseTestCase): ...@@ -58,8 +58,8 @@ class CourseUpdateTest(CourseTestCase):
self.assertHTMLEqual(content, payload['content'], "self closing ol") self.assertHTMLEqual(content, payload['content'], "self closing ol")
url = reverse('course_info_json', url = reverse('course_info_json',
kwargs={'org': self.course_location.org, kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': ''}) 'provided_id': ''})
resp = self.client.get(url) resp = self.client.get(url)
payload = json.loads(resp.content) payload = json.loads(resp.content)
...@@ -73,8 +73,8 @@ class CourseUpdateTest(CourseTestCase): ...@@ -73,8 +73,8 @@ class CourseUpdateTest(CourseTestCase):
# now try to update a non-existent update # now try to update a non-existent update
url = reverse('course_info_json', url = reverse('course_info_json',
kwargs={'org': self.course_location.org, kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': '9'}) 'provided_id': '9'})
content = 'blah blah' content = 'blah blah'
payload = {'content': content, payload = {'content': content,
...@@ -87,8 +87,8 @@ class CourseUpdateTest(CourseTestCase): ...@@ -87,8 +87,8 @@ class CourseUpdateTest(CourseTestCase):
content = '<garbage tag No closing brace to force <span>error</span>' content = '<garbage tag No closing brace to force <span>error</span>'
payload = {'content': content, payload = {'content': content,
'date': 'January 11, 2013'} 'date': 'January 11, 2013'}
url = reverse('course_info_json', kwargs={'org': self.course_location.org, url = reverse('course_info_json', kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': ''}) 'provided_id': ''})
self.assertContains( self.assertContains(
...@@ -99,8 +99,8 @@ class CourseUpdateTest(CourseTestCase): ...@@ -99,8 +99,8 @@ class CourseUpdateTest(CourseTestCase):
content = "<p><br><br></p>" content = "<p><br><br></p>"
payload = {'content': content, payload = {'content': content,
'date': 'January 11, 2013'} 'date': 'January 11, 2013'}
url = reverse('course_info_json', kwargs={'org': self.course_location.org, url = reverse('course_info_json', kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': ''}) 'provided_id': ''})
resp = self.client.post(url, json.dumps(payload), "application/json") resp = self.client.post(url, json.dumps(payload), "application/json")
...@@ -108,8 +108,8 @@ class CourseUpdateTest(CourseTestCase): ...@@ -108,8 +108,8 @@ class CourseUpdateTest(CourseTestCase):
self.assertHTMLEqual(content, json.loads(resp.content)['content']) self.assertHTMLEqual(content, json.loads(resp.content)['content'])
# now try to delete a non-existent update # now try to delete a non-existent update
url = reverse('course_info_json', kwargs={'org': self.course_location.org, url = reverse('course_info_json', kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': '19'}) 'provided_id': '19'})
payload = {'content': content, payload = {'content': content,
'date': 'January 21, 2013'} 'date': 'January 21, 2013'}
...@@ -119,8 +119,8 @@ class CourseUpdateTest(CourseTestCase): ...@@ -119,8 +119,8 @@ class CourseUpdateTest(CourseTestCase):
content = 'blah blah' content = 'blah blah'
payload = {'content': content, payload = {'content': content,
'date': 'January 28, 2013'} 'date': 'January 28, 2013'}
url = reverse('course_info_json', kwargs={'org': self.course_location.org, url = reverse('course_info_json', kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': ''}) 'provided_id': ''})
resp = self.client.post(url, json.dumps(payload), "application/json") resp = self.client.post(url, json.dumps(payload), "application/json")
payload = json.loads(resp.content) payload = json.loads(resp.content)
...@@ -128,16 +128,16 @@ class CourseUpdateTest(CourseTestCase): ...@@ -128,16 +128,16 @@ class CourseUpdateTest(CourseTestCase):
self.assertHTMLEqual(content, payload['content'], "single iframe") self.assertHTMLEqual(content, payload['content'], "single iframe")
# first count the entries # first count the entries
url = reverse('course_info_json', url = reverse('course_info_json',
kwargs={'org': self.course_location.org, kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': ''}) 'provided_id': ''})
resp = self.client.get(url) resp = self.client.get(url)
payload = json.loads(resp.content) payload = json.loads(resp.content)
before_delete = len(payload) before_delete = len(payload)
url = reverse('course_info_json', url = reverse('course_info_json',
kwargs={'org': self.course_location.org, kwargs={'org': self.course.location.org,
'course': self.course_location.course, 'course': self.course.location.course,
'provided_id': this_id}) 'provided_id': this_id})
resp = self.client.delete(url) resp = self.client.delete(url)
payload = json.loads(resp.content) payload = json.loads(resp.content)
......
...@@ -22,7 +22,3 @@ class DeleteItem(CourseTestCase): ...@@ -22,7 +22,3 @@ class DeleteItem(CourseTestCase):
# Now delete it. There was a bug that the delete was failing (static tabs do not exist in draft modulestore). # Now delete it. There was a bug that the delete was failing (static tabs do not exist in draft modulestore).
resp = self.client.post(reverse('delete_item'), resp.content, "application/json") resp = self.client.post(reverse('delete_item'), resp.content, "application/json")
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
import json
import mock
from unittest import TestCase
from .utils import CourseTestCase
from django.core.urlresolvers import reverse
from contentstore.utils import get_modulestore
from contentstore.views.course import (
validate_textbook_json, TextbookValidationError)
class TextbookTestCase(CourseTestCase):
def setUp(self):
super(TextbookTestCase, self).setUp()
self.url = reverse('textbook_index', kwargs={
'org': self.course.location.org,
'course': self.course.location.course,
'name': self.course.location.name,
})
def test_view_index(self):
resp = self.client.get(self.url)
self.assertEqual(resp.status_code, 200)
# we don't have resp.context right now,
# due to bugs in our testing harness :(
if resp.context:
self.assertEqual(resp.context['course'], self.course)
def test_view_index_xhr(self):
resp = self.client.get(
self.url,
HTTP_ACCEPT="application/json",
HTTP_X_REQUESTED_WITH='XMLHttpRequest'
)
self.assertEqual(resp.status_code, 200)
obj = json.loads(resp.content)
self.assertEqual(self.course.pdf_textbooks, obj)
def test_view_index_xhr_post(self):
textbooks = [
{"tab_title": "Hi, mom!"},
{"tab_title": "Textbook 2"},
]
# import nose; nose.tools.set_trace()
resp = self.client.post(
self.url,
data=json.dumps(textbooks),
content_type="application/json",
HTTP_ACCEPT="application/json",
HTTP_X_REQUESTED_WITH='XMLHttpRequest'
)
self.assertEqual(resp.status_code, 204)
self.assertEqual(resp.content, "")
# reload course
store = get_modulestore(self.course.location)
course = store.get_item(self.course.location)
self.assertEqual(course.pdf_textbooks, textbooks)
class TextbookValidationTestCase(TestCase):
def test_happy_path(self):
textbooks = [
{
"tab_title": "Hi, mom!",
"url": "/mom.pdf"
},
{
"tab_title": "Textbook 2",
"chapters": [
{
"title": "Chapter 1",
"url": "/ch1.pdf"
}, {
"title": "Chapter 2",
"url": "/ch2.pdf"
}
]
}
]
result = validate_textbook_json(json.dumps(textbooks))
self.assertEqual(textbooks, result)
def test_invalid_json(self):
with self.assertRaises(TextbookValidationError):
validate_textbook_json("[{'abc'}]")
def test_wrong_json(self):
with self.assertRaises(TextbookValidationError):
validate_textbook_json('{"tab_title": "Hi, mom!"}')
def test_no_tab_title(self):
with self.assertRaises(TextbookValidationError):
validate_textbook_json('[{"url": "/textbook.pdf"}')
...@@ -6,6 +6,10 @@ import json ...@@ -6,6 +6,10 @@ import json
from student.models import Registration from student.models import Registration
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test.client import Client
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
def parse_json(response): def parse_json(response):
...@@ -21,3 +25,37 @@ def user(email): ...@@ -21,3 +25,37 @@ def user(email):
def registration(email): def registration(email):
"""look up registration object by email""" """look up registration object by email"""
return Registration.objects.get(user__email=email) return Registration.objects.get(user__email=email)
class CourseTestCase(ModuleStoreTestCase):
def setUp(self):
"""
These tests need a user in the DB so that the django Test Client
can log them in.
They inherit from the ModuleStoreTestCase class so that the mongodb collection
will be cleared out before each test case execution and deleted
afterwards.
"""
uname = 'testuser'
email = 'test+courses@edx.org'
password = 'foo'
# Create the use so we can log them in.
self.user = User.objects.create_user(uname, email, password)
# Note that we do not actually need to do anything
# for registration if we directly mark them active.
self.user.is_active = True
# Staff has access to view all courses
self.user.is_staff = True
self.user.save()
self.client = Client()
self.client.login(username=uname, password=password)
self.course = CourseFactory.create(
template='i4x://edx/templates/course/Empty',
org='MITx',
number='999',
display_name='Robot Super Course',
)
...@@ -416,6 +416,23 @@ def course_advanced_updates(request, org, course, name): ...@@ -416,6 +416,23 @@ def course_advanced_updates(request, org, course, name):
return HttpResponse(response_json, mimetype="application/json") return HttpResponse(response_json, mimetype="application/json")
class TextbookValidationError(Exception):
pass
def validate_textbook_json(text):
try:
obj = json.loads(text)
except ValueError:
raise TextbookValidationError("invalid JSON")
if not isinstance(obj, (list, tuple)):
raise TextbookValidationError("must be JSON list")
for textbook in obj:
if not textbook.get("tab_title"):
raise TextbookValidationError("every textbook must have a tab_title")
return obj
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def textbook_index(request, org, course, name): def textbook_index(request, org, course, name):
...@@ -433,18 +450,10 @@ def textbook_index(request, org, course, name): ...@@ -433,18 +450,10 @@ def textbook_index(request, org, course, name):
return HttpResponse(json.dumps(course_module.pdf_textbooks), content_type="application/json") return HttpResponse(json.dumps(course_module.pdf_textbooks), content_type="application/json")
elif request.method == 'POST': elif request.method == 'POST':
try: try:
obj = json.loads(request.raw_post_data) course_module.pdf_textbooks = validate_textbook_json(request.body)
except ValueError: except TextbookValidationError as e:
msg = {"error": "invalid JSON"} msg = {"error": e.message}
return HttpResponseBadRequest(json.dumps(msg), content_type="application/json")
if not isinstance(obj, (list, tuple)):
msg = {"error": "must be JSON list"}
return HttpResponseBadRequest(json.dumps(msg), content_type="application/json")
for textbook in obj:
if not textbook.get("tab_title"):
msg = {"error": "every textbook must have a tab_title"}
return HttpResponseBadRequest(json.dumps(msg), content_type="application/json") return HttpResponseBadRequest(json.dumps(msg), content_type="application/json")
course_module.pdf_textbooks = obj
if not any(tab['type'] == 'pdf_textbooks' for tab in course_module.tabs): if not any(tab['type'] == 'pdf_textbooks' for tab in course_module.tabs):
course_module.tabs.append({"type": "pdf_textbooks"}) course_module.tabs.append({"type": "pdf_textbooks"})
store.update_metadata(course_module.location, own_metadata(course_module)) store.update_metadata(course_module.location, own_metadata(course_module))
......
File mode changed from 100644 to 100755
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment