Merge branch 'master' into jill/log-heartbeat-failures

This commit is contained in:
Jillian Vogel
2020-02-22 21:36:07 +10:30
3437 changed files with 157956 additions and 143508 deletions

View File

@@ -131,36 +131,6 @@ djcelery.WorkerState:
edx_oauth2_provider.TrustedClient:
".. no_pii:": "No PII"
# Via Proctoring
edx_proctoring.ProctoredExam:
".. no_pii:": "No PII"
edx_proctoring.ProctoredExamReviewPolicy:
".. no_pii:": "No PII"
edx_proctoring.ProctoredExamReviewPolicyHistory:
".. no_pii:": "No PII"
edx_proctoring.ProctoredExamSoftwareSecureComment:
".. no_pii:": "No PII"
edx_proctoring.ProctoredExamSoftwareSecureReview:
".. pii:": "Proctored exam review feedback from Software Secure, contains video_url. Retained for record keeping."
".. pii_types:": video
".. pii_retirement:": retained
edx_proctoring.ProctoredExamSoftwareSecureReviewHistory:
".. pii:": "Proctored exam review feedback from Software Secure, contains video_url. Retained for record keeping."
".. pii_types:": video
".. pii_retirement:": retained
edx_proctoring.ProctoredExamStudentAllowance:
".. no_pii:": "No PII"
edx_proctoring.ProctoredExamStudentAllowanceHistory:
".. no_pii:": "No PII"
edx_proctoring.ProctoredExamStudentAttempt:
".. pii:": "Tracks attempts by a user to take a proctored exam. Contains student_name. Retained for record keeping."
".. pii_types:": name
".. pii_retirement:": retained
edx_proctoring.ProctoredExamStudentAttemptHistory:
".. pii:": "Tracks attempts by a user to take a proctored exam. Contains student_name. Retained for record keeping."
".. pii_types:": name
".. pii_retirement:": retained
# Via VAL
edxval.CourseVideo:
".. no_pii:": "No PII"

View File

@@ -30,6 +30,7 @@ omit =
concurrency=multiprocessing
parallel = true
relative_files = true
[report]
ignore_errors = True

View File

@@ -1,7 +1,7 @@
source_path: ./
report_path: pii_report
safelist_path: .annotation_safe_list.yml
coverage_target: 100.0
coverage_target: 94.5
# See OEP-30 for more information on these values and what they mean:
# https://open-edx-proposals.readthedocs.io/en/latest/oep-0030-arch-pii-markup-and-auditing.html#docstring-annotations
annotations:

View File

@@ -22,10 +22,9 @@ JIRA
----
If you've got an idea for a new feature or new functionality for an existing feature,
please start a discussion on the `edx-code`_ mailing list to get feedback from
the community about the idea and your implementation choices.
.. _edx-code: https://groups.google.com/forum/#!forum/edx-code
please start a discussion in the `development <https://discuss.openedx.org/c/development>`__
category of the discussion forum list to get feedback from the community about the idea
and your implementation choices.
If you then plan to contribute your code upstream, please `start a discussion on JIRA`_
(you may first need to `create a free JIRA account`_).
@@ -33,14 +32,31 @@ Start a discussion by visiting the JIRA website and clicking the "Create" button
top of the page. Choose the project "Open Source Pull Requests" and the issue type
"Feature Proposal". In the description give us as much detail as you can for the feature
or functionality you are thinking about implementing. Include a link to any relevant
edx-code mailing list discussions about your idea. We encourage you to do this before
you begin implementing your feature, in order to get valuable feedback from the edX
product team early on in your journey and increase the likelihood of a successful
pull request.
forum discussions about your idea. We encourage you to do this before you begin
implementing your feature, in order to get valuable feedback from the edX product team
early on in your journey and increase the likelihood of a successful pull request.
.. _start a discussion on JIRA: https://openedx.atlassian.net/secure/Dashboard.jspa
.. _create a free JIRA account: https://openedx.atlassian.net/admin/users/sign-up
.. _forum:
Discussion forum
----------------
To ask technical questions and chat with the community, do not hesitate to join the
`Open edX discussion forum <https://discuss.openedx.org/>`__. There are different
categories for different topics:
- `Devops <https://discuss.openedx.org/c/devops>`__ for installation help
- `Development <https://discuss.openedx.org/c/development>`__, where Open edX developers
unite
- `Community <https://discuss.openedx.org/c/community>`__ to discuss organizational
matters in the open source community
- `Announcements <https://discuss.openedx.org/c/announcements>`__ where official Open edX
announcement are made
- `Educators <https://discuss.openedx.org/c/educators>`__, to discuss online learning in general
Slack
-----
@@ -51,34 +67,17 @@ between 13:00 and 21:00 UTC (9am to 5pm US Eastern time),
but interesting conversations can happen at any time.
There are many different channels available for different topics, including:
* ``#ops`` for installation help
* ``#events`` for upcoming events related to Open edX
* ``#content`` for discussions about course content and creating the best courses
And lots more! You can also make your own channels to discuss new topics.
Note that Slack is no longer the recommended communication channel to ask about
technical issues. To do so, you should instead join the `official forum <#forum>`__.
.. _Slack: https://slack.com/
.. _Sign up for a free account: https://openedx-slack-invite.herokuapp.com/
Mailing Lists
-------------
For asynchronous conversation, we have several mailing lists on Google Groups:
* `openedx-ops`_: everything related to *running* Open edX. This includes
installation issues, server management, cost analysis, and so on.
* `openedx-translation`_: everything related to *translating* Open edX into
other languages. This includes volunteer translators, our internationalization
infrastructure, issues related to Transifex, and so on.
* `openedx-analytics`_: everything related to *analytics* in Open edX.
* `edx-code`_: everything related to the *code* in Open edX. This includes
feature requests, idea proposals, refactorings, and so on.
.. _openedx-ops: https://groups.google.com/forum/#!forum/openedx-ops
.. _openedx-translation: https://groups.google.com/forum/#!forum/openedx-translation
.. _openedx-analytics: https://groups.google.com/forum/#!forum/openedx-analytics
.. _edx-code: https://groups.google.com/forum/#!forum/edx-code
Byte-sized Tasks & Bugs
-----------------------
@@ -195,7 +194,7 @@ By opening up a pull request, we expect the following things:
unable to participate in the review process.
3. If you have questions, you will ask them by either commenting on the pull
request or asking us in Slack or on the mailing list.
request or asking us in the discussion forum or on Slack.
4. If you do not respond to comments on your pull request within 7 days, we
will close it. You are welcome to re-open it when you are ready to engage.

View File

@@ -24,11 +24,13 @@ SWAGGER = docs/swagger.yaml
docs: api-docs guides ## build all the developer documentation for this repository
swagger: ## generate the swagger.yaml file
DJANGO_SETTINGS_MODULE=docs.docs_settings python manage.py lms generate_swagger --generator-class=openedx.core.apidocs.ApiSchemaGenerator -o $(SWAGGER)
DJANGO_SETTINGS_MODULE=docs.docs_settings python manage.py lms generate_swagger --generator-class=edx_api_doc_tools.ApiSchemaGenerator -o $(SWAGGER)
api-docs: swagger ## build the REST api docs
api-docs-sphinx: swagger ## generate the sphinx source files for api-docs
rm -f docs/api/gen/*
python docs/sw2md.py $(SWAGGER) docs/api/gen
python docs/sw2sphinxopenapi.py $(SWAGGER) docs/api/gen
api-docs: api-docs-sphinx ## build the REST api docs
cd docs/api; make html
guides: ## build the developer guide docs
@@ -50,6 +52,7 @@ pull_translations: ## pull translations from Transifex
git clean -fdX conf/locale/eo
i18n_tool validate
detect_changed_source_translations: ## check if translation files are up-to-date
i18n_tool changed
@@ -72,7 +75,7 @@ REQ_FILES = \
requirements/edx/coverage \
requirements/edx/paver \
requirements/edx-sandbox/shared \
requirements/edx-sandbox/base \
requirements/edx-sandbox/py35 \
requirements/edx/base \
requirements/edx/testing \
requirements/edx/development \
@@ -88,7 +91,7 @@ upgrade: ## update the pip requirements files to use the latest releases satisfy
done
# Post process all of the files generated above to work around open pip-tools issues
scripts/post-pip-compile.sh $(REQ_FILES:=.txt)
# Let tox control the Django version for tests
grep "^django==" requirements/edx/base.txt > requirements/edx/django.txt
sed '/^[dD]jango==/d' requirements/edx/testing.txt > requirements/edx/testing.tmp
# Let tox control the Django version & django-oauth-toolkit version for tests
grep -e "^django==" -e "^django-oauth-toolkit==" requirements/edx/base.txt > requirements/edx/django.txt
sed '/^[dD]jango==/d;/^django-oauth-toolkit==/d' requirements/edx/testing.txt > requirements/edx/testing.tmp
mv requirements/edx/testing.tmp requirements/edx/testing.txt

View File

@@ -2,7 +2,7 @@
Celery needs to be loaded when the cms modules are so that task
registration and discovery can work correctly.
"""
from __future__ import absolute_import
# We monkey patch Kombu's entrypoints listing because scanning through this
# accounts for the majority of LMS/Studio startup time for tests, and we don't

View File

@@ -4,7 +4,7 @@ and auto discover tasks in all installed django apps.
Taken from: https://celery.readthedocs.org/en/latest/django/first-steps-with-django.html
"""
from __future__ import absolute_import
import os

View File

@@ -6,13 +6,15 @@ pytest from looking for the conftest.py module in the parent directory when
only running cms tests.
"""
from __future__ import absolute_import, unicode_literals
import importlib
import os
import logging
import contracts
import pytest
from openedx.core.pytest_hooks import DeferPlugin
# Patch the xml libs before anything else.
from safe_lxml import defuse_xml_libs
@@ -23,6 +25,11 @@ def pytest_configure(config):
"""
Do core setup operations from manage.py before collecting tests.
"""
if config.pluginmanager.hasplugin("pytest_jsonreport") or config.pluginmanager.hasplugin("json-report"):
config.pluginmanager.register(DeferPlugin())
else:
logging.info("pytest did not register json_report correctly")
if config.getoption('help'):
return
enable_contracts = os.environ.get('ENABLE_CONTRACTS', False)

View File

@@ -2,7 +2,6 @@
Configuration for Studio API Django application
"""
from __future__ import absolute_import
from django.apps import AppConfig

View File

@@ -2,10 +2,12 @@
URLs for the Studio API app
"""
from __future__ import absolute_import
from django.conf.urls import include, url
app_name = 'cms.djangoapps.api'
urlpatterns = [
url(r'^v1/', include('cms.djangoapps.api.v1.urls', namespace='v1')),
]

View File

@@ -1,5 +1,5 @@
""" Course run serializers. """
from __future__ import absolute_import
import logging
import time # pylint: disable=unused-import

View File

@@ -1,6 +1,5 @@
"""Tests for course run serializers"""
from __future__ import absolute_import
import datetime

View File

@@ -1,6 +1,5 @@
"""Tests for Course run views"""
from __future__ import absolute_import
import datetime

View File

@@ -2,12 +2,13 @@
URLs for the Studio API [Course Run]
"""
from __future__ import absolute_import
from rest_framework.routers import DefaultRouter
from .views.course_runs import CourseRunViewSet
app_name = 'cms.djangoapps.api.v1'
router = DefaultRouter()
router.register(r'course_runs', CourseRunViewSet, base_name='course_run')
router.register(r'course_runs', CourseRunViewSet, basename='course_run')
urlpatterns = router.urls

View File

@@ -1,6 +1,5 @@
"""HTTP endpoints for the Course Run API."""
from __future__ import absolute_import
from django.conf import settings
from django.http import Http404
@@ -8,7 +7,7 @@ from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthenticat
from opaque_keys.edx.keys import CourseKey
from rest_framework import parsers, permissions, status, viewsets
from rest_framework.authentication import SessionAuthentication
from rest_framework.decorators import detail_route
from rest_framework.decorators import action
from rest_framework.response import Response
from contentstore.views.course import _accessible_courses_iter, get_course_and_check_access
@@ -75,7 +74,8 @@ class CourseRunViewSet(viewsets.GenericViewSet):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
@detail_route(
@action(
detail=True,
methods=['post', 'put'],
parser_classes=(parsers.FormParser, parsers.MultiPartParser,),
serializer_class=CourseRunImageSerializer)
@@ -86,7 +86,7 @@ class CourseRunViewSet(viewsets.GenericViewSet):
serializer.save()
return Response(serializer.data)
@detail_route(methods=['post'])
@action(detail=True, methods=['post'])
def rerun(self, request, *args, **kwargs):
course_run = self.get_object()
serializer = CourseRunRerunSerializer(course_run, data=request.data, context=self.get_serializer_context())

View File

@@ -3,7 +3,6 @@ CMS user tasks application configuration
Signal handlers are connected here.
"""
from __future__ import absolute_import
from django.apps import AppConfig

View File

@@ -1,7 +1,7 @@
"""
Receivers of signals sent from django-user-tasks
"""
from __future__ import absolute_import, print_function, unicode_literals
import logging

View File

@@ -2,7 +2,6 @@
Celery tasks used by cms_user_tasks
"""
from __future__ import absolute_import
from boto.exception import NoAuthHandlerFound
from celery.exceptions import MaxRetriesExceededError

View File

@@ -2,7 +2,6 @@
Unit tests for integration of the django-user-tasks app and its REST API.
"""
from __future__ import absolute_import, print_function, unicode_literals
import logging
from uuid import uuid4

View File

@@ -2,7 +2,6 @@
Admin site bindings for contentstore
"""
from __future__ import absolute_import
from config_models.admin import ConfigurationModelAdmin
from django.contrib import admin

View File

@@ -1,7 +1,7 @@
"""
Base test case for the course API views.
"""
from __future__ import absolute_import
from django.core.urlresolvers import reverse
from rest_framework.test import APITestCase

View File

@@ -1,7 +1,7 @@
"""
Tests for the course import API views
"""
from __future__ import absolute_import
import os
import tarfile

View File

@@ -1,7 +1,7 @@
"""
Tests for the course import API views
"""
from __future__ import absolute_import
from rest_framework import status

View File

@@ -1,7 +1,7 @@
"""
Tests for the course import API views
"""
from __future__ import absolute_import
from datetime import datetime

View File

@@ -1,5 +1,5 @@
""" Course API URLs. """
from __future__ import absolute_import
from django.conf import settings
from django.conf.urls import url

View File

@@ -1,7 +1,7 @@
"""
APIs related to Course Import.
"""
from __future__ import absolute_import
import base64
import logging

View File

@@ -1,5 +1,5 @@
# pylint: disable=missing-docstring
from __future__ import absolute_import
import logging
import time

View File

@@ -1,5 +1,5 @@
# pylint: disable=missing-docstring
from __future__ import absolute_import
import logging

View File

@@ -1,7 +1,7 @@
"""
Common utilities for Contentstore APIs.
"""
from __future__ import absolute_import
from contextlib import contextmanager

View File

@@ -4,7 +4,6 @@ Contentstore Application Configuration
Above-modulestore level signal handlers are connected here.
"""
from __future__ import absolute_import
from django.apps import AppConfig

View File

@@ -2,7 +2,7 @@
This module contains various configuration settings via
waffle switches for the contentstore app.
"""
from __future__ import absolute_import
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag, WaffleFlagNamespace, WaffleSwitchNamespace

View File

@@ -1,6 +1,5 @@
"""Util methods for Waffle checks"""
from __future__ import absolute_import
from cms.djangoapps.contentstore.config.waffle import ENABLE_CHECKLISTS_QUALITY

View File

@@ -1,7 +1,7 @@
"""
Class for manipulating groups configuration on a course object.
"""
from __future__ import absolute_import
import json
import logging

View File

@@ -12,7 +12,6 @@ Current db representation:
}
"""
from __future__ import absolute_import
import logging
import re

View File

@@ -1,5 +1,5 @@
""" Code to allow module store to interface with courseware index """
from __future__ import absolute_import
import logging
import re

View File

@@ -1,6 +1,5 @@
""" Upload file handler to help test progress bars in uploads. """
from __future__ import absolute_import
import time

View File

@@ -3,7 +3,6 @@ Utilities for export a course's XML into a git repository,
committing and pushing the changes.
"""
from __future__ import absolute_import
import logging
import os

View File

@@ -3,7 +3,6 @@ A single-use management command that provides an interactive way to remove
erroneous certificate names.
"""
from __future__ import absolute_import
from collections import namedtuple

View File

@@ -2,7 +2,7 @@
Script for removing all redundant Mac OS metadata files (with filename ".DS_Store"
or with filename which starts with "._") for all courses
"""
from __future__ import absolute_import
import logging

View File

@@ -1,7 +1,7 @@
"""
Django management command to create a course in a specific modulestore
"""
from __future__ import absolute_import
from datetime import datetime, timedelta

View File

@@ -1,7 +1,7 @@
"""
Management Command to delete course.
"""
from __future__ import absolute_import, print_function
from django.core.management.base import BaseCommand, CommandError
from opaque_keys import InvalidKeyError

View File

@@ -1,5 +1,5 @@
"""Script for deleting orphans"""
from __future__ import absolute_import, print_function
from django.core.management.base import BaseCommand, CommandError
from opaque_keys import InvalidKeyError

View File

@@ -6,7 +6,7 @@
# Run it this way:
# ./manage.py cms --settings dev edit_course_tabs --course Stanford/CS99/2013_spring
#
from __future__ import absolute_import, print_function
from django.core.management.base import BaseCommand, CommandError
from opaque_keys.edx.keys import CourseKey

View File

@@ -1,6 +1,5 @@
"""Script to Empty the trashcan"""
from __future__ import absolute_import
from django.core.management.base import BaseCommand
from opaque_keys.edx.keys import CourseKey

View File

@@ -1,7 +1,7 @@
"""
Script for exporting courseware from Mongo to a tar.gz file
"""
from __future__ import absolute_import, print_function
import os

View File

@@ -1,7 +1,7 @@
"""
Script for exporting all courseware from Mongo to a directory and listing the courses which failed to export
"""
from __future__ import absolute_import, print_function
from django.core.management.base import BaseCommand
from six import text_type

View File

@@ -1,7 +1,7 @@
"""
Script for exporting a content library from Mongo to a tar.gz file
"""
from __future__ import absolute_import, print_function
import os
import shutil

View File

@@ -14,7 +14,6 @@ At present, it differs from Studio exports in several ways:
* It only supports the export of courses. It does not export libraries.
"""
from __future__ import absolute_import
import os
import re

View File

@@ -1,7 +1,7 @@
"""
Script for fixing the item not found errors in a course
"""
from __future__ import absolute_import
from django.core.management.base import BaseCommand, CommandError
from opaque_keys.edx.keys import CourseKey

View File

@@ -1,7 +1,7 @@
"""
Script for force publishing a course
"""
from __future__ import absolute_import, print_function
from django.core.management.base import BaseCommand, CommandError
from opaque_keys import InvalidKeyError

View File

@@ -1,7 +1,7 @@
"""
Django management command to generate a test course from a course config json
"""
from __future__ import absolute_import
import json
import logging

View File

@@ -13,7 +13,6 @@ This functionality is also available as an export view in studio if the giturl
attribute is set and the FEATURE['ENABLE_EXPORT_GIT'] is set.
"""
from __future__ import absolute_import
import logging

View File

@@ -1,7 +1,7 @@
"""
Script for importing courseware from XML format
"""
from __future__ import absolute_import
from django.core.management.base import BaseCommand

View File

@@ -1,7 +1,7 @@
"""
Script for importing a content library from a tar.gz file
"""
from __future__ import absolute_import, print_function
import base64
import os

View File

@@ -2,7 +2,7 @@
Django management command to migrate a course from the old Mongo modulestore
to the new split-Mongo modulestore.
"""
from __future__ import absolute_import
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand, CommandError

View File

@@ -2,7 +2,6 @@
Command to migrate transcripts to django storage.
"""
from __future__ import absolute_import
import logging

View File

@@ -1,7 +1,7 @@
"""
Takes user input.
"""
from __future__ import absolute_import
import sys

View File

@@ -1,5 +1,5 @@
""" Management command to update courses' search index """
from __future__ import absolute_import
import logging
from textwrap import dedent

View File

@@ -1,5 +1,5 @@
""" Management command to update libraries' search index """
from __future__ import absolute_import, print_function
from textwrap import dedent

View File

@@ -1,6 +1,5 @@
"""Management command to restore assets from trash"""
from __future__ import absolute_import
from django.core.management.base import BaseCommand

View File

@@ -2,7 +2,7 @@
Test for assets cleanup of courses for Mac OS metadata files (with filename ".DS_Store"
or with filename which starts with "._")
"""
from __future__ import absolute_import
from django.conf import settings
from django.core.management import call_command

View File

@@ -1,7 +1,7 @@
"""
Unittests for creating a course in an chosen modulestore
"""
from __future__ import absolute_import
from six import StringIO
@@ -27,7 +27,7 @@ class TestArgParsing(TestCase):
errstring = "Error: too few arguments"
else:
errstring = "Error: the following arguments are required: modulestore, user, org, number, run"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('create_course')
def test_invalid_store(self):
@@ -36,12 +36,12 @@ class TestArgParsing(TestCase):
def test_nonexistent_user_id(self):
errstring = "No user 99 found"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('create_course', "split", "99", "org", "course", "run")
def test_nonexistent_user_email(self):
errstring = "No user fake@example.com found"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('create_course', "mongo", "fake@example.com", "org", "course", "run")

View File

@@ -1,7 +1,7 @@
"""
Delete course tests.
"""
from __future__ import absolute_import
import mock
from django.core.management import CommandError, call_command
@@ -25,13 +25,13 @@ class DeleteCourseTests(ModuleStoreTestCase):
def test_invalid_course_key(self):
course_run_key = 'foo/TestX/TS01/2015_Q7'
expected_error_message = 'Invalid course_key: ' + course_run_key
with self.assertRaisesRegexp(CommandError, expected_error_message):
with self.assertRaisesRegex(CommandError, expected_error_message):
call_command('delete_course', course_run_key)
def test_course_not_found(self):
course_run_key = 'TestX/TS01/2015_Q7'
expected_error_message = 'Course not found: ' + course_run_key
with self.assertRaisesRegexp(CommandError, expected_error_message):
with self.assertRaisesRegex(CommandError, expected_error_message):
call_command('delete_course', course_run_key)
def test_asset_and_course_deletion(self):

View File

@@ -1,6 +1,5 @@
"""Tests running the delete_orphan command"""
from __future__ import absolute_import
import ddt
import six
@@ -25,7 +24,7 @@ class TestDeleteOrphan(TestOrphanBase):
errstring = 'Error: too few arguments'
else:
errstring = 'Error: the following arguments are required: course_id'
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('delete_orphans')
@ddt.data(ModuleStoreEnum.Type.split, ModuleStoreEnum.Type.mongo)

View File

@@ -1,7 +1,7 @@
"""
Tests for exporting courseware to the desired path
"""
from __future__ import absolute_import
import shutil
import unittest
@@ -29,7 +29,7 @@ class TestArgParsingCourseExport(unittest.TestCase):
errstring = "Error: too few arguments"
else:
errstring = "Error: the following arguments are required: course_id, output_path"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('export')
@@ -62,7 +62,7 @@ class TestCourseExport(ModuleStoreTestCase):
)
# Test `export` management command with invalid course_id
errstring = "Invalid course_key: 'InvalidCourseID'."
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('export', "InvalidCourseID", self.temp_dir_1)
# Test `export` management command with correct course_id
@@ -74,5 +74,5 @@ class TestCourseExport(ModuleStoreTestCase):
Test export command with a valid course key that doesn't exist
"""
errstring = "Course with x/y/z key not found."
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('export', "x/y/z", self.temp_dir_1)

View File

@@ -1,7 +1,7 @@
"""
Test for export all courses.
"""
from __future__ import absolute_import
import shutil
from tempfile import mkdtemp

View File

@@ -2,7 +2,6 @@
Tests for exporting OLX content.
"""
from __future__ import absolute_import
import shutil
import tarfile
@@ -33,7 +32,7 @@ class TestArgParsingCourseExportOlx(unittest.TestCase):
errstring = "Error: too few arguments"
else:
errstring = "Error: the following arguments are required: course_id"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('export_olx')
@@ -48,7 +47,7 @@ class TestCourseExportOlx(ModuleStoreTestCase):
Test export command with an invalid course key.
"""
errstring = "Unparsable course_id"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('export_olx', 'InvalidCourseID')
def test_course_key_not_found(self):
@@ -56,7 +55,7 @@ class TestCourseExportOlx(ModuleStoreTestCase):
Test export command with a valid course key that doesn't exist.
"""
errstring = "Invalid course_id"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('export_olx', 'x/y/z')
def create_dummy_course(self, store_type):

View File

@@ -2,7 +2,6 @@
Tests for the fix_not_found management command
"""
from __future__ import absolute_import
import six
from django.core.management import CommandError, call_command
@@ -25,7 +24,7 @@ class TestFixNotFound(ModuleStoreTestCase):
else:
msg = "Error: the following arguments are required: course_id"
with self.assertRaisesRegexp(CommandError, msg):
with self.assertRaisesRegex(CommandError, msg):
call_command('fix_not_found')
def test_fix_not_found_non_split(self):
@@ -33,7 +32,7 @@ class TestFixNotFound(ModuleStoreTestCase):
The management command doesn't work on non split courses
"""
course = CourseFactory.create(default_store=ModuleStoreEnum.Type.mongo)
with self.assertRaisesRegexp(CommandError, "The owning modulestore does not support this command."):
with self.assertRaisesRegex(CommandError, "The owning modulestore does not support this command."):
call_command("fix_not_found", six.text_type(course.id))
def test_fix_not_found(self):

View File

@@ -1,7 +1,7 @@
"""
Tests for the force_publish management command
"""
from __future__ import absolute_import
import mock
import six
@@ -34,7 +34,7 @@ class TestForcePublish(SharedModuleStoreTestCase):
else:
errstring = "Error: the following arguments are required: course_key"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('force_publish')
def test_invalid_course_key(self):
@@ -42,7 +42,7 @@ class TestForcePublish(SharedModuleStoreTestCase):
Test 'force_publish' command with invalid course key
"""
errstring = "Invalid course key."
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('force_publish', 'TestX/TS01')
def test_too_many_arguments(self):
@@ -50,7 +50,7 @@ class TestForcePublish(SharedModuleStoreTestCase):
Test 'force_publish' command with more than 2 arguments
"""
errstring = "Error: unrecognized arguments: invalid-arg"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('force_publish', six.text_type(self.course.id), '--commit', 'invalid-arg')
def test_course_key_not_found(self):
@@ -58,7 +58,7 @@ class TestForcePublish(SharedModuleStoreTestCase):
Test 'force_publish' command with non-existing course key
"""
errstring = "Course not found."
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('force_publish', six.text_type('course-v1:org+course+run'))
def test_force_publish_non_split(self):
@@ -67,7 +67,7 @@ class TestForcePublish(SharedModuleStoreTestCase):
"""
course = CourseFactory.create(default_store=ModuleStoreEnum.Type.mongo)
errstring = 'The owning modulestore does not support this command.'
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('force_publish', six.text_type(course.id))

View File

@@ -1,7 +1,7 @@
"""
Unittest for generate a test course in an given modulestore
"""
from __future__ import absolute_import
import json
@@ -43,7 +43,7 @@ class TestGenerateCourses(ModuleStoreTestCase):
"""
Test that providing an invalid JSON object will result in the appropriate command error
"""
with self.assertRaisesRegexp(CommandError, "Invalid JSON object"):
with self.assertRaisesRegex(CommandError, "Invalid JSON object"):
arg = "invalid_json"
call_command("generate_courses", arg)
@@ -51,7 +51,7 @@ class TestGenerateCourses(ModuleStoreTestCase):
"""
Test that a missing list of courses in json will result in the appropriate command error
"""
with self.assertRaisesRegexp(CommandError, "JSON object is missing courses list"):
with self.assertRaisesRegex(CommandError, "JSON object is missing courses list"):
settings = {}
arg = json.dumps(settings)
call_command("generate_courses", arg)

View File

@@ -2,7 +2,6 @@
Unittests for exporting to git via management command.
"""
from __future__ import absolute_import
import copy
import os
@@ -59,7 +58,7 @@ class TestGitExport(CourseTestCase):
Test that the command interface works. Ignore stderr for clean
test output.
"""
with self.assertRaisesRegexp(CommandError, 'Error: unrecognized arguments:*'):
with self.assertRaisesRegex(CommandError, 'Error: unrecognized arguments:*'):
call_command('git_export', 'blah', 'blah', 'blah', stderr=StringIO())
if six.PY2:
@@ -73,23 +72,23 @@ class TestGitExport(CourseTestCase):
call_command('git_export', stderr=StringIO())
# Send bad url to get course not exported
with self.assertRaisesRegexp(CommandError, six.text_type(GitExportError.URL_BAD)):
with self.assertRaisesRegex(CommandError, six.text_type(GitExportError.URL_BAD)):
call_command('git_export', 'foo/bar/baz', 'silly', stderr=StringIO())
# Send bad course_id to get course not exported
with self.assertRaisesRegexp(CommandError, six.text_type(GitExportError.BAD_COURSE)):
with self.assertRaisesRegex(CommandError, six.text_type(GitExportError.BAD_COURSE)):
call_command('git_export', 'foo/bar:baz', 'silly', stderr=StringIO())
def test_error_output(self):
"""
Verify that error output is actually resolved as the correct string
"""
with self.assertRaisesRegexp(CommandError, six.text_type(GitExportError.BAD_COURSE)):
with self.assertRaisesRegex(CommandError, six.text_type(GitExportError.BAD_COURSE)):
call_command(
'git_export', 'foo/bar:baz', 'silly'
)
with self.assertRaisesRegexp(CommandError, six.text_type(GitExportError.URL_BAD)):
with self.assertRaisesRegex(CommandError, six.text_type(GitExportError.URL_BAD)):
call_command(
'git_export', 'foo/bar/baz', 'silly'
)
@@ -99,14 +98,13 @@ class TestGitExport(CourseTestCase):
Test several bad URLs for validation
"""
course_key = CourseLocator('org', 'course', 'run')
with self.assertRaisesRegexp(GitExportError, six.text_type(GitExportError.URL_BAD)):
with self.assertRaisesRegex(GitExportError, six.text_type(GitExportError.URL_BAD)):
git_export_utils.export_to_git(course_key, 'Sillyness')
with self.assertRaisesRegexp(GitExportError, six.text_type(GitExportError.URL_BAD)):
with self.assertRaisesRegex(GitExportError, six.text_type(GitExportError.URL_BAD)):
git_export_utils.export_to_git(course_key, 'example.com:edx/notreal')
with self.assertRaisesRegexp(GitExportError,
six.text_type(GitExportError.URL_NO_AUTH)):
with self.assertRaisesRegex(GitExportError, six.text_type(GitExportError.URL_NO_AUTH)):
git_export_utils.export_to_git(course_key, 'http://blah')
def test_bad_git_repos(self):
@@ -117,23 +115,20 @@ class TestGitExport(CourseTestCase):
self.assertFalse(os.path.isdir(test_repo_path))
course_key = CourseLocator('foo', 'blah', '100-')
# Test bad clones
with self.assertRaisesRegexp(GitExportError,
six.text_type(GitExportError.CANNOT_PULL)):
with self.assertRaisesRegex(GitExportError, six.text_type(GitExportError.CANNOT_PULL)):
git_export_utils.export_to_git(
course_key,
'https://user:blah@example.com/test_repo.git')
self.assertFalse(os.path.isdir(test_repo_path))
# Setup good repo with bad course to test xml export
with self.assertRaisesRegexp(GitExportError,
six.text_type(GitExportError.XML_EXPORT_FAIL)):
with self.assertRaisesRegex(GitExportError, six.text_type(GitExportError.XML_EXPORT_FAIL)):
git_export_utils.export_to_git(
course_key,
'file://{0}'.format(self.bare_repo_dir))
# Test bad git remote after successful clone
with self.assertRaisesRegexp(GitExportError,
six.text_type(GitExportError.CANNOT_PULL)):
with self.assertRaisesRegex(GitExportError, six.text_type(GitExportError.CANNOT_PULL)):
git_export_utils.export_to_git(
course_key,
'https://user:blah@example.com/r.git')
@@ -189,7 +184,6 @@ class TestGitExport(CourseTestCase):
'file://{0}'.format(self.bare_repo_dir)
)
with self.assertRaisesRegexp(GitExportError,
six.text_type(GitExportError.CANNOT_COMMIT)):
with self.assertRaisesRegex(GitExportError, six.text_type(GitExportError.CANNOT_COMMIT)):
git_export_utils.export_to_git(
self.course.id, 'file://{0}'.format(self.bare_repo_dir))

View File

@@ -2,7 +2,6 @@
Unittests for importing a course via management command
"""
from __future__ import absolute_import
import os
import shutil

View File

@@ -1,7 +1,7 @@
"""
Unittests for migrating a course to split mongo
"""
from __future__ import absolute_import
import six
@@ -30,7 +30,7 @@ class TestArgParsing(TestCase):
errstring = "Error: too few arguments"
else:
errstring = "Error: the following arguments are required: course_key, email"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command("migrate_to_split")
def test_invalid_location(self):
@@ -38,7 +38,7 @@ class TestArgParsing(TestCase):
Test passing an unparsable course id
"""
errstring = "Invalid location string"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command("migrate_to_split", "foo", "bar")
def test_nonexistent_user_id(self):
@@ -46,7 +46,7 @@ class TestArgParsing(TestCase):
Test error for using an unknown user primary key
"""
errstring = "No user found identified by 99"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command("migrate_to_split", "org/course/name", "99")
def test_nonexistent_user_email(self):
@@ -54,7 +54,7 @@ class TestArgParsing(TestCase):
Test error for using an unknown user email
"""
errstring = "No user found identified by fake@example.com"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command("migrate_to_split", "org/course/name", "fake@example.com")

View File

@@ -2,7 +2,7 @@
"""
Tests for course transcript migration management command.
"""
from __future__ import absolute_import
import itertools
import logging
@@ -69,12 +69,12 @@ class TestArgParsing(TestCase):
"""
def test_no_args(self):
errstring = "Must specify exactly one of --course_ids, --all_courses, --from_settings"
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('migrate_transcripts')
def test_invalid_course(self):
errstring = "Invalid course_key: 'invalid-course'."
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('migrate_transcripts', '--course-id', 'invalid-course')

View File

@@ -1,5 +1,5 @@
""" Tests for course reindex command """
from __future__ import absolute_import
import ddt
import mock
@@ -50,25 +50,25 @@ class TestReindexCourse(ModuleStoreTestCase):
def test_given_no_arguments_raises_command_error(self):
""" Test that raises CommandError for incorrect arguments """
with self.assertRaisesRegexp(CommandError, ".* requires one or more *"):
with self.assertRaisesRegex(CommandError, ".* requires one or more *"):
call_command('reindex_course')
@ddt.data('qwerty', 'invalid_key', 'xblockv1:qwerty')
def test_given_invalid_course_key_raises_not_found(self, invalid_key):
""" Test that raises InvalidKeyError for invalid keys """
err_string = u"Invalid course_key: '{0}'".format(invalid_key)
with self.assertRaisesRegexp(CommandError, err_string):
with self.assertRaisesRegex(CommandError, err_string):
call_command('reindex_course', invalid_key)
def test_given_library_key_raises_command_error(self):
""" Test that raises CommandError if library key is passed """
with self.assertRaisesRegexp(CommandError, ".* is not a course key"):
with self.assertRaisesRegex(CommandError, ".* is not a course key"):
call_command('reindex_course', text_type(self._get_lib_key(self.first_lib)))
with self.assertRaisesRegexp(CommandError, ".* is not a course key"):
with self.assertRaisesRegex(CommandError, ".* is not a course key"):
call_command('reindex_course', text_type(self._get_lib_key(self.second_lib)))
with self.assertRaisesRegexp(CommandError, ".* is not a course key"):
with self.assertRaisesRegex(CommandError, ".* is not a course key"):
call_command(
'reindex_course',
text_type(self.second_course.id),

View File

@@ -1,5 +1,5 @@
""" Tests for library reindex command """
from __future__ import absolute_import
import ddt
import mock
@@ -50,7 +50,7 @@ class TestReindexLibrary(ModuleStoreTestCase):
def test_given_no_arguments_raises_command_error(self):
""" Test that raises CommandError for incorrect arguments """
with self.assertRaisesRegexp(CommandError, ".* requires one or more *"):
with self.assertRaisesRegex(CommandError, ".* requires one or more *"):
call_command('reindex_library')
@ddt.data('qwerty', 'invalid_key', 'xblock-v1:qwe+rty')
@@ -61,13 +61,13 @@ class TestReindexLibrary(ModuleStoreTestCase):
def test_given_course_key_raises_command_error(self):
""" Test that raises CommandError if course key is passed """
with self.assertRaisesRegexp(CommandError, ".* is not a library key"):
with self.assertRaisesRegex(CommandError, ".* is not a library key"):
call_command('reindex_library', six.text_type(self.first_course.id))
with self.assertRaisesRegexp(CommandError, ".* is not a library key"):
with self.assertRaisesRegex(CommandError, ".* is not a library key"):
call_command('reindex_library', six.text_type(self.second_course.id))
with self.assertRaisesRegexp(CommandError, ".* is not a library key"):
with self.assertRaisesRegex(CommandError, ".* is not a library key"):
call_command(
'reindex_library',
six.text_type(self.second_course.id),

View File

@@ -2,7 +2,7 @@
"""
Tests for course video thumbnails management command.
"""
from __future__ import absolute_import
import logging
@@ -36,7 +36,7 @@ class TestArgParsing(TestCase):
def test_invalid_course(self):
errstring = "Invalid key specified: <class 'opaque_keys.edx.locator.CourseLocator'>: invalid-course"
setup_video_thumbnails_config(course_ids='invalid-course')
with self.assertRaisesRegexp(CommandError, errstring):
with self.assertRaisesRegex(CommandError, errstring):
call_command('video_thumbnails')

View File

@@ -1,7 +1,7 @@
"""
Common methods for cms commands to use
"""
from __future__ import absolute_import
from django.contrib.auth.models import User
from opaque_keys.edx.keys import CourseKey

View File

@@ -1,7 +1,7 @@
"""
Command to scrape thumbnails and add them to the course-videos.
"""
from __future__ import absolute_import
import logging

View File

@@ -1,7 +1,7 @@
"""
Verify the structure of courseware as to it's suitability for import
"""
from __future__ import absolute_import, print_function
from argparse import REMAINDER

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import django.db.models.deletion
from django.conf import settings
@@ -32,7 +32,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
('enabled', models.BooleanField(default=False, verbose_name='Enabled')),
('profile_whitelist', models.TextField(help_text=b'A comma-separated list of names of profiles to include in video encoding downloads.', blank=True)),
('profile_whitelist', models.TextField(help_text=u'A comma-separated list of names of profiles to include in video encoding downloads.', blank=True)),
('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')),
],
options={

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import django.db.models.deletion
from django.conf import settings

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
from django.db import migrations, models

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.22 on 2019-07-26 20:12
from __future__ import unicode_literals
from django.db import migrations

View File

@@ -2,7 +2,6 @@
Models for contentstore
"""
from __future__ import absolute_import
from config_models.models import ConfigurationModel
from django.db.models.fields import TextField
@@ -16,7 +15,7 @@ class VideoUploadConfig(ConfigurationModel):
"""
profile_whitelist = TextField(
blank=True,
help_text="A comma-separated list of names of profiles to include in video encoding downloads."
help_text=u"A comma-separated list of names of profiles to include in video encoding downloads."
)
@classmethod

View File

@@ -2,7 +2,6 @@
Code related to the handling of Proctored Exams in Studio
"""
from __future__ import absolute_import
import logging

View File

@@ -2,7 +2,6 @@
Authorization rules related to content management.
"""
from __future__ import absolute_import, unicode_literals
import user_tasks.rules

View File

@@ -1,6 +1,5 @@
""" receivers of course_published and library_updated events in order to trigger indexing task """
from __future__ import absolute_import
import logging
from datetime import datetime

View File

@@ -1,7 +1,7 @@
"""
Contentstore signals
"""
from __future__ import absolute_import
from django.dispatch import Signal

View File

@@ -1,7 +1,7 @@
"""
Storage backend for course import and export.
"""
from __future__ import absolute_import
from django.conf import settings
from django.core.files.storage import get_storage_class

View File

@@ -1,7 +1,7 @@
"""
This file contains celery tasks for contentstore views
"""
from __future__ import absolute_import
import base64
import json
@@ -32,7 +32,7 @@ from opaque_keys.edx.locator import LibraryLocator, BlockUsageLocator
from organizations.models import OrganizationCourse
from path import Path as path
from pytz import UTC
from six import iteritems, text_type
from six import iteritems, text_type, binary_type
from six.moves import range
from user_tasks.models import UserTaskArtifact, UserTaskStatus
from user_tasks.tasks import UserTask
@@ -528,7 +528,7 @@ def _parse_time(time_isoformat):
).replace(tzinfo=UTC)
@task()
@task(routing_key=settings.UPDATE_SEARCH_INDEX_JOB_QUEUE)
def update_search_index(course_id, triggered_time_isoformat):
""" Updates course search index. """
try:

View File

@@ -1,7 +1,7 @@
"""
Unit tests for cloning a course between the same and different module stores.
"""
from __future__ import absolute_import
import json

View File

@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function
import copy
import shutil
@@ -1352,7 +1351,7 @@ class ContentStoreTest(ContentStoreTestCase):
resp = self.client.ajax_post('/course/', self.course_data)
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
self.assertRegexpMatches(data['ErrMsg'], error_message)
self.assertRegex(data['ErrMsg'], error_message)
if test_enrollment:
# One test case involves trying to create the same course twice. Hence for that course,
# the user will be enrolled. In the other cases, initially_enrolled will be False.
@@ -1518,7 +1517,7 @@ class ContentStoreTest(ContentStoreTestCase):
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
retarget = text_type(course.id.make_usage_key('chapter', 'REPLACE')).replace('REPLACE', r'([0-9]|[a-f]){3,}')
self.assertRegexpMatches(data['locator'], retarget)
self.assertRegex(data['locator'], retarget)
def test_capa_module(self):
"""Test that a problem treats markdown specially."""
@@ -2186,10 +2185,12 @@ class EntryPageTestCase(TestCase):
self._test_page("/howitworks")
def test_signup(self):
self._test_page("/signup")
# deprecated signup url redirects to LMS register.
self._test_page("/signup", 301)
def test_login(self):
self._test_page("/signin")
# deprecated signin url redirects to LMS login.
self._test_page("/signin", 302)
def test_logout(self):
# Logout redirects.
@@ -2202,36 +2203,6 @@ class EntryPageTestCase(TestCase):
self._test_page('/accessibility')
class SigninPageTestCase(TestCase):
"""
Tests that the CSRF token is directly included in the signin form. This is
important to make sure that the script is functional independently of any
other script.
"""
def test_csrf_token_is_present_in_form(self):
# Expected html:
# <form>
# ...
# <fieldset>
# ...
# <input name="csrfmiddlewaretoken" value="...">
# ...
# </fieldset>
# ...
# </form>
response = self.client.get("/signin")
csrf_token = response.cookies.get("csrftoken")
form = lxml.html.fromstring(response.content).get_element_by_id("login_form")
csrf_input_field = form.find(".//input[@name='csrfmiddlewaretoken']")
self.assertIsNotNone(csrf_token)
self.assertIsNotNone(csrf_token.value)
self.assertIsNotNone(csrf_input_field)
self.assertTrue(_compare_salted_tokens(csrf_token.value, csrf_input_field.attrib["value"]))
def _create_course(test, course_key, course_data):
"""
Creates a course via an AJAX request and verifies the URL returned in the response.

View File

@@ -2,7 +2,6 @@
Tests core caching facilities.
"""
from __future__ import absolute_import
from django.test import TestCase
from opaque_keys.edx.locator import AssetLocator, CourseLocator

View File

@@ -1,7 +1,7 @@
"""
Test view handler for rerun (and eventually create)
"""
from __future__ import absolute_import
import datetime

View File

@@ -2,7 +2,7 @@
Unit tests for getting the list of courses for a user through iterating all courses and
by reversing group name formats.
"""
from __future__ import absolute_import
import random

View File

@@ -1,7 +1,7 @@
"""
Tests for Studio Course Settings.
"""
from __future__ import absolute_import
import copy
import datetime
@@ -87,10 +87,37 @@ class CourseSettingsEncoderTest(CourseTestCase):
jsondetails = json.dumps(details, cls=CourseSettingsEncoder)
jsondetails = json.loads(jsondetails)
self.assertEquals(1, jsondetails['number'])
self.assertEqual(1, jsondetails['number'])
self.assertEqual(jsondetails['string'], 'string')
class CourseAdvanceSettingViewTest(CourseTestCase, MilestonesTestCaseMixin):
"""
Tests for AdvanceSettings View.
"""
def setUp(self):
super(CourseAdvanceSettingViewTest, self).setUp()
self.fullcourse = CourseFactory.create()
self.course_setting_url = get_url(self.course.id, 'advanced_settings_handler')
@override_settings(FEATURES={'DISABLE_MOBILE_COURSE_AVAILABLE': True})
def test_mobile_field_available(self):
"""
Test to check `Mobile Course Available` field is not viewable in Studio
when DISABLE_MOBILE_COURSE_AVAILABLE is true.
"""
response = self.client.get_html(self.course_setting_url)
start = response.content.decode('utf-8').find("mobile_available")
end = response.content.decode('utf-8').find("}", start)
settings_fields = json.loads(response.content.decode('utf-8')[start + len("mobile_available: "):end + 1])
self.assertEqual(settings_fields["display_name"], "Mobile Course Available")
self.assertEqual(settings_fields["deprecated"], True)
@ddt.ddt
class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
"""
@@ -335,10 +362,10 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
}
response = self.client.post(settings_details_url, data=json.dumps(data), content_type='application/json',
HTTP_ACCEPT='application/json')
self.assertEquals(response.status_code, 200)
self.assertEqual(response.status_code, 200)
course = modulestore().get_course(self.course.id)
self.assertTrue(course.entrance_exam_enabled)
self.assertEquals(course.entrance_exam_minimum_score_pct, .60)
self.assertEqual(course.entrance_exam_minimum_score_pct, .60)
# Update the entrance exam
data['entrance_exam_enabled'] = "true"
@@ -349,10 +376,10 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
content_type='application/json',
HTTP_ACCEPT='application/json'
)
self.assertEquals(response.status_code, 200)
self.assertEqual(response.status_code, 200)
course = modulestore().get_course(self.course.id)
self.assertTrue(course.entrance_exam_enabled)
self.assertEquals(course.entrance_exam_minimum_score_pct, .80)
self.assertEqual(course.entrance_exam_minimum_score_pct, .80)
self.assertTrue(milestones_helpers.any_unfulfilled_milestones(self.course.id, self.user.id),
msg='The entrance exam should be required.')
@@ -366,9 +393,9 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
HTTP_ACCEPT='application/json'
)
course = modulestore().get_course(self.course.id)
self.assertEquals(response.status_code, 200)
self.assertEqual(response.status_code, 200)
self.assertFalse(course.entrance_exam_enabled)
self.assertEquals(course.entrance_exam_minimum_score_pct, None)
self.assertEqual(course.entrance_exam_minimum_score_pct, None)
self.assertFalse(milestones_helpers.any_unfulfilled_milestones(self.course.id, self.user.id),
msg='The entrance exam should not be required anymore')
@@ -396,12 +423,12 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
content_type='application/json',
HTTP_ACCEPT='application/json'
)
self.assertEquals(response.status_code, 200)
self.assertEqual(response.status_code, 200)
course = modulestore().get_course(self.course.id)
self.assertTrue(course.entrance_exam_enabled)
# entrance_exam_minimum_score_pct is not present in the request so default value should be saved.
self.assertEquals(course.entrance_exam_minimum_score_pct, .5)
self.assertEqual(course.entrance_exam_minimum_score_pct, .5)
#add entrance_exam_minimum_score_pct with empty value in json request.
test_data_2 = {
@@ -422,10 +449,10 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
content_type='application/json',
HTTP_ACCEPT='application/json'
)
self.assertEquals(response.status_code, 200)
self.assertEqual(response.status_code, 200)
course = modulestore().get_course(self.course.id)
self.assertTrue(course.entrance_exam_enabled)
self.assertEquals(course.entrance_exam_minimum_score_pct, .5)
self.assertEqual(course.entrance_exam_minimum_score_pct, .5)
def test_editable_short_description_fetch(self):
settings_details_url = get_url(self.course.id)

View File

@@ -1,7 +1,7 @@
"""
Testing indexing of the courseware as it is changed
"""
from __future__ import absolute_import, print_function
import json
import time

View File

@@ -1,6 +1,5 @@
"""Tests for CRUD Operations"""
from __future__ import absolute_import
from xmodule import templates
from xmodule.capa_module import ProblemBlock
@@ -39,8 +38,8 @@ class TemplateTests(ModuleStoreTestCase):
self.assertIsNotNone(dropdown)
self.assertIn('markdown', dropdown['metadata'])
self.assertIn('data', dropdown)
self.assertRegexpMatches(dropdown['metadata']['markdown'], r'.*dropdown problems.*')
self.assertRegexpMatches(dropdown['data'], r'<problem>\s*<optionresponse>\s*<p>.*dropdown problems.*')
self.assertRegex(dropdown['metadata']['markdown'], r'.*dropdown problems.*')
self.assertRegex(dropdown['data'], r'<problem>\s*<optionresponse>\s*<p>.*dropdown problems.*')
def test_get_some_templates(self):
self.assertEqual(len(SequenceDescriptor.templates()), 0)

View File

@@ -2,7 +2,6 @@
Test the ability to export courses to xml from studio
"""
from __future__ import absolute_import
import copy
import os

Some files were not shown because too many files have changed in this diff Show More