From 24a41dc59e8a32cb3797f09d2c7c01fb6f766853 Mon Sep 17 00:00:00 2001 From: Bill DeRusha Date: Wed, 26 Aug 2015 15:01:34 -0400 Subject: [PATCH] Improve teams test run times by skipping signals TNL-3126 add **kwargs to skip_signal method --- common/test/utils.py | 11 ++ lms/djangoapps/teams/search_indexes.py | 2 +- lms/djangoapps/teams/tests/test_views.py | 126 ++++++++++++++--------- 3 files changed, 92 insertions(+), 47 deletions(-) diff --git a/common/test/utils.py b/common/test/utils.py index 9ce575e658..4305b6e5fc 100644 --- a/common/test/utils.py +++ b/common/test/utils.py @@ -96,3 +96,14 @@ class MockSignalHandlerMixin(object): del kwargs['exclude_args'] self.assertEqual(mock_args, args) self.assertEqual(mock_kwargs, dict(kwargs, signal=mock_signal)) + + +@contextmanager +def skip_signal(signal, **kwargs): + """ + ContextManager to skip a signal by disconnecting it, yielding, + and then reconnecting the signal. + """ + signal.disconnect(**kwargs) + yield + signal.connect(**kwargs) diff --git a/lms/djangoapps/teams/search_indexes.py b/lms/djangoapps/teams/search_indexes.py index 24cfd77475..22af7227d4 100644 --- a/lms/djangoapps/teams/search_indexes.py +++ b/lms/djangoapps/teams/search_indexes.py @@ -88,7 +88,7 @@ class CourseTeamIndexer(object): return settings.FEATURES.get(cls.ENABLE_SEARCH_KEY, False) -@receiver(post_save, sender=CourseTeam) +@receiver(post_save, sender=CourseTeam, dispatch_uid='teams.signals.course_team_post_save_callback') def course_team_post_save_callback(**kwargs): """ Reindex object after save. diff --git a/lms/djangoapps/teams/tests/test_views.py b/lms/djangoapps/teams/tests/test_views.py index aff0241341..a6af127651 100644 --- a/lms/djangoapps/teams/tests/test_views.py +++ b/lms/djangoapps/teams/tests/test_views.py @@ -4,21 +4,22 @@ import json import pytz from datetime import datetime from dateutil import parser - import ddt from django.core.urlresolvers import reverse from django.conf import settings +from django.db.models.signals import post_save from nose.plugins.attrib import attr from rest_framework.test import APITestCase, APIClient from courseware.tests.factories import StaffFactory +from common.test.utils import skip_signal from student.tests.factories import UserFactory, AdminFactory, CourseEnrollmentFactory from student.models import CourseEnrollment +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from .factories import CourseTeamFactory, LAST_ACTIVITY_AT -from ..search_indexes import CourseTeamIndexer -from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase +from ..search_indexes import CourseTeamIndexer, CourseTeam, course_team_post_save_callback from django_comment_common.models import Role, FORUM_ROLE_COMMUNITY_TA from django_comment_common.utils import seed_permissions_roles @@ -194,32 +195,39 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase): username='student_enrolled_other_course_not_on_team' ) - # clear the teams search index before rebuilding teams - CourseTeamIndexer.engine().destroy() - - # 'solar team' is intentionally lower case to test case insensitivity in name ordering - self.test_team_1 = CourseTeamFactory.create( - name=u'sólar team', - course_id=self.test_course_1.id, - topic_id='topic_0' - ) - self.test_team_2 = CourseTeamFactory.create(name='Wind Team', course_id=self.test_course_1.id) - self.test_team_3 = CourseTeamFactory.create(name='Nuclear Team', course_id=self.test_course_1.id) - self.test_team_4 = CourseTeamFactory.create(name='Coal Team', course_id=self.test_course_1.id, is_active=False) - self.test_team_5 = CourseTeamFactory.create(name='Another Team', course_id=self.test_course_2.id) - self.test_team_6 = CourseTeamFactory.create( - name='Public Profile Team', - course_id=self.test_course_2.id, - topic_id='topic_6' - ) - self.test_team_7 = CourseTeamFactory.create( - name='Search', - description='queryable text', - country='GS', - language='to', - course_id=self.test_course_2.id, - topic_id='topic_7' - ) + with skip_signal( + post_save, + receiver=course_team_post_save_callback, + sender=CourseTeam, + dispatch_uid='teams.signals.course_team_post_save_callback' + ): + # 'solar team' is intentionally lower case to test case insensitivity in name ordering + self.test_team_1 = CourseTeamFactory.create( + name=u'sólar team', + course_id=self.test_course_1.id, + topic_id='topic_0' + ) + self.test_team_2 = CourseTeamFactory.create(name='Wind Team', course_id=self.test_course_1.id) + self.test_team_3 = CourseTeamFactory.create(name='Nuclear Team', course_id=self.test_course_1.id) + self.test_team_4 = CourseTeamFactory.create( + name='Coal Team', + course_id=self.test_course_1.id, + is_active=False + ) + self.test_team_5 = CourseTeamFactory.create(name='Another Team', course_id=self.test_course_2.id) + self.test_team_6 = CourseTeamFactory.create( + name='Public Profile Team', + course_id=self.test_course_2.id, + topic_id='topic_6' + ) + self.test_team_7 = CourseTeamFactory.create( + name='Search', + description='queryable text', + country='GS', + language='to', + course_id=self.test_course_2.id, + topic_id='topic_7' + ) self.test_team_name_id_map = {team.name: team for team in ( self.test_team_1, @@ -227,6 +235,8 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase): self.test_team_3, self.test_team_4, self.test_team_5, + self.test_team_6, + self.test_team_7, )} for user, course in [('staff', self.test_course_1), ('course_staff', self.test_course_1)]: @@ -455,9 +465,15 @@ class TestListTeamsAPI(TeamAPITestCase): # Make "solar team" the most recently active team. # The CourseTeamFactory sets the last_activity_at to a fixed time (in the past), so all of the # other teams have the same last_activity_at. - solar_team = self.test_team_name_id_map[u'sólar team'] - solar_team.last_activity_at = datetime.utcnow().replace(tzinfo=pytz.utc) - solar_team.save() + with skip_signal( + post_save, + receiver=course_team_post_save_callback, + sender=CourseTeam, + dispatch_uid='teams.signals.course_team_post_save_callback' + ): + solar_team = self.test_team_name_id_map[u'sólar team'] + solar_team.last_activity_at = datetime.utcnow().replace(tzinfo=pytz.utc) + solar_team.save() data = {'order_by': field} if field else {} self.verify_names(data, status, names) @@ -508,6 +524,12 @@ class TestListTeamsAPI(TeamAPITestCase): ) @ddt.unpack def test_text_search(self, text_search, expected_team_names): + # clear out the teams search index before reindexing + CourseTeamIndexer.engine().destroy() + + for team in self.test_team_name_id_map.values(): + CourseTeamIndexer.index(team) + self.verify_names( {'course_id': self.test_course_2.id, 'text_search': text_search}, 200, @@ -797,13 +819,19 @@ class TestListTopicsAPI(TeamAPITestCase): ) @ddt.unpack def test_order_by(self, field, status, names, expected_ordering): - # Add 2 teams to "Nuclear Power", which previously had no teams. - CourseTeamFactory.create( - name=u'Nuclear Team 1', course_id=self.test_course_1.id, topic_id='topic_2' - ) - CourseTeamFactory.create( - name=u'Nuclear Team 2', course_id=self.test_course_1.id, topic_id='topic_2' - ) + with skip_signal( + post_save, + receiver=course_team_post_save_callback, + sender=CourseTeam, + dispatch_uid='teams.signals.course_team_post_save_callback' + ): + # Add 2 teams to "Nuclear Power", which previously had no teams. + CourseTeamFactory.create( + name=u'Nuclear Team 1', course_id=self.test_course_1.id, topic_id='topic_2' + ) + CourseTeamFactory.create( + name=u'Nuclear Team 2', course_id=self.test_course_1.id, topic_id='topic_2' + ) data = {'course_id': self.test_course_1.id} if field: data['order_by'] = field @@ -817,13 +845,19 @@ class TestListTopicsAPI(TeamAPITestCase): Ensure that the secondary sort (alphabetical) when primary sort is team_count works across pagination boundaries. """ - # Add 2 teams to "Wind Power", which previously had no teams. - CourseTeamFactory.create( - name=u'Wind Team 1', course_id=self.test_course_1.id, topic_id='topic_1' - ) - CourseTeamFactory.create( - name=u'Wind Team 2', course_id=self.test_course_1.id, topic_id='topic_1' - ) + with skip_signal( + post_save, + receiver=course_team_post_save_callback, + sender=CourseTeam, + dispatch_uid='teams.signals.course_team_post_save_callback' + ): + # Add 2 teams to "Wind Power", which previously had no teams. + CourseTeamFactory.create( + name=u'Wind Team 1', course_id=self.test_course_1.id, topic_id='topic_1' + ) + CourseTeamFactory.create( + name=u'Wind Team 2', course_id=self.test_course_1.id, topic_id='topic_1' + ) topics = self.get_topics_list(data={ 'course_id': self.test_course_1.id,