@@ -69,7 +69,7 @@ class TestExportGit(CourseTestCase):
|
||||
self.assertIn(
|
||||
('giturl must be defined in your '
|
||||
'course settings before you can export to git.'),
|
||||
response.content
|
||||
response.content.decode('utf-8')
|
||||
)
|
||||
|
||||
response = self.client.get('{}?action=push'.format(self.test_url))
|
||||
@@ -77,7 +77,7 @@ class TestExportGit(CourseTestCase):
|
||||
self.assertIn(
|
||||
('giturl must be defined in your '
|
||||
'course settings before you can export to git.'),
|
||||
response.content
|
||||
response.content.decode('utf-8')
|
||||
)
|
||||
|
||||
def test_course_export_failures(self):
|
||||
@@ -88,7 +88,7 @@ class TestExportGit(CourseTestCase):
|
||||
modulestore().update_item(self.course_module, self.user.id)
|
||||
|
||||
response = self.client.get('{}?action=push'.format(self.test_url))
|
||||
self.assertIn('Export Failed:', response.content)
|
||||
self.assertIn('Export Failed:', response.content.decode('utf-8'))
|
||||
|
||||
def test_exception_translation(self):
|
||||
"""
|
||||
@@ -98,7 +98,7 @@ class TestExportGit(CourseTestCase):
|
||||
modulestore().update_item(self.course_module, self.user.id)
|
||||
|
||||
response = self.client.get('{}?action=push'.format(self.test_url))
|
||||
self.assertNotIn('django.utils.functional.__proxy__', response.content)
|
||||
self.assertNotIn('django.utils.functional.__proxy__', response.content.decode('utf-8'))
|
||||
|
||||
def test_course_export_success(self):
|
||||
"""
|
||||
@@ -107,7 +107,7 @@ class TestExportGit(CourseTestCase):
|
||||
|
||||
self.make_bare_repo_with_course('test_repo')
|
||||
response = self.client.get('{}?action=push'.format(self.test_url))
|
||||
self.assertIn('Export Succeeded', response.content)
|
||||
self.assertIn('Export Succeeded', response.content.decode('utf-8'))
|
||||
|
||||
def test_repo_with_dots(self):
|
||||
"""
|
||||
@@ -115,7 +115,7 @@ class TestExportGit(CourseTestCase):
|
||||
"""
|
||||
self.make_bare_repo_with_course('test.repo')
|
||||
response = self.client.get('{}?action=push'.format(self.test_url))
|
||||
self.assertIn('Export Succeeded', response.content)
|
||||
self.assertIn('Export Succeeded', response.content.decode('utf-8'))
|
||||
|
||||
def test_dirty_repo(self):
|
||||
"""
|
||||
|
||||
@@ -873,7 +873,7 @@ class TestGetTranscript(SharedModuleStoreTestCase):
|
||||
Verify that `get_transcript` function returns correct data when transcript is in content store.
|
||||
"""
|
||||
base_filename = 'video_101.srt'
|
||||
self.upload_file(self.create_srt_file(self.subs_srt), self.video.location, base_filename)
|
||||
self.upload_file(self.create_srt_file(self.subs_srt.encode('utf-8')), self.video.location, base_filename)
|
||||
self.create_transcript(subs_id, language, base_filename, youtube_id_1_0, html5_sources)
|
||||
content, file_name, mimetype = transcripts_utils.get_transcript(
|
||||
self.video,
|
||||
@@ -935,7 +935,7 @@ class TestGetTranscript(SharedModuleStoreTestCase):
|
||||
"""
|
||||
Verify that `get_transcript` function returns correct exception when transcript content is empty.
|
||||
"""
|
||||
self.upload_file(self.create_srt_file(''), self.video.location, 'ur_video_101.srt')
|
||||
self.upload_file(self.create_srt_file(b''), self.video.location, 'ur_video_101.srt')
|
||||
self.create_transcript('', 'ur', 'ur_video_101.srt')
|
||||
|
||||
with self.assertRaises(NotFoundError) as no_content_exception:
|
||||
|
||||
@@ -289,7 +289,7 @@ class TestAnnouncementsViews(MaintenanceViewTestCase):
|
||||
"""
|
||||
url = reverse("maintenance:announcement_index")
|
||||
response = self.client.get(url)
|
||||
self.assertIn('<div class="announcement-container">', response.content)
|
||||
self.assertIn('<div class="announcement-container">', response.content.decode('utf-8'))
|
||||
|
||||
def test_create(self):
|
||||
"""
|
||||
@@ -308,7 +308,7 @@ class TestAnnouncementsViews(MaintenanceViewTestCase):
|
||||
announcement.save()
|
||||
url = reverse("maintenance:announcement_edit", kwargs={"pk": announcement.pk})
|
||||
response = self.client.get(url)
|
||||
self.assertIn('<div class="wrapper-form announcement-container">', response.content)
|
||||
self.assertIn('<div class="wrapper-form announcement-container">', response.content.decode('utf-8'))
|
||||
self.client.post(url, {"content": "Test Edit Announcement", "active": True})
|
||||
announcement = Announcement.objects.get(pk=announcement.pk)
|
||||
self.assertEquals(announcement.content, "Test Edit Announcement")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
import re
|
||||
from six import StringIO
|
||||
from six import BytesIO
|
||||
from six.moves.urllib.parse import parse_qsl, urlparse, urlunparse
|
||||
|
||||
import ddt
|
||||
@@ -331,7 +331,7 @@ class CanonicalContentTest(SharedModuleStoreTestCase):
|
||||
StaticContent: the StaticContent object for the created image
|
||||
"""
|
||||
new_image = Image.new('RGB', dimensions, color)
|
||||
new_buf = StringIO()
|
||||
new_buf = BytesIO()
|
||||
new_image.save(new_buf, format='png')
|
||||
new_buf.seek(0)
|
||||
new_name = name.format(prefix)
|
||||
@@ -355,7 +355,7 @@ class CanonicalContentTest(SharedModuleStoreTestCase):
|
||||
StaticContent: the StaticContent object for the created content
|
||||
|
||||
"""
|
||||
new_buf = StringIO('testingggggggggggg')
|
||||
new_buf = BytesIO(b'testingggggggggggg')
|
||||
new_name = name.format(prefix)
|
||||
new_key = StaticContent.compute_location(cls.courses[prefix].id, new_name)
|
||||
new_content = StaticContent(new_key, new_name, 'application/octet-stream', new_buf.getvalue(), locked=locked)
|
||||
@@ -588,8 +588,6 @@ class CanonicalContentTest(SharedModuleStoreTestCase):
|
||||
|
||||
with check_mongo_calls(mongo_calls):
|
||||
asset_path = StaticContent.get_canonicalized_asset_path(self.courses[prefix].id, start, base_url, exts)
|
||||
print(expected)
|
||||
print(asset_path)
|
||||
self.assertIsNotNone(re.match(expected, asset_path))
|
||||
|
||||
@ddt.data(
|
||||
@@ -786,6 +784,4 @@ class CanonicalContentTest(SharedModuleStoreTestCase):
|
||||
|
||||
with check_mongo_calls(mongo_calls):
|
||||
asset_path = StaticContent.get_canonicalized_asset_path(self.courses[prefix].id, start, base_url, exts)
|
||||
print(expected)
|
||||
print(asset_path)
|
||||
self.assertIsNotNone(re.match(expected, asset_path))
|
||||
|
||||
@@ -327,14 +327,14 @@ def _get_redirect_to(request):
|
||||
mime_type, _ = mimetypes.guess_type(redirect_to, strict=False)
|
||||
if not is_safe_login_or_logout_redirect(request, redirect_to):
|
||||
log.warning(
|
||||
u'Unsafe redirect parameter detected after login page: %(redirect_to)r',
|
||||
u"Unsafe redirect parameter detected after login page: '%(redirect_to)s'",
|
||||
{"redirect_to": redirect_to}
|
||||
)
|
||||
redirect_to = None
|
||||
elif 'text/html' not in header_accept:
|
||||
log.info(
|
||||
u'Redirect to non html content %(content_type)r detected from %(user_agent)r'
|
||||
u' after login page: %(redirect_to)r',
|
||||
u"Redirect to non html content '%(content_type)s' detected from '%(user_agent)s'"
|
||||
u" after login page: '%(redirect_to)s'",
|
||||
{
|
||||
"redirect_to": redirect_to, "content_type": header_accept,
|
||||
"user_agent": request.META.get('HTTP_USER_AGENT', '')
|
||||
@@ -343,13 +343,13 @@ def _get_redirect_to(request):
|
||||
redirect_to = None
|
||||
elif mime_type:
|
||||
log.warning(
|
||||
u'Redirect to url path with specified filed type %(mime_type)r not allowed: %(redirect_to)r',
|
||||
u"Redirect to url path with specified filed type '%(mime_type)s' not allowed: '%(redirect_to)s'",
|
||||
{"redirect_to": redirect_to, "mime_type": mime_type}
|
||||
)
|
||||
redirect_to = None
|
||||
elif settings.STATIC_URL in redirect_to:
|
||||
log.warning(
|
||||
u'Redirect to static content detected after login page: %(redirect_to)r',
|
||||
u"Redirect to static content detected after login page: '%(redirect_to)s'",
|
||||
{"redirect_to": redirect_to}
|
||||
)
|
||||
redirect_to = None
|
||||
@@ -359,7 +359,7 @@ def _get_redirect_to(request):
|
||||
for theme in themes:
|
||||
if theme.theme_dir_name in next_path:
|
||||
log.warning(
|
||||
u'Redirect to theme content detected after login page: %(redirect_to)r',
|
||||
u"Redirect to theme content detected after login page: '%(redirect_to)s'",
|
||||
{"redirect_to": redirect_to}
|
||||
)
|
||||
redirect_to = None
|
||||
|
||||
@@ -38,20 +38,20 @@ class TestLoginHelper(TestCase):
|
||||
|
||||
@ddt.data(
|
||||
(logging.WARNING, "WARNING", "https://www.amazon.com", "text/html", None,
|
||||
"Unsafe redirect parameter detected after login page: u'https://www.amazon.com'"),
|
||||
"Unsafe redirect parameter detected after login page: 'https://www.amazon.com'"),
|
||||
(logging.WARNING, "WARNING", "testserver/edx.org/images/logo", "text/html", None,
|
||||
"Redirect to theme content detected after login page: u'testserver/edx.org/images/logo'"),
|
||||
"Redirect to theme content detected after login page: 'testserver/edx.org/images/logo'"),
|
||||
(logging.INFO, "INFO", "favicon.ico", "image/*", "test/agent",
|
||||
"Redirect to non html content 'image/*' detected from 'test/agent' after login page: u'favicon.ico'"),
|
||||
"Redirect to non html content 'image/*' detected from 'test/agent' after login page: 'favicon.ico'"),
|
||||
(logging.WARNING, "WARNING", "https://www.test.com/test.jpg", "image/*", None,
|
||||
"Unsafe redirect parameter detected after login page: u'https://www.test.com/test.jpg'"),
|
||||
"Unsafe redirect parameter detected after login page: 'https://www.test.com/test.jpg'"),
|
||||
(logging.INFO, "INFO", static_url + "dummy.png", "image/*", "test/agent",
|
||||
"Redirect to non html content 'image/*' detected from 'test/agent' after login page: u'" + static_url +
|
||||
"Redirect to non html content 'image/*' detected from 'test/agent' after login page: '" + static_url +
|
||||
"dummy.png" + "'"),
|
||||
(logging.WARNING, "WARNING", "test.png", "text/html", None,
|
||||
"Redirect to url path with specified filed type 'image/png' not allowed: u'test.png'"),
|
||||
"Redirect to url path with specified filed type 'image/png' not allowed: 'test.png'"),
|
||||
(logging.WARNING, "WARNING", static_url + "dummy.png", "text/html", None,
|
||||
"Redirect to url path with specified filed type 'image/png' not allowed: u'" + static_url + "dummy.png" + "'"),
|
||||
"Redirect to url path with specified filed type 'image/png' not allowed: '" + static_url + "dummy.png" + "'"),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_next_failures(self, log_level, log_name, unsafe_url, http_accept, user_agent, expected_log):
|
||||
|
||||
@@ -22,7 +22,7 @@ class StubYouTubeServiceTest(unittest.TestCase):
|
||||
|
||||
def test_unused_url(self):
|
||||
response = requests.get(self.url + 'unused_url')
|
||||
self.assertEqual("Unused url", response.content)
|
||||
self.assertEqual(b"Unused url", response.content)
|
||||
|
||||
@unittest.skip('Failing intermittently due to inconsistent responses from YT. See TE-871')
|
||||
def test_video_url(self):
|
||||
@@ -32,7 +32,7 @@ class StubYouTubeServiceTest(unittest.TestCase):
|
||||
|
||||
# YouTube metadata for video `OEoXaMPEzfM` states that duration is 116.
|
||||
self.assertEqual(
|
||||
'callback_func({"data": {"duration": 116, "message": "I\'m youtube.", "id": "OEoXaMPEzfM"}})',
|
||||
b'callback_func({"data": {"duration": 116, "message": "I\'m youtube.", "id": "OEoXaMPEzfM"}})',
|
||||
response.content
|
||||
)
|
||||
|
||||
@@ -46,7 +46,7 @@ class StubYouTubeServiceTest(unittest.TestCase):
|
||||
'<?xml version="1.0" encoding="utf-8" ?>',
|
||||
'<transcript><text start="1.0" dur="1.0">',
|
||||
'Equal transcripts</text></transcript>'
|
||||
]), response.content
|
||||
]).encode('utf-8'), response.content
|
||||
)
|
||||
|
||||
def test_transcript_url_not_equal(self):
|
||||
@@ -60,7 +60,7 @@ class StubYouTubeServiceTest(unittest.TestCase):
|
||||
'<transcript><text start="1.1" dur="5.5">',
|
||||
'Transcripts sample, different that on server',
|
||||
'</text></transcript>'
|
||||
]), response.content
|
||||
]).encode('utf-8'), response.content
|
||||
)
|
||||
|
||||
def test_transcript_not_found(self):
|
||||
|
||||
@@ -65,7 +65,7 @@ class StubYouTubeHandler(StubHttpRequestHandler):
|
||||
'<?xml version="1.0" encoding="utf-8" ?>',
|
||||
'<transcript><text start="1.0" dur="1.0">',
|
||||
'Equal transcripts</text></transcript>'
|
||||
])
|
||||
]).encode('utf-8')
|
||||
|
||||
self.send_response(
|
||||
200, content=status_message, headers={'Content-type': 'application/xml'}
|
||||
@@ -77,7 +77,7 @@ class StubYouTubeHandler(StubHttpRequestHandler):
|
||||
'<transcript><text start="1.1" dur="5.5">',
|
||||
'Transcripts sample, different that on server',
|
||||
'</text></transcript>'
|
||||
])
|
||||
]).encode('utf-8')
|
||||
|
||||
self.send_response(
|
||||
200, content=status_message, headers={'Content-type': 'application/xml'}
|
||||
@@ -99,7 +99,7 @@ class StubYouTubeHandler(StubHttpRequestHandler):
|
||||
# Delay the response to simulate network latency
|
||||
time.sleep(self.server.config.get('time_to_response', self.DEFAULT_DELAY_SEC))
|
||||
if self.server.config.get('youtube_api_blocked'):
|
||||
self.send_response(404, content='', headers={'Content-type': 'text/plain'})
|
||||
self.send_response(404, content=b'', headers={'Content-type': 'text/plain'})
|
||||
else:
|
||||
# Get the response to send from YouTube.
|
||||
# We need to do this every time because Google sometimes sends different responses
|
||||
@@ -110,7 +110,7 @@ class StubYouTubeHandler(StubHttpRequestHandler):
|
||||
|
||||
else:
|
||||
self.send_response(
|
||||
404, content="Unused url", headers={'Content-type': 'text/plain'}
|
||||
404, content=b"Unused url", headers={'Content-type': 'text/plain'}
|
||||
)
|
||||
|
||||
def _send_video_response(self, youtube_id, message):
|
||||
@@ -134,7 +134,7 @@ class StubYouTubeHandler(StubHttpRequestHandler):
|
||||
})
|
||||
)
|
||||
})
|
||||
response = "{cb}({data})".format(cb=callback, data=json.dumps(data))
|
||||
response = "{cb}({data})".format(cb=callback, data=json.dumps(data)).encode('utf-8')
|
||||
|
||||
self.send_response(200, content=response, headers={'Content-type': 'text/html'})
|
||||
self.log_message("Youtube: sent response {}".format(message))
|
||||
@@ -158,7 +158,7 @@ class StubYouTubeHandler(StubHttpRequestHandler):
|
||||
"message": message,
|
||||
})
|
||||
})
|
||||
response = "{cb}({data})".format(cb=callback, data=json.dumps(data))
|
||||
response = "{cb}({data})".format(cb=callback, data=json.dumps(data)).encode('utf-8')
|
||||
|
||||
self.send_response(200, content=response, headers={'Content-type': 'text/html'})
|
||||
self.log_message("Youtube: sent response {}".format(message))
|
||||
|
||||
@@ -144,7 +144,10 @@ class TrackMiddleware(object):
|
||||
# HTTP headers may contain Latin1 characters. Decoding using Latin1 encoding here
|
||||
# avoids encountering UnicodeDecodeError exceptions when these header strings are
|
||||
# output to tracking logs.
|
||||
context[context_key] = request.META.get(header_name, '').decode('latin1')
|
||||
context_value = request.META.get(header_name, '')
|
||||
if isinstance(context_value, six.binary_type):
|
||||
context_value = context_value.decode('latin1')
|
||||
context[context_key] = context_value
|
||||
|
||||
# Google Analytics uses the clientId to keep track of unique visitors. A GA cookie looks like
|
||||
# this: _ga=GA1.2.1033501218.1368477899. The clientId is this part: 1033501218.1368477899.
|
||||
@@ -183,8 +186,9 @@ class TrackMiddleware(object):
|
||||
# Using a known-insecure hash to shorten is silly.
|
||||
# Also, why do we need same length?
|
||||
key_salt = "common.djangoapps.track" + self.__class__.__name__
|
||||
key = hashlib.md5(key_salt + settings.SECRET_KEY).digest()
|
||||
encrypted_session_key = hmac.new(key, msg=session_key, digestmod=hashlib.md5).hexdigest()
|
||||
key_bytes = (key_salt + settings.SECRET_KEY).encode('utf-8')
|
||||
key = hashlib.md5(key_bytes).digest()
|
||||
encrypted_session_key = hmac.new(key, msg=session_key.encode('utf-8'), digestmod=hashlib.md5).hexdigest()
|
||||
return encrypted_session_key
|
||||
|
||||
def get_user_primary_key(self, request):
|
||||
|
||||
@@ -49,9 +49,7 @@ class TrackMiddlewareTestCase(TestCase):
|
||||
request.META[meta_key] = 'test latin1 \xd3 \xe9 \xf1' # pylint: disable=no-member
|
||||
|
||||
context = self.get_context_for_request(request)
|
||||
# The bytes in the string on the right are utf8 encoded in the source file, so we decode them to construct
|
||||
# a valid unicode string.
|
||||
self.assertEqual(context[context_key], 'test latin1 Ó é ñ'.decode('utf8'))
|
||||
self.assertEqual(context[context_key], u'test latin1 Ó é ñ')
|
||||
|
||||
def test_default_filters_do_not_render_view(self):
|
||||
for url in ['/event', '/event/1', '/login', '/heartbeat']:
|
||||
@@ -79,7 +77,7 @@ class TrackMiddlewareTestCase(TestCase):
|
||||
|
||||
def test_default_request_context(self):
|
||||
context = self.get_context_for_path('/courses/')
|
||||
self.assertEquals(context, {
|
||||
self.assertEqual(context, {
|
||||
'accept_language': '',
|
||||
'referer': '',
|
||||
'user_id': '',
|
||||
@@ -101,7 +99,7 @@ class TrackMiddlewareTestCase(TestCase):
|
||||
request.META['REMOTE_ADDR'] = remote_addr
|
||||
context = self.get_context_for_request(request)
|
||||
|
||||
self.assertEquals(context['ip'], remote_addr)
|
||||
self.assertEqual(context['ip'], remote_addr)
|
||||
|
||||
def test_single_forward_for_header_ip_context(self):
|
||||
request = self.request_factory.get('/courses/')
|
||||
@@ -112,7 +110,7 @@ class TrackMiddlewareTestCase(TestCase):
|
||||
request.META['HTTP_X_FORWARDED_FOR'] = forwarded_ip
|
||||
context = self.get_context_for_request(request)
|
||||
|
||||
self.assertEquals(context['ip'], forwarded_ip)
|
||||
self.assertEqual(context['ip'], forwarded_ip)
|
||||
|
||||
def test_multiple_forward_for_header_ip_context(self):
|
||||
request = self.request_factory.get('/courses/')
|
||||
@@ -123,7 +121,7 @@ class TrackMiddlewareTestCase(TestCase):
|
||||
request.META['HTTP_X_FORWARDED_FOR'] = forwarded_ip
|
||||
context = self.get_context_for_request(request)
|
||||
|
||||
self.assertEquals(context['ip'], '11.22.33.44')
|
||||
self.assertEqual(context['ip'], '11.22.33.44')
|
||||
|
||||
def get_context_for_path(self, path):
|
||||
"""Extract the generated event tracking context for a given request for the given path."""
|
||||
@@ -138,7 +136,7 @@ class TrackMiddlewareTestCase(TestCase):
|
||||
finally:
|
||||
self.track_middleware.process_response(request, None)
|
||||
|
||||
self.assertEquals(
|
||||
self.assertEqual(
|
||||
tracker.get_tracker().resolve_context(),
|
||||
{}
|
||||
)
|
||||
@@ -156,7 +154,7 @@ class TrackMiddlewareTestCase(TestCase):
|
||||
def assert_dict_subset(self, superset, subset):
|
||||
"""Assert that the superset dict contains all of the key-value pairs found in the subset dict."""
|
||||
for key, expected_value in six.iteritems(subset):
|
||||
self.assertEquals(superset[key], expected_value)
|
||||
self.assertEqual(superset[key], expected_value)
|
||||
|
||||
def test_request_with_user(self):
|
||||
user_id = 1
|
||||
@@ -177,7 +175,7 @@ class TrackMiddlewareTestCase(TestCase):
|
||||
request.session.save()
|
||||
session_key = request.session.session_key
|
||||
expected_session_key = self.track_middleware.encrypt_session_key(session_key)
|
||||
self.assertEquals(len(session_key), len(expected_session_key))
|
||||
self.assertEqual(len(session_key), len(expected_session_key))
|
||||
context = self.get_context_for_request(request)
|
||||
self.assert_dict_subset(context, {
|
||||
'session': expected_session_key,
|
||||
@@ -188,7 +186,7 @@ class TrackMiddlewareTestCase(TestCase):
|
||||
session_key = '665924b49a93e22b46ee9365abf28c2a'
|
||||
expected_session_key = '3b81f559d14130180065d635a4f35dd2'
|
||||
encrypted_session_key = self.track_middleware.encrypt_session_key(session_key)
|
||||
self.assertEquals(encrypted_session_key, expected_session_key)
|
||||
self.assertEqual(encrypted_session_key, expected_session_key)
|
||||
|
||||
def test_request_headers(self):
|
||||
ip_address = '10.0.0.0'
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import ddt
|
||||
import six
|
||||
from django.contrib.auth.models import User
|
||||
from django.test.client import RequestFactory
|
||||
from django.test.utils import override_settings
|
||||
@@ -316,7 +317,7 @@ class TestTrackViews(EventTrackingTestCase):
|
||||
}
|
||||
|
||||
task_info = {
|
||||
sentinel.task_key: sentinel.task_value
|
||||
six.text_type(sentinel.task_key): sentinel.task_value
|
||||
}
|
||||
expected_event_data = dict(task_info)
|
||||
expected_event_data.update(self.event)
|
||||
|
||||
@@ -85,7 +85,7 @@ class StoreUploadedFileTestCase(TestCase):
|
||||
def setUp(self):
|
||||
super(StoreUploadedFileTestCase, self).setUp()
|
||||
self.request = Mock(spec=HttpRequest)
|
||||
self.file_content = "test file content"
|
||||
self.file_content = b"test file content"
|
||||
self.stored_file_name = None
|
||||
self.file_storage = None
|
||||
self.default_max_size = 2000000
|
||||
@@ -149,7 +149,7 @@ class StoreUploadedFileTestCase(TestCase):
|
||||
def exception_validator(storage, filename):
|
||||
""" Validation test function that throws an exception """
|
||||
self.assertEqual("error_file.csv", os.path.basename(filename))
|
||||
with storage.open(filename, 'rU') as f:
|
||||
with storage.open(filename, 'rb') as f:
|
||||
self.assertEqual(self.file_content, f.read())
|
||||
store_file_data(storage, filename)
|
||||
raise FileValidationException("validation failed")
|
||||
@@ -190,7 +190,7 @@ class StoreUploadedFileTestCase(TestCase):
|
||||
"""
|
||||
Tests uploading a file with upper case extension. Verifies that the stored file contents are correct.
|
||||
"""
|
||||
file_content = "uppercase"
|
||||
file_content = b"uppercase"
|
||||
self.request.FILES = {"uploaded_file": SimpleUploadedFile("tempfile.CSV", file_content)}
|
||||
file_storage, stored_file_name = store_uploaded_file(
|
||||
self.request, "uploaded_file", [".gif", ".csv"], "second_stored_file", self.default_max_size
|
||||
@@ -202,7 +202,7 @@ class StoreUploadedFileTestCase(TestCase):
|
||||
Test that the file storage method will create a unique filename if the file already exists.
|
||||
"""
|
||||
requested_file_name = "nonunique_store"
|
||||
file_content = "copy"
|
||||
file_content = b"copy"
|
||||
|
||||
self.request.FILES = {"nonunique_file": SimpleUploadedFile("nonunique.txt", file_content)}
|
||||
_, first_stored_file_name = store_uploaded_file(
|
||||
@@ -220,7 +220,7 @@ class StoreUploadedFileTestCase(TestCase):
|
||||
def _verify_successful_upload(self, storage, file_name, expected_content):
|
||||
""" Helper method that checks that the stored version of the uploaded file has the correct content """
|
||||
self.assertTrue(storage.exists(file_name))
|
||||
with storage.open(file_name, 'r') as f:
|
||||
with storage.open(file_name, 'rb') as f:
|
||||
self.assertEqual(expected_content, f.read())
|
||||
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ class StaticContent(object):
|
||||
if query_val.startswith("/static/"):
|
||||
new_val = StaticContent.get_canonicalized_asset_path(
|
||||
course_key, query_val, base_url, excluded_exts, encode=False)
|
||||
updated_query_params.append((query_name, new_val))
|
||||
updated_query_params.append((query_name, new_val.encode('utf-8')))
|
||||
else:
|
||||
# Make sure we're encoding Unicode strings down to their byte string
|
||||
# representation so that `urlencode` can handle it.
|
||||
@@ -286,11 +286,11 @@ class StaticContent(object):
|
||||
|
||||
# Only encode this if told to. Important so that we don't double encode
|
||||
# when working with paths that are in query parameters.
|
||||
asset_path = asset_path.encode('utf-8')
|
||||
if encode:
|
||||
asset_path = asset_path.encode('utf-8')
|
||||
asset_path = quote_plus(asset_path, '/:+@')
|
||||
|
||||
return urlunparse(('', base_url.encode('utf-8'), asset_path, params, urlencode(updated_query_params), ''))
|
||||
return urlunparse(('', base_url, asset_path, params, urlencode(updated_query_params), ''))
|
||||
|
||||
def stream_data(self):
|
||||
yield self._data
|
||||
|
||||
@@ -99,7 +99,10 @@ class MongoContentStore(ContentStore):
|
||||
import_path=content.import_path,
|
||||
# getattr b/c caching may mean some pickled instances don't have attr
|
||||
locked=getattr(content, 'locked', False)) as fp:
|
||||
if hasattr(content.data, '__iter__'):
|
||||
|
||||
# It seems that this code thought that only some specific object would have the `__iter__` attribute
|
||||
# but the bytes object in python 3 has one and should not use the chunking logic.
|
||||
if hasattr(content.data, '__iter__') and not isinstance(content.data, six.binary_type):
|
||||
for chunk in content.data:
|
||||
fp.write(chunk)
|
||||
else:
|
||||
|
||||
@@ -1298,7 +1298,8 @@ class ModuleStoreWriteBase(ModuleStoreReadBase, ModuleStoreWrite):
|
||||
result = defaultdict(dict)
|
||||
if fields is None:
|
||||
return result
|
||||
cls = self.mixologist.mix(XBlock.load_class(category, select=prefer_xmodules))
|
||||
classes = XBlock.load_class(category, select=prefer_xmodules)
|
||||
cls = self.mixologist.mix(classes)
|
||||
for field_name, value in six.iteritems(fields):
|
||||
field = getattr(cls, field_name)
|
||||
result[field.scope][field_name] = value
|
||||
|
||||
@@ -126,7 +126,7 @@ def save_subs_to_store(subs, subs_id, item, language='en'):
|
||||
|
||||
Returns: location of saved subtitles.
|
||||
"""
|
||||
filedata = json.dumps(subs, indent=2)
|
||||
filedata = json.dumps(subs, indent=2).encode('utf-8')
|
||||
filename = subs_filename(subs_id, language)
|
||||
return save_to_store(filedata, filename, 'application/json', item.location)
|
||||
|
||||
|
||||
@@ -1187,10 +1187,11 @@ class TestConditionalContent(TestSubmittingProblems):
|
||||
self.assertEqual(self.score_for_hw('homework2'), [1.0, 2.0])
|
||||
self.assertEqual(self.earned_hw_scores(), [1.0, 3.0])
|
||||
|
||||
# Grade percent is .63. Here is the calculation
|
||||
homework_1_score = 1.0 / 2
|
||||
homework_2_score = (1.0 + 2.0) / 4
|
||||
self.check_grade_percent(round((homework_1_score + homework_2_score) / 2, 2))
|
||||
# Grade percent is .63. Here is the calculation:
|
||||
# homework_1_score = 1.0 / 2
|
||||
# homework_2_score = (1.0 + 2.0) / 4
|
||||
# round((homework_1_score + homework_2_score) / 2) == .63
|
||||
self.check_grade_percent(.63)
|
||||
|
||||
def test_split_different_problems_group_1(self):
|
||||
"""
|
||||
@@ -1205,10 +1206,11 @@ class TestConditionalContent(TestSubmittingProblems):
|
||||
self.assertEqual(self.score_for_hw('homework2'), [1.0])
|
||||
self.assertEqual(self.earned_hw_scores(), [1.0, 1.0])
|
||||
|
||||
# Grade percent is .75. Here is the calculation
|
||||
homework_1_score = 1.0 / 2
|
||||
homework_2_score = 1.0 / 1
|
||||
self.check_grade_percent(round((homework_1_score + homework_2_score) / 2, 2))
|
||||
# Grade percent is .75. Here is the calculation:
|
||||
# homework_1_score = 1.0 / 2
|
||||
# homework_2_score = 1.0 / 1
|
||||
# round((homework_1_score + homework_2_score) / 2) == .75
|
||||
self.check_grade_percent(.75)
|
||||
|
||||
def split_one_group_no_problems_setup(self, user_partition_group):
|
||||
"""
|
||||
@@ -1238,10 +1240,11 @@ class TestConditionalContent(TestSubmittingProblems):
|
||||
self.assertEqual(self.score_for_hw('homework2'), [])
|
||||
self.assertEqual(self.earned_hw_scores(), [1.0])
|
||||
|
||||
# Grade percent is .25. Here is the calculation.
|
||||
homework_1_score = 1.0 / 2
|
||||
homework_2_score = 0.0
|
||||
self.check_grade_percent(round((homework_1_score + homework_2_score) / 2, 2))
|
||||
# Grade percent is .25. Here is the calculation:
|
||||
# homework_1_score = 1.0 / 2
|
||||
# homework_2_score = 0.0
|
||||
# round((homework_1_score + homework_2_score) / 2) == .25
|
||||
self.check_grade_percent(.25)
|
||||
|
||||
def test_split_one_group_no_problems_group_1(self):
|
||||
"""
|
||||
@@ -1256,6 +1259,7 @@ class TestConditionalContent(TestSubmittingProblems):
|
||||
self.assertEqual(self.earned_hw_scores(), [1.0, 1.0])
|
||||
|
||||
# Grade percent is .75. Here is the calculation.
|
||||
homework_1_score = 1.0 / 2
|
||||
homework_2_score = 1.0 / 1
|
||||
self.check_grade_percent(round((homework_1_score + homework_2_score) / 2, 2))
|
||||
# homework_1_score = 1.0 / 2
|
||||
# homework_2_score = 1.0 / 1
|
||||
# round((homework_1_score + homework_2_score) / 2) == .75
|
||||
self.check_grade_percent(.75)
|
||||
|
||||
@@ -973,7 +973,7 @@ class TestStudioTranscriptTranslationPostDispatch(TestVideo):
|
||||
request = Request.blank('/translation', POST=post_data)
|
||||
response = self.item_descriptor.studio_transcript(request=request, dispatch='translation')
|
||||
self.assertEqual(response.status, '201 Created')
|
||||
response = json.loads(response.body)
|
||||
response = json.loads(response.text)
|
||||
self.assertTrue(response["language_code"], "uk")
|
||||
self.assertDictEqual(self.item_descriptor.transcripts, {})
|
||||
self.assertTrue(edxval_api.get_video_transcript_data(video_id=response["edx_video_id"], language_code="uk"))
|
||||
|
||||
@@ -243,7 +243,7 @@ class TestWordCloud(BaseTestXmodule):
|
||||
|
||||
for user in self.users:
|
||||
self.assertDictEqual(
|
||||
json.loads(responses[user.username].content),
|
||||
json.loads(responses[user.username].content.decode('utf-8')),
|
||||
{
|
||||
'status': 'fail',
|
||||
'error': 'Unknown Command!'
|
||||
|
||||
@@ -30,7 +30,7 @@ class AjaxExceptionTestCase(TestCase):
|
||||
self.assertEqual(self.exception1.status_code, response1.status_code)
|
||||
self.assertEqual(
|
||||
{"errors": json.loads(text_type(self.exception1))},
|
||||
json.loads(response1.content)
|
||||
json.loads(response1.content.decode('utf-8'))
|
||||
)
|
||||
|
||||
response2 = self.a.process_exception(self.request1, self.exception2)
|
||||
@@ -38,7 +38,7 @@ class AjaxExceptionTestCase(TestCase):
|
||||
self.assertEqual(self.exception2.status_code, response2.status_code)
|
||||
self.assertEqual(
|
||||
{"errors": [text_type(self.exception2)]},
|
||||
json.loads(response2.content)
|
||||
json.loads(response2.content.decode('utf-8'))
|
||||
)
|
||||
|
||||
self.assertIsNone(self.a.process_exception(self.request1, self.exception0))
|
||||
|
||||
@@ -33,7 +33,7 @@ class TestDashboardError(unittest.TestCase):
|
||||
"""
|
||||
def test_response(self):
|
||||
error = tools.DashboardError(u'Oh noes!')
|
||||
response = json.loads(error.response().content)
|
||||
response = json.loads(error.response().content.decode('utf-8'))
|
||||
self.assertEqual(response, {'error': 'Oh noes!'})
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class TestHandleDashboardError(unittest.TestCase):
|
||||
"""
|
||||
raise tools.DashboardError("Oh noes!")
|
||||
|
||||
response = json.loads(view(None, None).content)
|
||||
response = json.loads(view(None, None).content.decode('utf-8'))
|
||||
self.assertEqual(response, {'error': 'Oh noes!'})
|
||||
|
||||
def test_no_error(self):
|
||||
|
||||
@@ -175,8 +175,8 @@ def generate_signed_message(method, headers_dict, body_dict, access_key, secret_
|
||||
message = signing_format_message(method, headers_dict, body_dict)
|
||||
|
||||
# hmac needs a byte string for it's starting key, can't be unicode.
|
||||
hashed = hmac.new(secret_key.encode('utf-8'), message, sha256)
|
||||
signature = binascii.b2a_base64(hashed.digest()).rstrip('\n')
|
||||
hashed = hmac.new(secret_key.encode('utf-8'), message.encode('utf-8'), sha256)
|
||||
signature = binascii.b2a_base64(hashed.digest()).rstrip(b'\n')
|
||||
authorization_header = u"SSI {}:{}".format(access_key, signature)
|
||||
|
||||
message += '\n'
|
||||
@@ -223,12 +223,12 @@ def body_string(body_dict, prefix=""):
|
||||
if isinstance(arr, dict):
|
||||
body_list.append(body_string(arr, u"{}.{}.".format(key, i)))
|
||||
else:
|
||||
body_list.append(u"{}.{}:{}\n".format(key, i, arr).encode('utf-8'))
|
||||
body_list.append(u"{}.{}:{}\n".format(key, i, arr))
|
||||
elif isinstance(value, dict):
|
||||
body_list.append(body_string(value, key + ":"))
|
||||
else:
|
||||
if value is None:
|
||||
value = "null"
|
||||
body_list.append(u"{}{}:{}\n".format(prefix, key, value).encode('utf-8'))
|
||||
body_list.append(u"{}{}:{}\n".format(prefix, key, value))
|
||||
|
||||
return "".join(body_list) # Note that trailing \n's are important
|
||||
|
||||
@@ -1298,7 +1298,7 @@ class TestCheckoutWithEcommerceService(ModuleStoreTestCase):
|
||||
self.assertTrue(mock_audit_log.called)
|
||||
|
||||
# Check the api call
|
||||
self.assertEqual(json.loads(httpretty.last_request().body), {
|
||||
self.assertEqual(json.loads(httpretty.last_request().body.decode('utf-8')), {
|
||||
'products': [{'sku': 'test-sku'}],
|
||||
'checkout': True,
|
||||
'payment_processor_name': 'test-processor',
|
||||
@@ -1845,7 +1845,7 @@ class TestPhotoVerificationResultsCallback(ModuleStoreTestCase):
|
||||
self.assertEqual(attempt.status, u'denied')
|
||||
self.assertEqual(attempt.error_code, u'Your photo doesn\'t meet standards.')
|
||||
self.assertEqual(attempt.error_msg, u'[{"photoIdReasons": ["Not provided"]}]')
|
||||
self.assertEquals(response.content, 'OK!')
|
||||
self.assertEquals(response.content.decode('utf-8'), 'OK!')
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
|
||||
@patch(
|
||||
|
||||
@@ -1113,7 +1113,7 @@ def results_callback(request):
|
||||
body = request.body
|
||||
|
||||
try:
|
||||
body_dict = json.loads(body)
|
||||
body_dict = json.loads(body.decode('utf-8'))
|
||||
except ValueError:
|
||||
log.exception(u"Invalid JSON received from Software Secure:\n\n{}\n".format(body))
|
||||
return HttpResponseBadRequest(u"Invalid JSON. Received:\n\n{}".format(body))
|
||||
|
||||
@@ -105,7 +105,7 @@ class LmsSearchFilterGeneratorTestCase(ModuleStoreTestCase):
|
||||
self.assertEqual('LogistrationX', exclude_orgs[0])
|
||||
self.assertEqual('TestSiteX', exclude_orgs[1])
|
||||
|
||||
@patch('openedx.core.djangoapps.site_configuration.helpers.get_all_orgs', Mock(return_value=[]))
|
||||
@patch('openedx.core.djangoapps.site_configuration.helpers.get_all_orgs', Mock(return_value=set()))
|
||||
def test_no_excludes_with_no_orgs(self):
|
||||
""" Test when no org is present - nothing to exclude """
|
||||
_, _, exclude_dictionary = LmsSearchFilterGenerator.generate_field_filters(user=self.user)
|
||||
@@ -120,7 +120,7 @@ class LmsSearchFilterGeneratorTestCase(ModuleStoreTestCase):
|
||||
|
||||
@patch(
|
||||
'openedx.core.djangoapps.site_configuration.helpers.get_all_orgs',
|
||||
Mock(return_value=["TestSite1", "TestSite2", "TestSite3", "TestSite4"])
|
||||
Mock(return_value={"TestSite1", "TestSite2", "TestSite3", "TestSite4"})
|
||||
)
|
||||
def test_excludes_multi_orgs(self):
|
||||
_, _, exclude_dictionary = LmsSearchFilterGenerator.generate_field_filters(user=self.user)
|
||||
@@ -134,7 +134,7 @@ class LmsSearchFilterGeneratorTestCase(ModuleStoreTestCase):
|
||||
|
||||
@patch(
|
||||
'openedx.core.djangoapps.site_configuration.helpers.get_all_orgs',
|
||||
Mock(return_value=["TestSite1", "TestSite2", "TestSite3", "TestSite4"])
|
||||
Mock(return_value={"TestSite1", "TestSite2", "TestSite3", "TestSite4"})
|
||||
)
|
||||
@patch('openedx.core.djangoapps.site_configuration.helpers.get_value', Mock(return_value='TestSite3'))
|
||||
def test_excludes_multi_orgs_within(self):
|
||||
|
||||
@@ -50,7 +50,7 @@ class AccessTokenExchangeFormTest(AccessTokenExchangeTestMixin):
|
||||
self.assertTrue(form.is_valid())
|
||||
self.assertEqual(form.cleaned_data["user"], self.user)
|
||||
self.assertEqual(form.cleaned_data["client"], self.oauth_client)
|
||||
self.assertEqual(scope.to_names(form.cleaned_data["scope"]), expected_scopes)
|
||||
self.assertEqual(set(scope.to_names(form.cleaned_data["scope"])), set(expected_scopes))
|
||||
|
||||
|
||||
# This is necessary because cms does not implement third party auth
|
||||
|
||||
@@ -63,11 +63,16 @@ class AccessTokenExchangeViewTest(AccessTokenExchangeTestMixin):
|
||||
timedelta(seconds=int(content["expires_in"])),
|
||||
provider.constants.EXPIRE_DELTA_PUBLIC
|
||||
)
|
||||
self.assertEqual(content["scope"], ' '.join(expected_scopes))
|
||||
actual_scopes = content["scope"]
|
||||
if actual_scopes:
|
||||
actual_scopes = actual_scopes.split(' ')
|
||||
else:
|
||||
actual_scopes = []
|
||||
self.assertEqual(set(actual_scopes), set(expected_scopes))
|
||||
token = self.oauth2_adapter.get_access_token(token_string=content["access_token"])
|
||||
self.assertEqual(token.user, self.user)
|
||||
self.assertEqual(self.oauth2_adapter.get_client_for_token(token), self.oauth_client)
|
||||
self.assertEqual(self.oauth2_adapter.get_token_scope_names(token), expected_scopes)
|
||||
self.assertEqual(set(self.oauth2_adapter.get_token_scope_names(token)), set(expected_scopes))
|
||||
|
||||
def test_single_access_token(self):
|
||||
def extract_token(response):
|
||||
@@ -184,7 +189,7 @@ class TestLoginWithAccessTokenView(TestCase):
|
||||
Calls the login_with_access_token endpoint and verifies the response given the expected values.
|
||||
"""
|
||||
url = reverse("login_with_access_token")
|
||||
response = self.client.post(url, HTTP_AUTHORIZATION=b"Bearer {0}".format(access_token))
|
||||
response = self.client.post(url, HTTP_AUTHORIZATION=u"Bearer {0}".format(access_token).encode('utf-8'))
|
||||
self.assertEqual(response.status_code, expected_status_code)
|
||||
if expected_cookie_name:
|
||||
self.assertIn(expected_cookie_name, response.cookies)
|
||||
|
||||
@@ -10,7 +10,6 @@ import ddt
|
||||
import mock
|
||||
import six
|
||||
from django.core.management import call_command
|
||||
from django.utils import six
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
|
||||
@@ -230,6 +229,12 @@ class TestDumpToNeo4jCommand(TestDumpToNeo4jCommandBase):
|
||||
)
|
||||
|
||||
|
||||
class SomeThing(object):
|
||||
"""Just to test the stringification of an object."""
|
||||
def __str__(self):
|
||||
return "<SomeThing>"
|
||||
|
||||
|
||||
@skip_unless_lms
|
||||
@ddt.ddt
|
||||
class TestModuleStoreSerializer(TestDumpToNeo4jCommandBase):
|
||||
@@ -379,7 +384,7 @@ class TestModuleStoreSerializer(TestDumpToNeo4jCommandBase):
|
||||
|
||||
@ddt.data(
|
||||
(1, 1),
|
||||
(object, "<type 'object'>"),
|
||||
(SomeThing(), "<SomeThing>"),
|
||||
(1.5, 1.5),
|
||||
("úñîçø∂é", "úñîçø∂é"),
|
||||
(b"plain string", b"plain string"),
|
||||
@@ -388,7 +393,8 @@ class TestModuleStoreSerializer(TestDumpToNeo4jCommandBase):
|
||||
((1,), "(1,)"),
|
||||
# list of elements should be coerced into a list of the
|
||||
# string representations of those elements
|
||||
([object, object], ["<type 'object'>", "<type 'object'>"])
|
||||
([SomeThing(), SomeThing()], ["<SomeThing>", "<SomeThing>"]),
|
||||
([1, 2], ["1", "2"]),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_coerce_types(self, original_value, coerced_expected):
|
||||
|
||||
@@ -36,7 +36,7 @@ def get_shared_secret_key(provider_id):
|
||||
|
||||
if isinstance(secret, six.text_type):
|
||||
try:
|
||||
secret = str(secret)
|
||||
secret.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
secret = None
|
||||
log.error(u'Shared secret key for credit provider "%s" contains non-ASCII unicode.', provider_id)
|
||||
|
||||
@@ -8,6 +8,7 @@ from datetime import datetime
|
||||
|
||||
import six
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django_mysql.models import ListCharField
|
||||
from oauth2_provider.settings import oauth2_settings
|
||||
@@ -19,6 +20,7 @@ from openedx.core.djangolib.markup import HTML
|
||||
from openedx.core.lib.request_utils import get_request_or_stub
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class RestrictedApplication(models.Model):
|
||||
"""
|
||||
This model lists which django-oauth-toolkit Applications are considered 'restricted'
|
||||
@@ -35,7 +37,7 @@ class RestrictedApplication(models.Model):
|
||||
class Meta:
|
||||
app_label = 'oauth_dispatch'
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
"""
|
||||
Return a unicode representation of this object
|
||||
"""
|
||||
@@ -59,6 +61,7 @@ class RestrictedApplication(models.Model):
|
||||
return access_token.expires == datetime(1970, 1, 1, tzinfo=utc)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class ApplicationAccess(models.Model):
|
||||
"""
|
||||
Specifies access control information for the associated Application.
|
||||
@@ -81,7 +84,7 @@ class ApplicationAccess(models.Model):
|
||||
def get_scopes(cls, application):
|
||||
return cls.objects.get(application=application).scopes
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
"""
|
||||
Return a unicode representation of this object.
|
||||
"""
|
||||
@@ -91,6 +94,7 @@ class ApplicationAccess(models.Model):
|
||||
)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class ApplicationOrganization(models.Model):
|
||||
"""
|
||||
Associates a DOT Application to an Organization.
|
||||
@@ -129,7 +133,7 @@ class ApplicationOrganization(models.Model):
|
||||
queryset = queryset.filter(relation_type=relation_type)
|
||||
return [r.organization.name for r in queryset]
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
"""
|
||||
Return a unicode representation of this object.
|
||||
"""
|
||||
|
||||
@@ -63,7 +63,7 @@ class AccessTokenLoginMixin(object):
|
||||
|
||||
return self.client.post(
|
||||
self.login_with_access_token_url,
|
||||
HTTP_AUTHORIZATION=b"Bearer {0}".format(access_token if access_token else self.access_token)
|
||||
HTTP_AUTHORIZATION=u"Bearer {0}".format(access_token if access_token else self.access_token).encode('utf-8')
|
||||
)
|
||||
|
||||
def _assert_access_token_is_valid(self, access_token=None):
|
||||
|
||||
@@ -210,7 +210,7 @@ def get_all_orgs():
|
||||
This can be used, for example, to do filtering.
|
||||
|
||||
Returns:
|
||||
A list of all organizations present in the site configuration.
|
||||
A set of all organizations present in the site configuration.
|
||||
"""
|
||||
# Import is placed here to avoid model import at project startup.
|
||||
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
|
||||
|
||||
@@ -114,7 +114,7 @@ class SiteConfiguration(models.Model):
|
||||
for example, to do filtering.
|
||||
|
||||
Returns:
|
||||
A list of all organizations present in site configuration.
|
||||
A set of all organizations present in site configuration.
|
||||
"""
|
||||
org_filter_set = set()
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ Tests for site configuration's django models.
|
||||
from __future__ import absolute_import
|
||||
|
||||
from mock import patch
|
||||
import six
|
||||
|
||||
from django.test import TestCase
|
||||
from django.db import IntegrityError, transaction
|
||||
@@ -321,10 +322,7 @@ class SiteConfigurationTests(TestCase):
|
||||
)
|
||||
|
||||
# Test that the default value is returned if the value for the given key is not found in the configuration
|
||||
self.assertListEqual(
|
||||
list(SiteConfiguration.get_all_orgs()),
|
||||
expected_orgs,
|
||||
)
|
||||
six.assertCountEqual(self, SiteConfiguration.get_all_orgs(), expected_orgs)
|
||||
|
||||
def test_get_all_orgs_returns_only_enabled(self):
|
||||
"""
|
||||
@@ -343,7 +341,4 @@ class SiteConfigurationTests(TestCase):
|
||||
)
|
||||
|
||||
# Test that the default value is returned if the value for the given key is not found in the configuration
|
||||
self.assertListEqual(
|
||||
list(SiteConfiguration.get_all_orgs()),
|
||||
expected_orgs,
|
||||
)
|
||||
six.assertCountEqual(self, SiteConfiguration.get_all_orgs(), expected_orgs)
|
||||
|
||||
@@ -225,13 +225,13 @@ class StudentViewShimTest(TestCase):
|
||||
)
|
||||
response = view(HttpRequest())
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.content, "third-party-auth")
|
||||
self.assertEqual(response.content, b"third-party-auth")
|
||||
|
||||
def test_non_json_response(self):
|
||||
view = self._shimmed_view(HttpResponse(content="Not a JSON dict"))
|
||||
response = view(HttpRequest())
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, "Not a JSON dict")
|
||||
self.assertEqual(response.content, b"Not a JSON dict")
|
||||
|
||||
@ddt.data("redirect", "redirect_url")
|
||||
def test_ignore_redirect_from_json(self, redirect_key):
|
||||
@@ -254,7 +254,7 @@ class StudentViewShimTest(TestCase):
|
||||
)
|
||||
response = view(HttpRequest())
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.content, "Error!")
|
||||
self.assertEqual(response.content, b"Error!")
|
||||
|
||||
def test_preserve_headers(self):
|
||||
view_response = HttpResponse()
|
||||
|
||||
@@ -8,6 +8,7 @@ from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
|
||||
import six
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import authenticate
|
||||
from django.contrib.auth import login as django_login
|
||||
@@ -110,11 +111,11 @@ def _enforce_password_policy_compliance(request, user):
|
||||
password_policy_compliance.enforce_compliance_on_login(user, request.POST.get('password'))
|
||||
except password_policy_compliance.NonCompliantPasswordWarning as e:
|
||||
# Allow login, but warn the user that they will be required to reset their password soon.
|
||||
PageLevelMessages.register_warning_message(request, e.message)
|
||||
PageLevelMessages.register_warning_message(request, six.text_type(e))
|
||||
except password_policy_compliance.NonCompliantPasswordException as e:
|
||||
send_password_reset_email_for_user(user, request)
|
||||
# Prevent the login attempt.
|
||||
raise AuthFailedError(e.message)
|
||||
raise AuthFailedError(six.text_type(e))
|
||||
|
||||
|
||||
def _generate_not_activated_message(user):
|
||||
|
||||
@@ -323,7 +323,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
|
||||
visible=True,
|
||||
enabled=True,
|
||||
icon_class='',
|
||||
icon_image=SimpleUploadedFile('icon.svg', '<svg><rect width="50" height="100"/></svg>'),
|
||||
icon_image=SimpleUploadedFile('icon.svg', b'<svg><rect width="50" height="100"/></svg>'),
|
||||
)
|
||||
self.hidden_enabled_provider = self.configure_linkedin_provider(
|
||||
visible=False,
|
||||
@@ -606,7 +606,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
|
||||
tpa_hint = self.hidden_disabled_provider.provider_id
|
||||
params = [("next", "/courses/something/?tpa_hint={0}".format(tpa_hint))]
|
||||
response = self.client.get(reverse('signin_user'), params, HTTP_ACCEPT="text/html")
|
||||
self.assertNotIn(response.content, tpa_hint)
|
||||
self.assertNotIn(response.content.decode('utf-8'), tpa_hint)
|
||||
|
||||
@ddt.data(
|
||||
('signin_user', 'login'),
|
||||
@@ -650,7 +650,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
|
||||
tpa_hint = self.hidden_disabled_provider.provider_id
|
||||
params = [("next", "/courses/something/?tpa_hint={0}".format(tpa_hint))]
|
||||
response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html")
|
||||
self.assertNotIn(response.content, tpa_hint)
|
||||
self.assertNotIn(response.content.decode('utf-8'), tpa_hint)
|
||||
|
||||
@override_settings(FEATURES=dict(settings.FEATURES, THIRD_PARTY_AUTH_HINT='oa2-google-oauth2'))
|
||||
@ddt.data(
|
||||
|
||||
@@ -10,6 +10,7 @@ from config_models.models import ConfigurationModel
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save, pre_save
|
||||
from django.dispatch import receiver
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy
|
||||
from edx_django_utils.cache import RequestCache
|
||||
from opaque_keys.edx.django.models import CourseKeyField
|
||||
@@ -92,6 +93,7 @@ def pre_save_callback(sender, instance, **kwargs): # pylint: disable=unused-arg
|
||||
instance._old_mode = None # pylint: disable=protected-access
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class VerifiedTrackCohortedCourse(models.Model):
|
||||
"""
|
||||
Tracks which courses have verified track auto-cohorting enabled.
|
||||
@@ -109,7 +111,7 @@ class VerifiedTrackCohortedCourse(models.Model):
|
||||
|
||||
CACHE_NAMESPACE = u"verified_track_content.VerifiedTrackCohortedCourse.cache."
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return u"Course: {}, enabled: {}".format(six.text_type(self.course_key), self.enabled)
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
"""Tests for zendesk_proxy views."""
|
||||
from __future__ import absolute_import
|
||||
import json
|
||||
|
||||
from copy import deepcopy
|
||||
import json
|
||||
|
||||
import ddt
|
||||
from django.urls import reverse
|
||||
from django.test.utils import override_settings
|
||||
from mock import MagicMock, patch
|
||||
import six
|
||||
from six.moves import range
|
||||
|
||||
from openedx.core.djangoapps.zendesk_proxy.v0.views import ZENDESK_REQUESTS_PER_HOUR
|
||||
from openedx.core.lib.api.test_utils import ApiTestCase
|
||||
from six.moves import range
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -45,14 +47,30 @@ class ZendeskProxyTestCase(ApiTestCase):
|
||||
self.assertHttpCreated(response)
|
||||
(mock_args, mock_kwargs) = mock_post.call_args
|
||||
self.assertEqual(mock_args, ('https://www.superrealurlsthataredefinitelynotfake.com/api/v2/tickets.json',))
|
||||
six.assertCountEqual(self, mock_kwargs.keys(), ['headers', 'data'])
|
||||
self.assertEqual(
|
||||
mock_kwargs,
|
||||
mock_kwargs['headers'],
|
||||
{
|
||||
'headers': {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer abcdefghijklmnopqrstuvwxyz1234567890'
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer abcdefghijklmnopqrstuvwxyz1234567890'
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
json.loads(mock_kwargs['data']),
|
||||
{
|
||||
'ticket': {
|
||||
'comment': {
|
||||
'body': "Help! I'm trapped in a unit test factory and I can't get out!",
|
||||
'uploads': None,
|
||||
},
|
||||
'custom_fields': None,
|
||||
'requester': {
|
||||
'email': 'JohnQStudent@example.com',
|
||||
'name': 'John Q. Student',
|
||||
},
|
||||
'subject': 'Python Unit Test Help Request',
|
||||
'tags': ['python_unit_test'],
|
||||
},
|
||||
'data': '{"ticket": {"comment": {"body": "Help! I\'m trapped in a unit test factory and I can\'t get out!", "uploads": null}, "tags": ["python_unit_test"], "subject": "Python Unit Test Help Request", "custom_fields": null, "requester": {"name": "John Q. Student", "email": "JohnQStudent@example.com"}}}' # pylint: disable=line-too-long
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
"""Tests for zendesk_proxy views."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
import json
|
||||
|
||||
from copy import deepcopy
|
||||
import json
|
||||
|
||||
import ddt
|
||||
from django.urls import reverse
|
||||
from django.test.utils import override_settings
|
||||
from mock import MagicMock, patch
|
||||
import six
|
||||
from six.moves import range
|
||||
|
||||
from openedx.core.djangoapps.zendesk_proxy.v1.views import ZendeskProxyThrottle
|
||||
from openedx.core.lib.api.test_utils import ApiTestCase
|
||||
from six.moves import range
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -53,14 +56,30 @@ class ZendeskProxyTestCase(ApiTestCase):
|
||||
self.assertHttpCreated(response)
|
||||
(mock_args, mock_kwargs) = mock_post.call_args
|
||||
self.assertEqual(mock_args, ('https://www.superrealurlsthataredefinitelynotfake.com/api/v2/tickets.json',))
|
||||
six.assertCountEqual(self, mock_kwargs.keys(), ['headers', 'data'])
|
||||
self.assertEqual(
|
||||
mock_kwargs,
|
||||
mock_kwargs['headers'],
|
||||
{
|
||||
'headers': {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer abcdefghijklmnopqrstuvwxyz1234567890'
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer abcdefghijklmnopqrstuvwxyz1234567890'
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
json.loads(mock_kwargs['data']),
|
||||
{
|
||||
'ticket': {
|
||||
'comment': {
|
||||
'body': "Help! I'm trapped in a unit test factory and I can't get out!",
|
||||
'uploads': None,
|
||||
},
|
||||
'custom_fields': [{'id': '001', 'value': 'demo-course'}],
|
||||
'requester': {
|
||||
'email': 'JohnQStudent@example.com',
|
||||
'name': 'John Q. Student',
|
||||
},
|
||||
'subject': 'Python Unit Test Help Request',
|
||||
'tags': ['python_unit_test'],
|
||||
},
|
||||
'data': '{"ticket": {"comment": {"body": "Help! I\'m trapped in a unit test factory and I can\'t get out!", "uploads": null}, "tags": ["python_unit_test"], "subject": "Python Unit Test Help Request", "custom_fields": [{"id": "001", "value": "demo-course"}], "requester": {"name": "John Q. Student", "email": "JohnQStudent@example.com"}}}' # pylint: disable=line-too-long
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user