From 0d2ae5d4af5313dd3870b7955d2a7b783a742f75 Mon Sep 17 00:00:00 2001 From: "J. Cliff Dyer" Date: Wed, 4 Jan 2017 16:57:40 -0500 Subject: [PATCH 1/2] Store failed subsection grade calculations TNL-6250 --- lms/djangoapps/grades/signals/handlers.py | 5 +- lms/djangoapps/grades/tasks.py | 3 +- lms/envs/common.py | 4 + .../core/djangoapps/celery_utils/__init__.py | 0 .../celery_utils/migrations/0001_initial.py | 34 ++++++++ .../celery_utils/migrations/__init__.py | 0 .../core/djangoapps/celery_utils/models.py | 32 +++++++ openedx/core/djangoapps/celery_utils/task.py | 44 ++++++++++ .../djangoapps/celery_utils/tests/__init__.py | 0 .../celery_utils/tests/test_task.py | 84 +++++++++++++++++++ 10 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 openedx/core/djangoapps/celery_utils/__init__.py create mode 100644 openedx/core/djangoapps/celery_utils/migrations/0001_initial.py create mode 100644 openedx/core/djangoapps/celery_utils/migrations/__init__.py create mode 100644 openedx/core/djangoapps/celery_utils/models.py create mode 100644 openedx/core/djangoapps/celery_utils/task.py create mode 100644 openedx/core/djangoapps/celery_utils/tests/__init__.py create mode 100644 openedx/core/djangoapps/celery_utils/tests/test_task.py diff --git a/lms/djangoapps/grades/signals/handlers.py b/lms/djangoapps/grades/signals/handlers.py index fa05873c45..74bd721acc 100644 --- a/lms/djangoapps/grades/signals/handlers.py +++ b/lms/djangoapps/grades/signals/handlers.py @@ -4,15 +4,14 @@ Grades related signals. from logging import getLogger -from courseware.model_data import get_score, set_score from django.dispatch import receiver -from openedx.core.lib.grade_utils import is_score_higher from submissions.models import score_set, score_reset -from util.date_utils import to_timestamp from courseware.model_data import get_score, set_score from eventtracking import tracker +from openedx.core.lib.grade_utils import is_score_higher from student.models import user_by_anonymous_id +from util.date_utils import to_timestamp from track.event_transaction_utils import ( get_event_transaction_type, get_event_transaction_id, diff --git a/lms/djangoapps/grades/tasks.py b/lms/djangoapps/grades/tasks.py index c58647adc4..6a5a235839 100644 --- a/lms/djangoapps/grades/tasks.py +++ b/lms/djangoapps/grades/tasks.py @@ -11,6 +11,7 @@ from logging import getLogger from courseware.model_data import get_score from lms.djangoapps.course_blocks.api import get_course_blocks +from openedx.core.djangoapps.celery_utils.task import PersistOnFailureTask from opaque_keys.edx.keys import UsageKey from opaque_keys.edx.locator import CourseLocator from submissions import api as sub_api @@ -54,7 +55,7 @@ def recalculate_subsection_grade( ) -@task(default_retry_delay=30, routing_key=settings.RECALCULATE_GRADES_ROUTING_KEY) +@task(base=PersistOnFailureTask, default_retry_delay=30, routing_key=settings.RECALCULATE_GRADES_ROUTING_KEY) def recalculate_subsection_grade_v2(**kwargs): """ Updates a saved subsection grade. diff --git a/lms/envs/common.py b/lms/envs/common.py index c826fd1b9f..cc2145e9e9 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -2153,6 +2153,10 @@ INSTALLED_APPS = ( # additional release utilities to ease automation 'release_util', + + # Customized celery tasks, including persisting failed tasks so they can + # be retried + 'openedx.core.djangoapps.celery_utils', ) # Migrations which are not in the standard module "migrations" diff --git a/openedx/core/djangoapps/celery_utils/__init__.py b/openedx/core/djangoapps/celery_utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openedx/core/djangoapps/celery_utils/migrations/0001_initial.py b/openedx/core/djangoapps/celery_utils/migrations/0001_initial.py new file mode 100644 index 0000000000..b85dcc1801 --- /dev/null +++ b/openedx/core/djangoapps/celery_utils/migrations/0001_initial.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import django.utils.timezone +import jsonfield.fields +import model_utils.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='FailedTask', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, verbose_name='created', editable=False)), + ('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, verbose_name='modified', editable=False)), + ('task_name', models.CharField(max_length=255)), + ('task_id', models.CharField(max_length=255, db_index=True)), + ('args', jsonfield.fields.JSONField(blank=True)), + ('kwargs', jsonfield.fields.JSONField(blank=True)), + ('exc', models.CharField(max_length=255)), + ('datetime_resolved', models.DateTimeField(default=None, null=True, db_index=True, blank=True)), + ], + ), + migrations.AlterIndexTogether( + name='failedtask', + index_together=set([('task_name', 'exc')]), + ), + ] diff --git a/openedx/core/djangoapps/celery_utils/migrations/__init__.py b/openedx/core/djangoapps/celery_utils/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openedx/core/djangoapps/celery_utils/models.py b/openedx/core/djangoapps/celery_utils/models.py new file mode 100644 index 0000000000..b96dd0aabc --- /dev/null +++ b/openedx/core/djangoapps/celery_utils/models.py @@ -0,0 +1,32 @@ +""" +Models to support persistent tasks. +""" + +from django.db import models +from jsonfield import JSONField +from model_utils.models import TimeStampedModel + + +class FailedTask(TimeStampedModel): + """ + Representation of tasks that have failed + """ + task_name = models.CharField(max_length=255) + task_id = models.CharField(max_length=255, db_index=True) + args = JSONField(blank=True) + kwargs = JSONField(blank=True) + exc = models.CharField(max_length=255) + datetime_resolved = models.DateTimeField(blank=True, null=True, default=None, db_index=True) + + class Meta(object): + index_together = [ + (u'task_name', u'exc'), + ] + + def __unicode__(self): + return u'FailedTask: {task_name}, args={args}, kwargs={kwargs} ({resolution})'.format( + task_name=self.task_name, + args=self.args, + kwargs=self.kwargs, + resolution=u"not resolved" if self.datetime_resolved is None else "resolved" + ) diff --git a/openedx/core/djangoapps/celery_utils/task.py b/openedx/core/djangoapps/celery_utils/task.py new file mode 100644 index 0000000000..2170368db6 --- /dev/null +++ b/openedx/core/djangoapps/celery_utils/task.py @@ -0,0 +1,44 @@ +""" +Celery utility code for persistent tasks. +""" + +from celery import Task + +from .models import FailedTask + + +# pylint: disable=abstract-method +class PersistOnFailureTask(Task): + """ + Custom Celery Task base class that persists task data on failure. + """ + + def on_failure(self, exc, task_id, args, kwargs, einfo): + """ + If the task fails, persist a record of the task. + """ + FailedTask.objects.create( + task_name=_truncate_to_field(FailedTask, 'task_name', self.name), + task_id=task_id, # Fixed length UUID: No need to truncate + args=args, + kwargs=kwargs, + exc=_truncate_to_field(FailedTask, 'exc', repr(exc)), + ) + super(PersistOnFailureTask, self).on_failure(exc, task_id, args, kwargs, einfo) + + +def _truncate_to_field(model, field_name, value): + """ + If data is too big for the field, it would cause a failure to + insert, so we shorten it, truncating in the middle (because + valuable information often shows up at the end. + """ + field = model._meta.get_field(field_name) # pylint: disable=protected-access + if len(value) > field.max_length: + midpoint = field.max_length // 2 + len_after_midpoint = field.max_length - midpoint + first = value[:midpoint] + sep = u'...' + last = value[len(value) - len_after_midpoint + len(sep):] + value = sep.join([first, last]) + return value diff --git a/openedx/core/djangoapps/celery_utils/tests/__init__.py b/openedx/core/djangoapps/celery_utils/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openedx/core/djangoapps/celery_utils/tests/test_task.py b/openedx/core/djangoapps/celery_utils/tests/test_task.py new file mode 100644 index 0000000000..a579f7480e --- /dev/null +++ b/openedx/core/djangoapps/celery_utils/tests/test_task.py @@ -0,0 +1,84 @@ +u""" +Testing persistent tasks +""" + +from __future__ import print_function + +from celery import task +from django.conf import settings +from django.test import TestCase +from unittest import skipUnless +import six + +from ..models import FailedTask +from ..task import PersistOnFailureTask + + +class PersistOnFailureTaskTestCase(TestCase): + """ + Test that persistent tasks save the appropriate values when needed. + """ + + @classmethod + def setUpClass(cls): + @task(base=PersistOnFailureTask) + def exampletask(message=None): + u""" + A simple task for testing persistence + """ + if message: + raise ValueError(message) + return + cls.exampletask = exampletask + super(PersistOnFailureTaskTestCase, cls).setUpClass() + + + @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + def test_exampletask_without_failure(self): + result = self.exampletask.delay() + result.wait() + self.assertEqual(result.status, u'SUCCESS') + self.assertFalse(FailedTask.objects.exists()) + + @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + def test_exampletask_with_failure(self): + result = self.exampletask.delay(message=u'The example task failed') + with self.assertRaises(ValueError): + result.wait() + self.assertEqual(result.status, u'FAILURE') + failed_task_object = FailedTask.objects.get() + # Assert that we get the kind of data we expect + self.assertEqual( + failed_task_object.task_name, + u'openedx.core.djangoapps.celery_utils.tests.test_task.exampletask' + ) + self.assertEqual(failed_task_object.args, []) + self.assertEqual(failed_task_object.kwargs, {u'message': u'The example task failed'}) + self.assertEqual(failed_task_object.exc, u"ValueError(u'The example task failed',)") + self.assertIsNone(failed_task_object.datetime_resolved) + + @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + def test_persists_when_called_with_wrong_args(self): + result = self.exampletask.delay(15, u'2001-03-04', err=True) + with self.assertRaises(TypeError): + result.wait() + self.assertEqual(result.status, u'FAILURE') + failed_task_object = FailedTask.objects.get() + self.assertEqual(failed_task_object.args, [15, u'2001-03-04']) + self.assertEqual(failed_task_object.kwargs, {u'err': True}) + + @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + def test_persists_with_overlength_field(self): + overlong_message = u''.join(u'%03d' % x for x in six.moves.range(100)) + result = self.exampletask.delay(message=overlong_message) + with self.assertRaises(ValueError): + result.wait() + failed_task_object = FailedTask.objects.get() + # Length is max field length + self.assertEqual(len(failed_task_object.exc), 255) + # Ellipses are put in the middle + self.assertEqual(u'037...590', failed_task_object.exc[124:133]) + # The beginning of the input is captured + self.assertEqual(failed_task_object.exc[:11], u"ValueError(") + # The end of the input is captured + self.assertEqual(failed_task_object.exc[-9:], u"098099',)") From f33832a69108d8595bfa50a3b8d10e3e3d2b2856 Mon Sep 17 00:00:00 2001 From: "J. Cliff Dyer" Date: Thu, 12 Jan 2017 14:53:57 -0500 Subject: [PATCH 2/2] scoutrule: dedupe skip_unless_lms --- .../djangoapps/api_admin/tests/test_forms.py | 5 +- .../djangoapps/api_admin/tests/test_models.py | 7 ++- .../djangoapps/api_admin/tests/test_views.py | 47 +++++++++++++++---- .../djangoapps/bookmarks/tests/test_api.py | 4 +- .../djangoapps/bookmarks/tests/test_models.py | 6 +-- .../bookmarks/tests/test_services.py | 6 +-- .../djangoapps/bookmarks/tests/test_views.py | 6 +-- .../cache_toolbox/tests/test_middleware.py | 8 ++-- .../celery_utils/tests/test_task.py | 9 +--- .../tests/test_partition_scheme.py | 9 ++-- .../course_groups/tests/test_views.py | 6 +-- .../coursetalk/tests/test_helpers.py | 6 +-- .../credentials/tests/test_models.py | 7 ++- .../credentials/tests/test_utils.py | 7 +-- .../core/djangoapps/credit/tests/test_api.py | 7 ++- .../djangoapps/credit/tests/test_partition.py | 6 +-- .../djangoapps/credit/tests/test_signals.py | 5 +- .../djangoapps/credit/tests/test_views.py | 12 ++--- .../core/djangoapps/embargo/tests/test_api.py | 6 +-- .../embargo/tests/test_middleware.py | 6 +-- .../djangoapps/embargo/tests/test_views.py | 5 +- .../external_auth/tests/test_ssl.py | 38 +++++++-------- .../profile_images/tests/test_images.py | 9 ++-- .../profile_images/tests/test_views.py | 13 +++-- .../programs/tasks/v1/tests/test_tasks.py | 13 +++-- .../test_backpopulate_program_credentials.py | 5 +- .../djangoapps/programs/tests/test_utils.py | 14 +++--- .../tests/test_middleware.py | 4 +- .../djangoapps/theming/tests/test_finders.py | 4 +- .../djangoapps/theming/tests/test_helpers.py | 6 +-- .../theming/tests/test_microsites.py | 5 +- .../djangoapps/theming/tests/test_storage.py | 4 +- .../theming/tests/test_theme_locales.py | 9 ++-- .../tests/test_theme_style_overrides.py | 15 +++--- .../user_api/accounts/tests/test_api.py | 13 ++--- .../accounts/tests/test_image_helpers.py | 7 ++- .../user_api/accounts/tests/test_views.py | 9 ++-- .../tests/test_email_opt_in_list.py | 5 +- .../user_api/preferences/tests/test_api.py | 6 +-- .../user_api/preferences/tests/test_views.py | 9 ++-- .../djangoapps/user_api/tests/test_views.py | 10 ++-- openedx/core/djangolib/testing/utils.py | 15 ++++++ 42 files changed, 199 insertions(+), 194 deletions(-) diff --git a/openedx/core/djangoapps/api_admin/tests/test_forms.py b/openedx/core/djangoapps/api_admin/tests/test_forms.py index e10aa6c771..6e676dd9a2 100644 --- a/openedx/core/djangoapps/api_admin/tests/test_forms.py +++ b/openedx/core/djangoapps/api_admin/tests/test_forms.py @@ -1,15 +1,14 @@ #pylint: disable=missing-docstring -import unittest import ddt -from django.conf import settings from django.test import TestCase from openedx.core.djangoapps.api_admin.forms import ApiAccessRequestForm from openedx.core.djangoapps.api_admin.tests.utils import VALID_DATA +from openedx.core.djangolib.testing.utils import skip_unless_lms -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms @ddt.ddt class ApiAccessFormTest(TestCase): diff --git a/openedx/core/djangoapps/api_admin/tests/test_models.py b/openedx/core/djangoapps/api_admin/tests/test_models.py index 9337d26c0e..8db4abf204 100644 --- a/openedx/core/djangoapps/api_admin/tests/test_models.py +++ b/openedx/core/djangoapps/api_admin/tests/test_models.py @@ -2,21 +2,20 @@ from smtplib import SMTPException import ddt -from django.conf import settings from django.db import IntegrityError from django.test import TestCase import mock -import unittest from microsite_configuration.tests.factories import SiteFactory from openedx.core.djangoapps.api_admin.models import ApiAccessRequest, ApiAccessConfig from openedx.core.djangoapps.api_admin.models import log as model_log from openedx.core.djangoapps.api_admin.tests.factories import ApiAccessRequestFactory +from openedx.core.djangolib.testing.utils import skip_unless_lms from student.tests.factories import UserFactory @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class ApiAccessRequestTests(TestCase): def setUp(self): @@ -79,7 +78,7 @@ class ApiAccessConfigTests(TestCase): ) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class ApiAccessRequestSignalTests(TestCase): def setUp(self): super(ApiAccessRequestSignalTests, self).setUp() diff --git a/openedx/core/djangoapps/api_admin/tests/test_views.py b/openedx/core/djangoapps/api_admin/tests/test_views.py index c9e25c50d4..5d2c3757ca 100644 --- a/openedx/core/djangoapps/api_admin/tests/test_views.py +++ b/openedx/core/djangoapps/api_admin/tests/test_views.py @@ -1,7 +1,6 @@ """ Tests for the api_admin app's views. """ import json -import unittest import ddt import httpretty @@ -16,19 +15,26 @@ from openedx.core.djangoapps.api_admin.tests.factories import ( ApiAccessRequestFactory, ApplicationFactory, CatalogFactory ) from openedx.core.djangoapps.api_admin.tests.utils import VALID_DATA +from openedx.core.djangolib.testing.utils import skip_unless_lms from student.tests.factories import UserFactory Application = get_application_model() # pylint: disable=invalid-name class ApiAdminTest(TestCase): + """ + Base class to allow API admin access to tests. + """ def setUp(self): super(ApiAdminTest, self).setUp() ApiAccessConfig(enabled=True).save() -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class ApiRequestViewTest(ApiAdminTest): + """ + Test the API Request View. + """ def setUp(self): super(ApiRequestViewTest, self).setUp() self.url = reverse('api_admin:api-request') @@ -93,10 +99,13 @@ class ApiRequestViewTest(ApiAdminTest): self.assertEqual(response.status_code, 404) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms @override_settings(PLATFORM_NAME='edX') @ddt.ddt class ApiRequestStatusViewTest(ApiAdminTest): + """ + Tests of the API Status endpoint. + """ def setUp(self): super(ApiRequestStatusViewTest, self).setUp() password = 'abc123' @@ -198,10 +207,15 @@ class ApiRequestStatusViewTest(ApiAdminTest): self.assertIn('Enter a valid URL.', response.content) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class ApiTosViewTest(ApiAdminTest): + """ + Tests of the API terms of service endpoint. + """ def test_get_api_tos(self): - """Verify that the terms of service can be read.""" + """ + Verify that the terms of service can be read. + """ url = reverse('api_admin:api-tos') response = self.client.get(url) self.assertEqual(response.status_code, 200) @@ -209,6 +223,9 @@ class ApiTosViewTest(ApiAdminTest): class CatalogTest(ApiAdminTest): + """ + Test the catalog API. + """ def setUp(self): super(CatalogTest, self).setUp() password = 'abc123' @@ -232,8 +249,11 @@ class CatalogTest(ApiAdminTest): ) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class CatalogSearchViewTest(CatalogTest): + """ + Test the catalog search endpoint. + """ def setUp(self): super(CatalogSearchViewTest, self).setUp() self.url = reverse('api_admin:catalog-search') @@ -254,8 +274,11 @@ class CatalogSearchViewTest(CatalogTest): self.assertRedirects(response, reverse('api_admin:catalog-search')) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class CatalogListViewTest(CatalogTest): + """ + Test the catalog list endpoint. + """ def setUp(self): super(CatalogListViewTest, self).setUp() self.catalog_user = UserFactory() @@ -304,8 +327,11 @@ class CatalogListViewTest(CatalogTest): self.assertEqual(len([r for r in httpretty.httpretty.latest_requests if r.method == 'POST']), 0) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class CatalogEditViewTest(CatalogTest): + """ + Test edits to the catalog endpoint. + """ def setUp(self): super(CatalogEditViewTest, self).setUp() self.catalog_user = UserFactory() @@ -353,8 +379,11 @@ class CatalogEditViewTest(CatalogTest): self.assertEqual(len([r for r in httpretty.httpretty.latest_requests if r.method == 'PATCH']), 0) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class CatalogPreviewViewTest(CatalogTest): + """ + Test the catalog preview endpoint. + """ def setUp(self): super(CatalogPreviewViewTest, self).setUp() self.url = reverse('api_admin:catalog-preview') diff --git a/openedx/core/djangoapps/bookmarks/tests/test_api.py b/openedx/core/djangoapps/bookmarks/tests/test_api.py index 975b3bae09..bb8705306b 100644 --- a/openedx/core/djangoapps/bookmarks/tests/test_api.py +++ b/openedx/core/djangoapps/bookmarks/tests/test_api.py @@ -4,13 +4,13 @@ Tests for bookmarks api. import ddt from mock import patch from nose.plugins.attrib import attr -from unittest import skipUnless from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from opaque_keys.edx.keys import UsageKey +from openedx.core.djangolib.testing.utils import skip_unless_lms from xmodule.modulestore.exceptions import ItemNotFoundError from .. import api @@ -38,7 +38,7 @@ class BookmarkApiEventTestMixin(object): @attr(shard=2) @ddt.ddt -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Tests only valid in LMS') +@skip_unless_lms class BookmarksAPITests(BookmarkApiEventTestMixin, BookmarksTestsBase): """ These tests cover the parts of the API methods. diff --git a/openedx/core/djangoapps/bookmarks/tests/test_models.py b/openedx/core/djangoapps/bookmarks/tests/test_models.py index 6afb63e79f..cdc9ab3d26 100644 --- a/openedx/core/djangoapps/bookmarks/tests/test_models.py +++ b/openedx/core/djangoapps/bookmarks/tests/test_models.py @@ -8,9 +8,6 @@ from freezegun import freeze_time import mock from nose.plugins.attrib import attr import pytz -from unittest import skipUnless - -from django.conf import settings from opaque_keys.edx.keys import UsageKey from opaque_keys.edx.locator import CourseLocator, BlockUsageLocator @@ -19,6 +16,7 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.factories import check_mongo_calls, CourseFactory, ItemFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from openedx.core.djangolib.testing.utils import skip_unless_lms from student.tests.factories import AdminFactory, UserFactory from .. import DEFAULT_FIELDS, OPTIONAL_FIELDS, PathItem @@ -228,7 +226,7 @@ class BookmarksTestsBase(ModuleStoreTestCase): @attr(shard=2) @ddt.ddt -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Tests only valid in LMS') +@skip_unless_lms class BookmarkModelTests(BookmarksTestsBase): """ Test the Bookmark model. diff --git a/openedx/core/djangoapps/bookmarks/tests/test_services.py b/openedx/core/djangoapps/bookmarks/tests/test_services.py index 5dbaea99b2..341803cbdf 100644 --- a/openedx/core/djangoapps/bookmarks/tests/test_services.py +++ b/openedx/core/djangoapps/bookmarks/tests/test_services.py @@ -2,18 +2,16 @@ Tests for bookmark services. """ from nose.plugins.attrib import attr -from unittest import skipUnless - -from django.conf import settings from opaque_keys.edx.keys import UsageKey +from openedx.core.djangolib.testing.utils import skip_unless_lms from ..services import BookmarksService from .test_models import BookmarksTestsBase @attr(shard=2) -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Tests only valid in LMS') +@skip_unless_lms class BookmarksServiceTests(BookmarksTestsBase): """ Tests the Bookmarks service. diff --git a/openedx/core/djangoapps/bookmarks/tests/test_views.py b/openedx/core/djangoapps/bookmarks/tests/test_views.py index c3f0d7dc3d..e8344f70ec 100644 --- a/openedx/core/djangoapps/bookmarks/tests/test_views.py +++ b/openedx/core/djangoapps/bookmarks/tests/test_views.py @@ -5,7 +5,6 @@ Tests for bookmark views. import ddt import json from nose.plugins.attrib import attr -from unittest import skipUnless import urllib from django.conf import settings @@ -13,6 +12,7 @@ from django.core.urlresolvers import reverse from mock import patch from rest_framework.test import APIClient +from openedx.core.djangolib.testing.utils import skip_unless_lms from xmodule.modulestore import ModuleStoreEnum from .test_models import BookmarksTestsBase @@ -66,7 +66,7 @@ class BookmarksViewsTestsBase(BookmarksTestsBase, BookmarkApiEventTestMixin): @attr(shard=2) @ddt.ddt -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Tests only valid in LMS') +@skip_unless_lms class BookmarksListViewTests(BookmarksViewsTestsBase): """ This contains the tests for GET & POST methods of bookmark.views.BookmarksListView class @@ -371,7 +371,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase): @attr(shard=2) @ddt.ddt -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Tests only valid in LMS') +@skip_unless_lms class BookmarksDetailViewTests(BookmarksViewsTestsBase): """ This contains the tests for GET & DELETE methods of bookmark.views.BookmarksDetailView class diff --git a/openedx/core/djangoapps/cache_toolbox/tests/test_middleware.py b/openedx/core/djangoapps/cache_toolbox/tests/test_middleware.py index 2e6744e0ad..adef0877f9 100644 --- a/openedx/core/djangoapps/cache_toolbox/tests/test_middleware.py +++ b/openedx/core/djangoapps/cache_toolbox/tests/test_middleware.py @@ -1,12 +1,10 @@ """Tests for cached authentication middleware.""" -import unittest - -from django.conf import settings from django.contrib.auth.models import User from django.core.urlresolvers import reverse from django.test import TestCase from mock import patch +from openedx.core.djangolib.testing.utils import skip_unless_cms, skip_unless_lms from student.tests.factories import UserFactory @@ -33,13 +31,13 @@ class CachedAuthMiddlewareTestCase(TestCase): response = self.client.get(test_url) self.assertRedirects(response, redirect_url) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms def test_session_change_lms(self): """Test session verification with LMS-specific URLs.""" dashboard_url = reverse('dashboard') self._test_change_session_hash(dashboard_url, reverse('signin_user') + '?next=' + dashboard_url) - @unittest.skipUnless(settings.ROOT_URLCONF == 'cms.urls', 'Test only valid in cms') + @skip_unless_cms def test_session_change_cms(self): """Test session verification with CMS-specific URLs.""" home_url = reverse('home') diff --git a/openedx/core/djangoapps/celery_utils/tests/test_task.py b/openedx/core/djangoapps/celery_utils/tests/test_task.py index a579f7480e..8fd8a511a5 100644 --- a/openedx/core/djangoapps/celery_utils/tests/test_task.py +++ b/openedx/core/djangoapps/celery_utils/tests/test_task.py @@ -5,15 +5,15 @@ Testing persistent tasks from __future__ import print_function from celery import task -from django.conf import settings from django.test import TestCase -from unittest import skipUnless import six +from openedx.core.djangolib.testing.utils import skip_unless_lms from ..models import FailedTask from ..task import PersistOnFailureTask +@skip_unless_lms class PersistOnFailureTaskTestCase(TestCase): """ Test that persistent tasks save the appropriate values when needed. @@ -32,15 +32,12 @@ class PersistOnFailureTaskTestCase(TestCase): cls.exampletask = exampletask super(PersistOnFailureTaskTestCase, cls).setUpClass() - - @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') def test_exampletask_without_failure(self): result = self.exampletask.delay() result.wait() self.assertEqual(result.status, u'SUCCESS') self.assertFalse(FailedTask.objects.exists()) - @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') def test_exampletask_with_failure(self): result = self.exampletask.delay(message=u'The example task failed') with self.assertRaises(ValueError): @@ -57,7 +54,6 @@ class PersistOnFailureTaskTestCase(TestCase): self.assertEqual(failed_task_object.exc, u"ValueError(u'The example task failed',)") self.assertIsNone(failed_task_object.datetime_resolved) - @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') def test_persists_when_called_with_wrong_args(self): result = self.exampletask.delay(15, u'2001-03-04', err=True) with self.assertRaises(TypeError): @@ -67,7 +63,6 @@ class PersistOnFailureTaskTestCase(TestCase): self.assertEqual(failed_task_object.args, [15, u'2001-03-04']) self.assertEqual(failed_task_object.kwargs, {u'err': True}) - @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') def test_persists_with_overlength_field(self): overlong_message = u''.join(u'%03d' % x for x in six.moves.range(100)) result = self.exampletask.delay(message=overlong_message) diff --git a/openedx/core/djangoapps/course_groups/tests/test_partition_scheme.py b/openedx/core/djangoapps/course_groups/tests/test_partition_scheme.py index bc02328a67..bdab552cdf 100644 --- a/openedx/core/djangoapps/course_groups/tests/test_partition_scheme.py +++ b/openedx/core/djangoapps/course_groups/tests/test_partition_scheme.py @@ -2,13 +2,9 @@ Test the partitions and partitions service """ - -import json -from django.conf import settings import django.test from mock import patch from nose.plugins.attrib import attr -from unittest import skipUnless from courseware.masquerade import handle_ajax, setup_masquerade from courseware.tests.test_masquerade import StaffMasqueradeTestCase @@ -19,6 +15,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, TEST_DAT from xmodule.modulestore.tests.factories import ToyCourseFactory from openedx.core.djangoapps.user_api.partition_schemes import RandomUserPartitionScheme +from openedx.core.djangolib.testing.utils import skip_unless_lms from ..partition_scheme import CohortPartitionScheme, get_cohorted_user_partition from ..models import CourseUserGroupPartitionGroup from ..views import link_cohort_to_partition_group, unlink_cohort_partition_group @@ -383,7 +380,7 @@ class TestMasqueradedGroup(StaffMasqueradeTestCase): self._verify_masquerade_for_group(self.user_partition.groups[1]) self._verify_masquerade_for_group(None) - @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS') + @skip_unless_lms @patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) def test_group_masquerade(self): """ @@ -391,7 +388,7 @@ class TestMasqueradedGroup(StaffMasqueradeTestCase): """ self._verify_masquerade_for_all_groups() - @skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS') + @skip_unless_lms @patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False}) def test_group_masquerade_with_cohort(self): """ diff --git a/openedx/core/djangoapps/course_groups/tests/test_views.py b/openedx/core/djangoapps/course_groups/tests/test_views.py index fcef92da52..ca971f1257 100644 --- a/openedx/core/djangoapps/course_groups/tests/test_views.py +++ b/openedx/core/djangoapps/course_groups/tests/test_views.py @@ -8,9 +8,7 @@ import json from collections import namedtuple from datetime import datetime from nose.plugins.attrib import attr -from unittest import skipUnless -from django.conf import settings from django.contrib.auth.models import User from django.http import Http404 from django.test.client import RequestFactory @@ -22,6 +20,8 @@ from xmodule.modulestore.tests.factories import CourseFactory from opaque_keys.edx.locations import SlashSeparatedCourseKey from xmodule.modulestore.tests.factories import ItemFactory from lms.djangoapps.django_comment_client.constants import TYPE_ENTRY, TYPE_SUBCATEGORY +from openedx.core.djangolib.testing.utils import skip_unless_lms + from ..models import CourseUserGroup, CourseCohort from ..views import ( @@ -1207,7 +1207,7 @@ class RemoveUserFromCohortTestCase(CohortViewsTestCase): @attr(shard=2) -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Tests only valid in LMS') +@skip_unless_lms class CourseCohortDiscussionTopicsTestCase(CohortViewsTestCase): """ Tests the `cohort_discussion_topics` view. diff --git a/openedx/core/djangoapps/coursetalk/tests/test_helpers.py b/openedx/core/djangoapps/coursetalk/tests/test_helpers.py index bc742e01d5..379f4ea4f8 100644 --- a/openedx/core/djangoapps/coursetalk/tests/test_helpers.py +++ b/openedx/core/djangoapps/coursetalk/tests/test_helpers.py @@ -1,17 +1,15 @@ """ CourseTalk widget helpers tests """ from __future__ import unicode_literals -from unittest import skipUnless - from django import test -from django.conf import settings from opaque_keys.edx.locations import SlashSeparatedCourseKey from openedx.core.djangoapps.coursetalk import helpers from openedx.core.djangoapps.coursetalk import models +from openedx.core.djangolib.testing.utils import skip_unless_lms -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Tests only valid in LMS') +@skip_unless_lms class CourseTalkKeyTests(test.TestCase): """ CourseTalkKeyTests: diff --git a/openedx/core/djangoapps/credentials/tests/test_models.py b/openedx/core/djangoapps/credentials/tests/test_models.py index e934659f39..1e653610da 100644 --- a/openedx/core/djangoapps/credentials/tests/test_models.py +++ b/openedx/core/djangoapps/credentials/tests/test_models.py @@ -1,14 +1,13 @@ """Tests for models supporting Credentials-related functionality.""" -import unittest - -from django.conf import settings from django.test import TestCase from nose.plugins.attrib import attr + from openedx.core.djangoapps.credentials.tests.mixins import CredentialsApiConfigMixin +from openedx.core.djangolib.testing.utils import skip_unless_lms -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms @attr(shard=2) class TestCredentialsApiConfig(CredentialsApiConfigMixin, TestCase): """Tests covering the CredentialsApiConfig model.""" diff --git a/openedx/core/djangoapps/credentials/tests/test_utils.py b/openedx/core/djangoapps/credentials/tests/test_utils.py index 87b1c2a26e..443eec7029 100644 --- a/openedx/core/djangoapps/credentials/tests/test_utils.py +++ b/openedx/core/djangoapps/credentials/tests/test_utils.py @@ -1,7 +1,4 @@ """Tests covering Credentials utilities.""" -import unittest - -from django.conf import settings from django.core.cache import cache from nose.plugins.attrib import attr import httpretty @@ -18,11 +15,11 @@ from openedx.core.djangoapps.credentials.utils import ( from openedx.core.djangoapps.credentials.tests import factories from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin from openedx.core.djangoapps.programs.models import ProgramsApiConfig -from openedx.core.djangolib.testing.utils import CacheIsolationTestCase +from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms from student.tests.factories import UserFactory -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms @attr(shard=2) class TestCredentialsRetrieval(ProgramsApiConfigMixin, CredentialsApiConfigMixin, CredentialsDataMixin, ProgramsDataMixin, CacheIsolationTestCase): diff --git a/openedx/core/djangoapps/credit/tests/test_api.py b/openedx/core/djangoapps/credit/tests/test_api.py index cf3fe723fe..da7f374965 100644 --- a/openedx/core/djangoapps/credit/tests/test_api.py +++ b/openedx/core/djangoapps/credit/tests/test_api.py @@ -3,10 +3,8 @@ Tests for the API functions in the credit app. """ import datetime import json -import unittest import ddt -from django.conf import settings from django.contrib.auth.models import User from django.core import mail from django.test.utils import override_settings @@ -36,6 +34,7 @@ from openedx.core.djangoapps.credit.models import ( CreditEligibility, CreditRequest ) +from openedx.core.djangolib.testing.utils import skip_unless_lms from course_modes.models import CourseMode from student.models import CourseEnrollment from student.tests.factories import UserFactory @@ -203,7 +202,7 @@ class CreditApiTestBase(ModuleStoreTestCase): @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS') +@skip_unless_lms @ddt.ddt class CreditRequirementApiTests(CreditApiTestBase): """ @@ -1165,7 +1164,7 @@ class CreditProviderIntegrationApiTests(CreditApiTestBase): @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS') +@skip_unless_lms @override_settings( ECOMMERCE_API_URL=TEST_API_URL, ECOMMERCE_API_SIGNING_KEY=TEST_API_SIGNING_KEY, diff --git a/openedx/core/djangoapps/credit/tests/test_partition.py b/openedx/core/djangoapps/credit/tests/test_partition.py index c1d893ef39..1fff58795e 100644 --- a/openedx/core/djangoapps/credit/tests/test_partition.py +++ b/openedx/core/djangoapps/credit/tests/test_partition.py @@ -5,9 +5,6 @@ Tests for In-Course Reverification Access Control Partition scheme import ddt from nose.plugins.attrib import attr -import unittest - -from django.conf import settings from lms.djangoapps.verify_student.models import ( VerificationCheckpoint, @@ -15,6 +12,7 @@ from lms.djangoapps.verify_student.models import ( SkippedReverification, ) from openedx.core.djangoapps.credit.partition_schemes import VerificationPartitionScheme +from openedx.core.djangolib.testing.utils import skip_unless_lms from student.models import CourseEnrollment from student.tests.factories import UserFactory from xmodule.partitions.partitions import UserPartition, Group @@ -24,7 +22,7 @@ from xmodule.modulestore.tests.factories import CourseFactory @attr(shard=2) @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class ReverificationPartitionTest(ModuleStoreTestCase): """Tests for the Reverification Partition Scheme. """ diff --git a/openedx/core/djangoapps/credit/tests/test_signals.py b/openedx/core/djangoapps/credit/tests/test_signals.py index a3abe179b9..50566faf3c 100644 --- a/openedx/core/djangoapps/credit/tests/test_signals.py +++ b/openedx/core/djangoapps/credit/tests/test_signals.py @@ -6,9 +6,7 @@ import ddt import pytz from datetime import timedelta, datetime from mock import MagicMock -from unittest import skipUnless -from django.conf import settings from django.test.client import RequestFactory from nose.plugins.attrib import attr from course_modes.models import CourseMode @@ -22,10 +20,11 @@ from openedx.core.djangoapps.credit.api import ( ) from openedx.core.djangoapps.credit.models import CreditCourse, CreditProvider from openedx.core.djangoapps.credit.signals import listen_for_grade_calculation +from openedx.core.djangolib.testing.utils import skip_unless_lms @attr(shard=2) -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS') +@skip_unless_lms @ddt.ddt class TestMinGradedRequirementStatus(ModuleStoreTestCase): """Test cases to check the minimum grade requirement status updated. diff --git a/openedx/core/djangoapps/credit/tests/test_views.py b/openedx/core/djangoapps/credit/tests/test_views.py index a438b4b20e..72cb2a58c3 100644 --- a/openedx/core/djangoapps/credit/tests/test_views.py +++ b/openedx/core/djangoapps/credit/tests/test_views.py @@ -8,7 +8,6 @@ from __future__ import unicode_literals import datetime import json -import unittest import ddt import pytz @@ -28,6 +27,7 @@ from openedx.core.djangoapps.credit.signature import signature from openedx.core.djangoapps.credit.tests.factories import ( CreditProviderFactory, CreditEligibilityFactory, CreditCourseFactory, CreditRequestFactory, ) +from openedx.core.djangolib.testing.utils import skip_unless_lms from openedx.core.lib.token_utils import JwtBuilder from student.tests.factories import UserFactory, AdminFactory from util.date_utils import to_timestamp @@ -113,7 +113,7 @@ class ReadOnlyMixin(object): @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class CreditCourseViewSetTests(AuthMixin, UserMixin, TestCase): """ Tests for the CreditCourse endpoints. @@ -276,7 +276,7 @@ class CreditCourseViewSetTests(AuthMixin, UserMixin, TestCase): @attr(shard=2) @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class CreditProviderViewSetTests(ApiTestCaseMixin, ReadOnlyMixin, AuthMixin, UserMixin, TestCase): """ Tests for CreditProviderViewSet. """ list_path = 'credit:creditprovider-list' @@ -320,7 +320,7 @@ class CreditProviderViewSetTests(ApiTestCaseMixin, ReadOnlyMixin, AuthMixin, Use @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class CreditProviderRequestCreateViewTests(ApiTestCaseMixin, UserMixin, TestCase): """ Tests for CreditProviderRequestCreateView. """ @@ -470,7 +470,7 @@ class CreditProviderRequestCreateViewTests(ApiTestCaseMixin, UserMixin, TestCase @attr(shard=2) @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class CreditProviderCallbackViewTests(UserMixin, TestCase): """ Tests for CreditProviderCallbackView. """ @@ -624,7 +624,7 @@ class CreditProviderCallbackViewTests(UserMixin, TestCase): @attr(shard=2) @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class CreditEligibilityViewTests(AuthMixin, UserMixin, ReadOnlyMixin, TestCase): """ Tests for CreditEligibilityView. """ view_name = 'credit:eligibility_details' diff --git a/openedx/core/djangoapps/embargo/tests/test_api.py b/openedx/core/djangoapps/embargo/tests/test_api.py index 614e5cd67d..7f17010fc7 100644 --- a/openedx/core/djangoapps/embargo/tests/test_api.py +++ b/openedx/core/djangoapps/embargo/tests/test_api.py @@ -5,7 +5,6 @@ Tests for EmbargoMiddleware from contextlib import contextmanager import mock from nose.plugins.attrib import attr -import unittest import pygeoip import ddt @@ -14,6 +13,7 @@ from django.test.utils import override_settings from django.core.cache import cache from django.db import connection +from openedx.core.djangolib.testing.utils import skip_unless_lms from student.tests.factories import UserFactory from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.django_utils import ( @@ -41,7 +41,7 @@ MODULESTORE_CONFIG = mixed_store_config(settings.COMMON_TEST_DATA_ROOT, {}) @attr(shard=3) @ddt.ddt @override_settings(MODULESTORE=MODULESTORE_CONFIG) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms @mock.patch.dict(settings.FEATURES, {'EMBARGO': True}) class EmbargoCheckAccessApiTests(ModuleStoreTestCase): """Test the embargo API calls to determine whether a user has access. """ @@ -239,7 +239,7 @@ class EmbargoCheckAccessApiTests(ModuleStoreTestCase): @ddt.ddt @override_settings(MODULESTORE=MODULESTORE_CONFIG) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class EmbargoMessageUrlApiTests(UrlResetMixin, ModuleStoreTestCase): """Test the embargo API calls for retrieving the blocking message URLs. """ diff --git a/openedx/core/djangoapps/embargo/tests/test_middleware.py b/openedx/core/djangoapps/embargo/tests/test_middleware.py index cd64ab691c..bf1d7a35ed 100644 --- a/openedx/core/djangoapps/embargo/tests/test_middleware.py +++ b/openedx/core/djangoapps/embargo/tests/test_middleware.py @@ -2,7 +2,6 @@ Tests for EmbargoMiddleware with CountryAccessRules """ -import unittest from mock import patch from nose.plugins.attrib import attr import ddt @@ -11,11 +10,12 @@ from django.core.urlresolvers import reverse from django.conf import settings from django.core.cache import cache as django_cache +from config_models.models import cache as config_cache +from openedx.core.djangolib.testing.utils import skip_unless_lms from util.testing import UrlResetMixin from student.tests.factories import UserFactory from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase -from config_models.models import cache as config_cache from ..models import RestrictedCourse, IPFilter from ..test_utils import restrict_course @@ -23,7 +23,7 @@ from ..test_utils import restrict_course @attr(shard=3) @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class EmbargoMiddlewareAccessTests(UrlResetMixin, ModuleStoreTestCase): """Tests of embargo middleware country access rules. diff --git a/openedx/core/djangoapps/embargo/tests/test_views.py b/openedx/core/djangoapps/embargo/tests/test_views.py index 48afff368c..f9b00c566e 100644 --- a/openedx/core/djangoapps/embargo/tests/test_views.py +++ b/openedx/core/djangoapps/embargo/tests/test_views.py @@ -1,6 +1,5 @@ """Tests for embargo app views. """ -import unittest from mock import patch from django.core.urlresolvers import reverse from django.conf import settings @@ -8,11 +7,11 @@ import ddt from util.testing import UrlResetMixin from .. import messages -from openedx.core.djangolib.testing.utils import CacheIsolationTestCase +from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms @ddt.ddt class CourseAccessMessageViewTest(CacheIsolationTestCase, UrlResetMixin): """Tests for the courseware access message view. diff --git a/openedx/core/djangoapps/external_auth/tests/test_ssl.py b/openedx/core/djangoapps/external_auth/tests/test_ssl.py index 910a20e822..71e1a11802 100644 --- a/openedx/core/djangoapps/external_auth/tests/test_ssl.py +++ b/openedx/core/djangoapps/external_auth/tests/test_ssl.py @@ -3,10 +3,10 @@ Provides unit tests for SSL based authentication portions of the external_auth app. """ # pylint: disable=no-member -import copy -import unittest - from contextlib import contextmanager +import copy +from mock import Mock, patch + from django.conf import settings from django.contrib.auth import SESSION_KEY from django.contrib.auth.models import AnonymousUser, User @@ -15,10 +15,10 @@ from django.core.urlresolvers import reverse from django.test.client import Client from django.test.client import RequestFactory from django.test.utils import override_settings -from mock import Mock, patch from openedx.core.djangoapps.external_auth.models import ExternalAuthMap import openedx.core.djangoapps.external_auth.views as external_auth_views +from openedx.core.djangolib.testing.utils import skip_unless_cms, skip_unless_lms from student.models import CourseEnrollment from student.roles import CourseStaffRole from student.tests.factories import UserFactory @@ -81,7 +81,7 @@ class SSLClientTest(ModuleStoreTestCase): self.factory = RequestFactory() self.mock = Mock() - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms def test_ssl_login_with_signup_lms(self): """ Validate that an SSL login creates an eamap user and @@ -101,7 +101,7 @@ class SSLClientTest(ModuleStoreTestCase): with self.assertRaises(User.DoesNotExist): User.objects.get(email=self.USER_EMAIL) - @unittest.skipUnless(settings.ROOT_URLCONF == 'cms.urls', 'Test only valid in cms') + @skip_unless_cms def test_ssl_login_with_signup_cms(self): """ Validate that an SSL login creates an eamap user and @@ -120,7 +120,7 @@ class SSLClientTest(ModuleStoreTestCase): with self.assertRaises(User.DoesNotExist): User.objects.get(email=self.USER_EMAIL) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_IMMEDIATE_SIGNUP) def test_ssl_login_without_signup_lms(self): """ @@ -140,7 +140,7 @@ class SSLClientTest(ModuleStoreTestCase): except ExternalAuthMap.DoesNotExist, ex: self.fail('User did not get properly added to internal users, exception was {0}'.format(str(ex))) - @unittest.skipUnless(settings.ROOT_URLCONF == 'cms.urls', 'Test only valid in cms') + @skip_unless_cms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_IMMEDIATE_SIGNUP) def test_ssl_login_without_signup_cms(self): """ @@ -166,7 +166,7 @@ class SSLClientTest(ModuleStoreTestCase): except ExternalAuthMap.DoesNotExist, ex: self.fail('User did not get properly added to internal users, exception was {0}'.format(str(ex))) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_IMMEDIATE_SIGNUP) def test_default_login_decorator_ssl(self): """ @@ -184,7 +184,7 @@ class SSLClientTest(ModuleStoreTestCase): response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_IMMEDIATE_SIGNUP) def test_registration_page_bypass(self): """ @@ -198,7 +198,7 @@ class SSLClientTest(ModuleStoreTestCase): response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) - @unittest.skipUnless(settings.ROOT_URLCONF == 'cms.urls', 'Test only valid in cms') + @skip_unless_cms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_IMMEDIATE_SIGNUP) def test_cms_registration_page_bypass(self): """ @@ -217,7 +217,7 @@ class SSLClientTest(ModuleStoreTestCase): response = self.client.get(reverse('signup'), follow=True) self.assertEqual(response.status_code, 404) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_IMMEDIATE_SIGNUP) def test_signin_page_bypass(self): """ @@ -238,7 +238,7 @@ class SSLClientTest(ModuleStoreTestCase): response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_IMMEDIATE_SIGNUP) def test_ssl_bad_eamap(self): """ @@ -263,7 +263,7 @@ class SSLClientTest(ModuleStoreTestCase): SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL)) self.assertIn(SESSION_KEY, self.client.session) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms @override_settings(FEATURES=FEATURES_WITHOUT_SSL_AUTH) def test_ssl_decorator_no_certs(self): """Make sure no external auth happens without SSL enabled""" @@ -279,7 +279,7 @@ class SSLClientTest(ModuleStoreTestCase): self.assertTrue(self.mock.called) self.assertEqual(0, len(ExternalAuthMap.objects.all())) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms def test_ssl_login_decorator(self): """Create mock function to test ssl login decorator""" @@ -305,7 +305,7 @@ class SSLClientTest(ModuleStoreTestCase): dec_mock(request) self.assertTrue(self.mock.called) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_IMMEDIATE_SIGNUP) def test_ssl_decorator_auto_signup(self): """ @@ -330,7 +330,7 @@ class SSLClientTest(ModuleStoreTestCase): self.assertTrue(self.mock.called) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_AUTO_ACTIVATE) def test_ssl_lms_redirection(self): """ @@ -361,7 +361,7 @@ class SSLClientTest(ModuleStoreTestCase): response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) - @unittest.skipUnless(settings.ROOT_URLCONF == 'cms.urls', 'Test only valid in cms') + @skip_unless_cms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_AUTO_ACTIVATE) def test_ssl_cms_redirection(self): """ @@ -393,7 +393,7 @@ class SSLClientTest(ModuleStoreTestCase): response.redirect_chain[-1]) self.assertIn(SESSION_KEY, self.client.session) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms @override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_AUTO_ACTIVATE) def test_ssl_logout(self): """ diff --git a/openedx/core/djangoapps/profile_images/tests/test_images.py b/openedx/core/djangoapps/profile_images/tests/test_images.py index 27b43a5b21..40e3474092 100644 --- a/openedx/core/djangoapps/profile_images/tests/test_images.py +++ b/openedx/core/djangoapps/profile_images/tests/test_images.py @@ -5,9 +5,7 @@ from contextlib import closing from itertools import product import os from tempfile import NamedTemporaryFile -import unittest -from django.conf import settings from django.core.files.uploadedfile import UploadedFile from django.test import TestCase from django.test.utils import override_settings @@ -17,6 +15,7 @@ from nose.plugins.attrib import attr import piexif from PIL import Image +from openedx.core.djangolib.testing.utils import skip_unless_lms from ..exceptions import ImageValidationError from ..images import ( create_profile_images, @@ -31,7 +30,7 @@ from .helpers import make_image_file, make_uploaded_file @attr(shard=2) @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Profile Image API is only supported in LMS') +@skip_unless_lms class TestValidateUploadedImage(TestCase): """ Test validate_uploaded_image @@ -127,7 +126,7 @@ class TestValidateUploadedImage(TestCase): @attr(shard=2) @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Profile Image API is only supported in LMS') +@skip_unless_lms class TestGenerateProfileImages(TestCase): """ Test create_profile_images @@ -224,7 +223,7 @@ class TestGenerateProfileImages(TestCase): @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Profile Image API is only supported in LMS') +@skip_unless_lms class TestRemoveProfileImages(TestCase): """ Test remove_profile_images diff --git a/openedx/core/djangoapps/profile_images/tests/test_views.py b/openedx/core/djangoapps/profile_images/tests/test_views.py index c54934d4bf..9f885a37de 100644 --- a/openedx/core/djangoapps/profile_images/tests/test_views.py +++ b/openedx/core/djangoapps/profile_images/tests/test_views.py @@ -5,9 +5,7 @@ from contextlib import closing import datetime from nose.plugins.attrib import attr from pytz import UTC -import unittest -from django.conf import settings from django.core.urlresolvers import reverse from django.http import HttpResponse @@ -24,6 +22,7 @@ from openedx.core.djangoapps.user_api.accounts.image_helpers import ( get_profile_image_names, get_profile_image_storage, ) +from openedx.core.djangolib.testing.utils import skip_unless_lms from ..images import create_profile_images, ImageValidationError from ..views import LOG_MESSAGE_CREATE, LOG_MESSAGE_DELETE @@ -153,7 +152,7 @@ class ProfileImageEndpointMixin(UserSettingsEventTestMixin): @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Profile Image API is only supported in LMS') +@skip_unless_lms @mock.patch('openedx.core.djangoapps.profile_images.views.log') class ProfileImageViewGeneralTestCase(ProfileImageEndpointMixin, APITestCase): """ @@ -174,7 +173,7 @@ class ProfileImageViewGeneralTestCase(ProfileImageEndpointMixin, APITestCase): @attr(shard=2) @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Profile Image API is only supported in LMS') +@skip_unless_lms @mock.patch('openedx.core.djangoapps.profile_images.views.log') class ProfileImageViewPostTestCase(ProfileImageEndpointMixin, APITestCase): """ @@ -384,7 +383,7 @@ class ProfileImageViewPostTestCase(ProfileImageEndpointMixin, APITestCase): @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Profile Image API is only supported in LMS') +@skip_unless_lms @mock.patch('openedx.core.djangoapps.profile_images.views.log') class ProfileImageViewDeleteTestCase(ProfileImageEndpointMixin, APITestCase): """ @@ -515,7 +514,7 @@ class DeprecatedProfileImageTestMixin(ProfileImageEndpointMixin): @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Profile Image API is only supported in LMS') +@skip_unless_lms @mock.patch('openedx.core.djangoapps.profile_images.views.log') class DeprecatedProfileImageUploadTestCase(DeprecatedProfileImageTestMixin, APITestCase): """ @@ -528,7 +527,7 @@ class DeprecatedProfileImageUploadTestCase(DeprecatedProfileImageTestMixin, APIT @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Profile Image API is only supported in LMS') +@skip_unless_lms @mock.patch('openedx.core.djangoapps.profile_images.views.log') class DeprecatedProfileImageRemoveTestCase(DeprecatedProfileImageTestMixin, APITestCase): """ diff --git a/openedx/core/djangoapps/programs/tasks/v1/tests/test_tasks.py b/openedx/core/djangoapps/programs/tasks/v1/tests/test_tasks.py index 642b2d20dc..73e360e88b 100644 --- a/openedx/core/djangoapps/programs/tasks/v1/tests/test_tasks.py +++ b/openedx/core/djangoapps/programs/tasks/v1/tests/test_tasks.py @@ -2,7 +2,6 @@ Tests for programs celery tasks. """ import json -import unittest from celery.exceptions import MaxRetriesExceededError import ddt @@ -20,7 +19,7 @@ from openedx.core.djangoapps.credentials.tests.mixins import CredentialsApiConfi from openedx.core.djangoapps.programs.tests import factories from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin from openedx.core.djangoapps.programs.tasks.v1 import tasks -from openedx.core.djangolib.testing.utils import CacheIsolationTestCase +from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms from student.tests.factories import UserFactory @@ -28,7 +27,7 @@ TASKS_MODULE = 'openedx.core.djangoapps.programs.tasks.v1.tasks' UTILS_MODULE = 'openedx.core.djangoapps.programs.utils' -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class GetApiClientTestCase(TestCase, ProgramsApiConfigMixin): """ Test the get_api_client function @@ -53,7 +52,7 @@ class GetApiClientTestCase(TestCase, ProgramsApiConfigMixin): @httpretty.activate -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class GetCompletedProgramsTestCase(ProgramsApiConfigMixin, CacheIsolationTestCase): """ Test the get_completed_programs function @@ -113,7 +112,7 @@ class GetCompletedProgramsTestCase(ProgramsApiConfigMixin, CacheIsolationTestCas self._assert_num_requests(1) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class GetAwardedCertificateProgramsTestCase(TestCase): """ Test the get_awarded_certificate_programs function @@ -154,7 +153,7 @@ class GetAwardedCertificateProgramsTestCase(TestCase): self.assertEqual(result, [1]) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class AwardProgramCertificateTestCase(TestCase): """ Test the award_program_certificate function @@ -183,7 +182,7 @@ class AwardProgramCertificateTestCase(TestCase): self.assertEqual(json.loads(httpretty.last_request().body), expected_body) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms @ddt.ddt @mock.patch(TASKS_MODULE + '.award_program_certificate') @mock.patch(TASKS_MODULE + '.get_awarded_certificate_programs') diff --git a/openedx/core/djangoapps/programs/tests/test_backpopulate_program_credentials.py b/openedx/core/djangoapps/programs/tests/test_backpopulate_program_credentials.py index e28f9204a7..9382139210 100644 --- a/openedx/core/djangoapps/programs/tests/test_backpopulate_program_credentials.py +++ b/openedx/core/djangoapps/programs/tests/test_backpopulate_program_credentials.py @@ -1,9 +1,7 @@ """Tests for the backpopulate_program_credentials management command.""" import json -from unittest import skipUnless import ddt -from django.conf import settings from django.core.management import call_command, CommandError from django.test import TestCase from edx_oauth2_provider.tests.factories import ClientFactory @@ -17,6 +15,7 @@ from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFact from openedx.core.djangoapps.programs.models import ProgramsApiConfig from openedx.core.djangoapps.programs.tests import factories from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin +from openedx.core.djangolib.testing.utils import skip_unless_lms from student.tests.factories import UserFactory @@ -26,7 +25,7 @@ COMMAND_MODULE = 'openedx.core.djangoapps.programs.management.commands.backpopul @ddt.ddt @httpretty.activate @mock.patch(COMMAND_MODULE + '.award_program_certificates.delay') -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class BackpopulateProgramCredentialsTests(ProgramsApiConfigMixin, TestCase): """Tests for the backpopulate_program_credentials management command.""" course_id, alternate_course_id = 'org/course/run', 'org/alternate/run' diff --git a/openedx/core/djangoapps/programs/tests/test_utils.py b/openedx/core/djangoapps/programs/tests/test_utils.py index 4e42b8c6ef..f72bd4f5a7 100644 --- a/openedx/core/djangoapps/programs/tests/test_utils.py +++ b/openedx/core/djangoapps/programs/tests/test_utils.py @@ -2,11 +2,9 @@ import copy import datetime import json -from unittest import skipUnless import uuid import ddt -from django.conf import settings from django.core.cache import cache from django.core.urlresolvers import reverse from django.test import TestCase @@ -29,7 +27,7 @@ from openedx.core.djangoapps.programs import utils from openedx.core.djangoapps.programs.models import ProgramsApiConfig from openedx.core.djangoapps.programs.tests import factories from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin -from openedx.core.djangolib.testing.utils import CacheIsolationTestCase +from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms from student.tests.factories import UserFactory, CourseEnrollmentFactory from util.date_utils import strftime_localized from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @@ -45,7 +43,7 @@ MARKETING_URL = 'https://www.example.com/marketing/path' @ddt.ddt @attr(shard=2) @httpretty.activate -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestProgramRetrieval(ProgramsApiConfigMixin, ProgramsDataMixin, CredentialsDataMixin, CredentialsApiConfigMixin, CacheIsolationTestCase): """Tests covering the retrieval of programs from the Programs service.""" @@ -190,7 +188,7 @@ class TestProgramRetrieval(ProgramsApiConfigMixin, ProgramsDataMixin, Credential self.assertEqual(actual, []) -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class GetProgramsByRunTests(TestCase): """Tests verifying that programs are inverted correctly.""" maxDiff = None @@ -262,7 +260,7 @@ class GetProgramsByRunTests(TestCase): self.assertEqual(course_ids, []) -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class GetCompletedCoursesTestCase(TestCase): """ Test the get_completed_courses function @@ -308,7 +306,7 @@ class GetCompletedCoursesTestCase(TestCase): @attr(shard=2) @httpretty.activate -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestProgramProgressMeter(ProgramsApiConfigMixin, TestCase): """Tests of the program progress utility class.""" def setUp(self): @@ -700,7 +698,7 @@ class TestProgramProgressMeter(ProgramsApiConfigMixin, TestCase): @ddt.ddt @override_settings(ECOMMERCE_PUBLIC_URL_ROOT=ECOMMERCE_URL_ROOT) -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms @mock.patch(UTILS_MODULE + '.get_run_marketing_url', mock.Mock(return_value=MARKETING_URL)) class TestProgramDataExtender(ProgramsApiConfigMixin, ModuleStoreTestCase): """Tests of the program data extender utility class.""" diff --git a/openedx/core/djangoapps/site_configuration/tests/test_middleware.py b/openedx/core/djangoapps/site_configuration/tests/test_middleware.py index 97850352f9..48277a4f7b 100644 --- a/openedx/core/djangoapps/site_configuration/tests/test_middleware.py +++ b/openedx/core/djangoapps/site_configuration/tests/test_middleware.py @@ -3,7 +3,6 @@ Test site_configuration middleware. """ import ddt -import unittest from mock import patch from django.conf import settings @@ -22,6 +21,7 @@ from microsite_configuration.tests.tests import ( MICROSITE_BACKENDS, ) from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory, SiteFactory +from openedx.core.djangolib.testing.utils import skip_unless_lms # NOTE: We set SESSION_SAVE_EVERY_REQUEST to True in order to make sure @@ -29,7 +29,7 @@ from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfi # pylint: disable=no-member, protected-access @ddt.ddt @override_settings(SESSION_SAVE_EVERY_REQUEST=True) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class SessionCookieDomainMicrositeOverrideTests(DatabaseMicrositeTestCase): """ Tests regarding the session cookie management in the middlware for Microsites diff --git a/openedx/core/djangoapps/theming/tests/test_finders.py b/openedx/core/djangoapps/theming/tests/test_finders.py index 83497603f1..f429f0f259 100644 --- a/openedx/core/djangoapps/theming/tests/test_finders.py +++ b/openedx/core/djangoapps/theming/tests/test_finders.py @@ -1,15 +1,15 @@ """ Tests for comprehensive theme static files finders. """ -import unittest from django.conf import settings from django.test import TestCase from openedx.core.djangoapps.theming.finders import ThemeFilesFinder +from openedx.core.djangolib.testing.utils import skip_unless_lms -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestThemeFinders(TestCase): """ Test comprehensive theming static files finders. diff --git a/openedx/core/djangoapps/theming/tests/test_helpers.py b/openedx/core/djangoapps/theming/tests/test_helpers.py index b8ffd048a7..cdac467a67 100644 --- a/openedx/core/djangoapps/theming/tests/test_helpers.py +++ b/openedx/core/djangoapps/theming/tests/test_helpers.py @@ -1,7 +1,6 @@ """ Test helpers for Comprehensive Theming. """ -import unittest from mock import patch, Mock from django.test import TestCase, override_settings @@ -12,6 +11,7 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_ from openedx.core.djangoapps.theming import helpers as theming_helpers from openedx.core.djangoapps.theming.helpers import get_template_path_with_theme, strip_site_theme_templates_path, \ get_themes, Theme, get_theme_base_dir +from openedx.core.djangolib.testing.utils import skip_unless_cms, skip_unless_lms class TestHelpers(TestCase): @@ -201,7 +201,7 @@ class TestHelpers(TestCase): self.assertEqual(theming_helpers.get_template_path("about.html"), "/microsite/about.html") -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestHelpersLMS(TestCase): """Test comprehensive theming helper functions.""" @@ -244,7 +244,7 @@ class TestHelpersLMS(TestCase): self.assertEqual(template_path, '/red-theme/lms/templates/header.html') -@unittest.skipUnless(settings.ROOT_URLCONF == 'cms.urls', 'Test only valid in cms') +@skip_unless_cms class TestHelpersCMS(TestCase): """Test comprehensive theming helper functions.""" diff --git a/openedx/core/djangoapps/theming/tests/test_microsites.py b/openedx/core/djangoapps/theming/tests/test_microsites.py index 0f3a79fba1..1cb6c007af 100644 --- a/openedx/core/djangoapps/theming/tests/test_microsites.py +++ b/openedx/core/djangoapps/theming/tests/test_microsites.py @@ -1,16 +1,15 @@ """ Tests for microsites and comprehensive themes. """ -import unittest - from django.conf import settings from django.test import TestCase from django.contrib.sites.models import Site from openedx.core.djangoapps.theming.models import SiteTheme +from openedx.core.djangolib.testing.utils import skip_unless_lms -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestComprehensiveThemeLMS(TestCase): """ Test html, sass and static file overrides for comprehensive themes. diff --git a/openedx/core/djangoapps/theming/tests/test_storage.py b/openedx/core/djangoapps/theming/tests/test_storage.py index f0d544743f..35409fc079 100644 --- a/openedx/core/djangoapps/theming/tests/test_storage.py +++ b/openedx/core/djangoapps/theming/tests/test_storage.py @@ -2,7 +2,6 @@ Tests for comprehensive theme static files storage classes. """ import ddt -import unittest import re from mock import patch @@ -12,9 +11,10 @@ from django.conf import settings from openedx.core.djangoapps.theming.helpers import get_theme_base_dirs, Theme, get_theme_base_dir from openedx.core.djangoapps.theming.storage import ThemeStorage +from openedx.core.djangolib.testing.utils import skip_unless_lms -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms @ddt.ddt class TestStorageLMS(TestCase): """ diff --git a/openedx/core/djangoapps/theming/tests/test_theme_locales.py b/openedx/core/djangoapps/theming/tests/test_theme_locales.py index f577ef23bd..3cc7bc4e53 100644 --- a/openedx/core/djangoapps/theming/tests/test_theme_locales.py +++ b/openedx/core/djangoapps/theming/tests/test_theme_locales.py @@ -1,18 +1,19 @@ """ -Tests for Themeing locales +Tests for Theming locales """ +import os -import unittest from django.conf import settings from django.test import TestCase -import os + +from openedx.core.djangolib.testing.utils import skip_unless_lms class TestComprehensiveThemeLocale(TestCase): """ Test Comprehensive Theme Locales """ - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms def test_theme_locale_path_in_settings(self): """ test comprehensive theming paths in settings. diff --git a/openedx/core/djangoapps/theming/tests/test_theme_style_overrides.py b/openedx/core/djangoapps/theming/tests/test_theme_style_overrides.py index e6bbad5f7f..a1a0c8d0b3 100644 --- a/openedx/core/djangoapps/theming/tests/test_theme_style_overrides.py +++ b/openedx/core/djangoapps/theming/tests/test_theme_style_overrides.py @@ -1,18 +1,17 @@ """ - Tests for comprehensive themes. +Tests for comprehensive themes. """ -import unittest - from django.conf import settings from django.core.urlresolvers import reverse from django.test import TestCase from django.contrib import staticfiles from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme +from openedx.core.djangolib.testing.utils import skip_unless_cms, skip_unless_lms from student.tests.factories import UserFactory -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestComprehensiveThemeLMS(TestCase): """ Test html, sass and static file overrides for comprehensive themes. @@ -66,7 +65,7 @@ class TestComprehensiveThemeLMS(TestCase): self.assertEqual(result, settings.TEST_THEME / 'lms/static/images/logo.png') -@unittest.skipUnless(settings.ROOT_URLCONF == 'cms.urls', 'Test only valid in cms') +@skip_unless_cms class TestComprehensiveThemeCMS(TestCase): """ Test html, sass and static file overrides for comprehensive themes. @@ -92,7 +91,7 @@ class TestComprehensiveThemeCMS(TestCase): self.assertContains(resp, "Login Page override for test-theme.") -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestComprehensiveThemeDisabledLMS(TestCase): """ Test Sass compilation order and sass overrides for comprehensive themes. @@ -115,7 +114,7 @@ class TestComprehensiveThemeDisabledLMS(TestCase): self.assertEqual(result, settings.REPO_ROOT / 'lms/static/images/logo.png') -@unittest.skipUnless(settings.ROOT_URLCONF == 'cms.urls', 'Test only valid in cms') +@skip_unless_cms class TestComprehensiveThemeDisabledCMS(TestCase): """ Test default html, sass and static file when no theme is applied. @@ -139,7 +138,7 @@ class TestComprehensiveThemeDisabledCMS(TestCase): self.assertNotContains(resp, "Login Page override for test-theme.") -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestStanfordTheme(TestCase): """ Test html, sass and static file overrides for stanford theme. diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_api.py b/openedx/core/djangoapps/user_api/accounts/tests/test_api.py index 348f636db2..514d322739 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_api.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_api.py @@ -17,6 +17,7 @@ from django.conf import settings from django.contrib.auth.models import User from django.core import mail from django.test.client import RequestFactory +from openedx.core.djangolib.testing.utils import skip_unless_lms from student.models import PendingEmailChange from student.tests.tests import UserSettingsEventTestMixin from ...errors import ( @@ -35,7 +36,7 @@ def mock_render_to_string(template_name, context): @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Account APIs are only supported in LMS') +@skip_unless_lms class TestAccountApi(UserSettingsEventTestMixin, TestCase): """ These tests specifically cover the parts of the API methods that are not covered by test_views.py. @@ -239,7 +240,7 @@ class TestAccountApi(UserSettingsEventTestMixin, TestCase): {'full': 50, 'small': 10}, clear=True ) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Account APIs are only supported in LMS') +@skip_unless_lms class AccountSettingsOnCreationTest(TestCase): # pylint: disable=missing-docstring @@ -333,7 +334,7 @@ class AccountCreationActivationAndPasswordChangeTest(TestCase): u'a' * (PASSWORD_MAX_LENGTH + 1) ] - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @skip_unless_lms def test_activate_account(self): # Create the account, which is initially inactive activation_key = create_account(self.USERNAME, self.PASSWORD, self.EMAIL) @@ -393,7 +394,7 @@ class AccountCreationActivationAndPasswordChangeTest(TestCase): def test_activate_account_invalid_key(self): activate_account(u'invalid') - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS') + @skip_unless_lms def test_request_password_change(self): # Create and activate an account activation_key = create_account(self.USERNAME, self.PASSWORD, self.EMAIL) @@ -411,7 +412,7 @@ class AccountCreationActivationAndPasswordChangeTest(TestCase): result = re.search(r'(?Phttps?://[^\s]+)', email_body) self.assertIsNot(result, None) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS') + @skip_unless_lms def test_request_password_change_invalid_user(self): with self.assertRaises(UserNotFound): request_password_change(self.EMAIL, self.ORIG_HOST, self.IS_SECURE) @@ -419,7 +420,7 @@ class AccountCreationActivationAndPasswordChangeTest(TestCase): # Verify that no email messages have been sent self.assertEqual(len(mail.outbox), 0) - @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS') + @skip_unless_lms def test_request_password_change_inactive_user(self): # Create an account, but do not activate it create_account(self.USERNAME, self.PASSWORD, self.EMAIL) diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_image_helpers.py b/openedx/core/djangoapps/user_api/accounts/tests/test_image_helpers.py index 6197d1eb62..41014691b5 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_image_helpers.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_image_helpers.py @@ -6,13 +6,12 @@ import hashlib from mock import patch from nose.plugins.attrib import attr from pytz import UTC -from unittest import skipUnless -from django.conf import settings from django.test import TestCase -from ..image_helpers import get_profile_image_urls_for_user +from openedx.core.djangolib.testing.utils import skip_unless_lms from student.tests.factories import UserFactory +from ..image_helpers import get_profile_image_urls_for_user TEST_SIZES = {'full': 50, 'small': 10} TEST_PROFILE_IMAGE_UPLOAD_DT = datetime.datetime(2002, 1, 9, 15, 43, 01, tzinfo=UTC) @@ -20,7 +19,7 @@ TEST_PROFILE_IMAGE_UPLOAD_DT = datetime.datetime(2002, 1, 9, 15, 43, 01, tzinfo= @attr(shard=2) @patch.dict('openedx.core.djangoapps.user_api.accounts.image_helpers.PROFILE_IMAGE_SIZES_MAP', TEST_SIZES, clear=True) -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class ProfileImageUrlTestCase(TestCase): """ Tests for profile image URL generation helpers. diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_views.py b/openedx/core/djangoapps/user_api/accounts/tests/test_views.py index 91dc74468b..0a45abe8f0 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_views.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_views.py @@ -12,7 +12,6 @@ import json from mock import patch from nose.plugins.attrib import attr from pytz import UTC -import unittest from django.conf import settings from django.core.urlresolvers import reverse @@ -25,7 +24,7 @@ from student.tests.factories import UserFactory from student.models import UserProfile, LanguageProficiency, PendingEmailChange from openedx.core.djangoapps.user_api.accounts import ACCOUNT_VISIBILITY_PREF_KEY from openedx.core.djangoapps.user_api.preferences.api import set_user_preference -from openedx.core.djangolib.testing.utils import CacheIsolationTestCase +from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms from .. import PRIVATE_VISIBILITY, ALL_USERS_VISIBILITY TEST_PROFILE_IMAGE_UPLOADED_AT = datetime.datetime(2002, 1, 9, 15, 43, 01, tzinfo=UTC) @@ -140,7 +139,7 @@ class UserAPITestCase(APITestCase): @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Account APIs are only supported in LMS') +@skip_unless_lms @attr(shard=2) class TestOwnUsernameAPI(CacheIsolationTestCase, UserAPITestCase): """ @@ -193,7 +192,7 @@ class TestOwnUsernameAPI(CacheIsolationTestCase, UserAPITestCase): @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Account APIs are only supported in LMS') +@skip_unless_lms @patch('openedx.core.djangoapps.user_api.accounts.image_helpers._PROFILE_IMAGE_SIZES', [50, 10]) @patch.dict( 'openedx.core.djangoapps.user_api.accounts.image_helpers.PROFILE_IMAGE_SIZES_MAP', @@ -783,7 +782,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase): @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestAccountAPITransactions(TransactionTestCase): """ Tests the transactional behavior of the account API diff --git a/openedx/core/djangoapps/user_api/management/tests/test_email_opt_in_list.py b/openedx/core/djangoapps/user_api/management/tests/test_email_opt_in_list.py index a9eac55811..0b4a19efb4 100644 --- a/openedx/core/djangoapps/user_api/management/tests/test_email_opt_in_list.py +++ b/openedx/core/djangoapps/user_api/management/tests/test_email_opt_in_list.py @@ -6,10 +6,8 @@ import shutil import csv from collections import defaultdict from nose.plugins.attrib import attr -from unittest import skipUnless import ddt -from django.conf import settings from django.contrib.auth.models import User from django.core.management.base import CommandError @@ -21,11 +19,12 @@ from student.models import CourseEnrollment from openedx.core.djangoapps.user_api.preferences.api import update_email_opt_in from openedx.core.djangoapps.user_api.models import UserOrgTag from openedx.core.djangoapps.user_api.management.commands import email_opt_in_list +from openedx.core.djangolib.testing.utils import skip_unless_lms @attr(shard=2) @ddt.ddt -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class EmailOptInListTest(ModuleStoreTestCase): """Tests for the email opt-in list management command. """ diff --git a/openedx/core/djangoapps/user_api/preferences/tests/test_api.py b/openedx/core/djangoapps/user_api/preferences/tests/test_api.py index 152acdaf74..3f7b6615ef 100644 --- a/openedx/core/djangoapps/user_api/preferences/tests/test_api.py +++ b/openedx/core/djangoapps/user_api/preferences/tests/test_api.py @@ -4,17 +4,15 @@ Unit tests for preference APIs. """ import datetime import ddt -import unittest from mock import patch from nose.plugins.attrib import attr from pytz import common_timezones, utc -from django.conf import settings from django.contrib.auth.models import User from django.test.utils import override_settings from dateutil.parser import parse as parse_datetime -from openedx.core.djangolib.testing.utils import CacheIsolationTestCase +from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms from openedx.core.lib.time_zone_utils import get_display_time_zone from student.tests.factories import UserFactory @@ -42,7 +40,7 @@ from ...preferences.api import ( @attr(shard=2) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Account APIs are only supported in LMS') +@skip_unless_lms class TestPreferenceAPI(CacheIsolationTestCase): """ These tests specifically cover the parts of the API methods that are not covered by test_views.py. diff --git a/openedx/core/djangoapps/user_api/preferences/tests/test_views.py b/openedx/core/djangoapps/user_api/preferences/tests/test_views.py index e55ecba99e..9e9af11b43 100644 --- a/openedx/core/djangoapps/user_api/preferences/tests/test_views.py +++ b/openedx/core/djangoapps/user_api/preferences/tests/test_views.py @@ -3,17 +3,16 @@ Unit tests for preference APIs. """ -import unittest import ddt import json from mock import patch from django.core.urlresolvers import reverse -from django.conf import settings from django.test.testcases import TransactionTestCase from rest_framework.test import APIClient from student.tests.factories import UserFactory +from openedx.core.djangolib.testing.utils import skip_unless_lms from ...accounts.tests.test_views import UserAPITestCase from ..api import set_user_preference from .test_api import get_expected_validation_developer_message, get_expected_key_error_user_message @@ -22,7 +21,7 @@ TOO_LONG_PREFERENCE_KEY = u"x" * 256 @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestPreferencesAPI(UserAPITestCase): """ Unit tests /api/user/v1/accounts/{username}/ @@ -316,7 +315,7 @@ class TestPreferencesAPI(UserAPITestCase): ) -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestPreferencesAPITransactions(TransactionTestCase): """ Tests the transactional behavior of the preferences API @@ -363,7 +362,7 @@ class TestPreferencesAPITransactions(TransactionTestCase): @ddt.ddt -@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class TestPreferencesDetailAPI(UserAPITestCase): """ Unit tests /api/user/v1/accounts/{username}/{preference_key} diff --git a/openedx/core/djangoapps/user_api/tests/test_views.py b/openedx/core/djangoapps/user_api/tests/test_views.py index 9b881de733..e9496e440c 100644 --- a/openedx/core/djangoapps/user_api/tests/test_views.py +++ b/openedx/core/djangoapps/user_api/tests/test_views.py @@ -21,7 +21,7 @@ from social.apps.django_app.default.models import UserSocialAuth from django_comment_common import models from openedx.core.lib.api.test_utils import ApiTestCase, TEST_API_KEY from openedx.core.lib.time_zone_utils import get_display_time_zone -from openedx.core.djangolib.testing.utils import CacheIsolationTestCase +from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms from student.tests.factories import UserFactory from third_party_auth.tests.testutil import simulate_running_pipeline, ThirdPartyAuthTestMixin from third_party_auth.tests.utils import ( @@ -541,7 +541,7 @@ class PreferenceUsersListViewTest(UserApiTestCase): @ddt.ddt -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class LoginSessionViewTest(UserAPITestCase): """Tests for the login end-points of the user API. """ @@ -713,7 +713,7 @@ class LoginSessionViewTest(UserAPITestCase): @ddt.ddt -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class PasswordResetViewTest(UserAPITestCase): """Tests of the user API's password reset endpoint. """ @@ -771,7 +771,7 @@ class PasswordResetViewTest(UserAPITestCase): @ddt.ddt -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase): """Tests for the registration end-points of the User API. """ @@ -1925,7 +1925,7 @@ class TestGoogleRegistrationView( @ddt.ddt -@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +@skip_unless_lms class UpdateEmailOptInTestCase(UserAPITestCase, SharedModuleStoreTestCase): """Tests the UpdateEmailOptInPreference view. """ diff --git a/openedx/core/djangolib/testing/utils.py b/openedx/core/djangolib/testing/utils.py index 8218be239f..6b986be227 100644 --- a/openedx/core/djangolib/testing/utils.py +++ b/openedx/core/djangolib/testing/utils.py @@ -9,6 +9,7 @@ Utility classes for testing django applications. """ import copy +from unittest import skipUnless import crum from django import db @@ -175,3 +176,17 @@ def get_mock_request(user=None): request.get_host = lambda: "edx.org" crum.set_current_request(request) return request + + +def skip_unless_cms(func): + """ + Only run the decorated test in the CMS test suite + """ + return skipUnless(settings.ROOT_URLCONF == 'cms.urls', 'Test only valid in CMS')(func) + + +def skip_unless_lms(func): + """ + Only run the decorated test in the LMS test suite + """ + return skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS')(func)