From 553d35e53ec39e7fb68a3985d2d5dcbb6e45ec88 Mon Sep 17 00:00:00 2001
From: Jeremy Bowman <jbowman@edx.org>
Date: Tue, 24 Sep 2019 10:14:17 -0400
Subject: [PATCH] Upgrade mock BOM-596 (#21717)

---
 common/djangoapps/edxmako/tests.py            |  8 ++--
 .../tests/test_mixed_modulestore.py           |  6 ---
 .../modulestore/tests/test_xml_importer.py    |  2 +-
 lms/djangoapps/branding/tests/test_page.py    |  2 +-
 lms/djangoapps/certificates/api.py            |  4 +-
 .../certificates/tests/test_webview_views.py  | 25 +++++++-----
 lms/djangoapps/grades/signals/handlers.py     | 10 +++--
 lms/djangoapps/grades/tests/test_signals.py   | 12 ++++--
 lms/djangoapps/grades/tests/test_tasks.py     | 19 +--------
 .../instructor/tests/test_enrollment.py       |  9 ++---
 .../instructor_task/tests/test_tasks.py       |  8 ++--
 .../course_groups/tests/test_cohorts.py       | 40 -------------------
 .../programs/tasks/v1/tests/test_tasks.py     |  2 +-
 .../test_backpopulate_program_credentials.py  |  1 -
 .../commands/tests/test_send_course_update.py |  5 ++-
 .../accounts/tests/test_retirement_views.py   |  9 +++--
 .../enterprise_support/tests/test_api.py      |  2 -
 .../completion_integration/test_handlers.py   |  2 +-
 requirements/edx/base.txt                     |  3 +-
 requirements/edx/development.txt              |  3 +-
 requirements/edx/paver.in                     |  2 +-
 requirements/edx/paver.txt                    |  5 ++-
 requirements/edx/testing.in                   |  1 -
 requirements/edx/testing.txt                  |  5 +--
 24 files changed, 68 insertions(+), 117 deletions(-)

diff --git a/common/djangoapps/edxmako/tests.py b/common/djangoapps/edxmako/tests.py
index 29af0070d63..7a270ae4b8f 100644
--- a/common/djangoapps/edxmako/tests.py
+++ b/common/djangoapps/edxmako/tests.py
@@ -125,9 +125,11 @@ class MakoRequestContextTest(TestCase):
             self.assertIsNotNone(get_template_request_context())
 
         mock_get_current_request = Mock()
-        with patch('edxmako.request_context.get_current_request', mock_get_current_request):
-            # requestcontext should not be None, because the cache is filled
-            self.assertIsNotNone(get_template_request_context())
+        with patch('edxmako.request_context.get_current_request'):
+            with patch('edxmako.request_context.RequestContext.__init__') as mock_context_init:
+                # requestcontext should not be None, because the cache is filled
+                self.assertIsNotNone(get_template_request_context())
+                mock_context_init.assert_not_called()
         mock_get_current_request.assert_not_called()
 
         RequestCache.clear_all_namespaces()
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
index 27b0b5e8094..3dbc6a9addf 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py
@@ -2785,12 +2785,6 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
                     self.store.publish(unit.location, self.user_id)
                     signal_handler.send.assert_not_called()
 
-                    self.store.unpublish(unit.location, self.user_id)
-                    signal_handler.send.assert_not_called()
-
-                    self.store.delete_item(unit.location, self.user_id)
-                    signal_handler.send.assert_not_called()
-
                 signal_handler.send.assert_called_with('course_published', course_key=course.id)
 
                 # Test editing draftable block type without publish
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_xml_importer.py b/common/lib/xmodule/xmodule/modulestore/tests/test_xml_importer.py
index 0cdfb2bf52d..f40716cfa3e 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/test_xml_importer.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/test_xml_importer.py
@@ -391,4 +391,4 @@ class StaticContentImporterTest(unittest.TestCase):
                 base_dir=base_dir
             )
             mock_file.assert_called_with(full_file_path, 'rb')
-            self.mocked_content_store.assert_called_once()
+            self.mocked_content_store.generate_thumbnail.assert_called_once()
diff --git a/lms/djangoapps/branding/tests/test_page.py b/lms/djangoapps/branding/tests/test_page.py
index 164dce826e2..693ee071bff 100644
--- a/lms/djangoapps/branding/tests/test_page.py
+++ b/lms/djangoapps/branding/tests/test_page.py
@@ -295,7 +295,7 @@ class IndexPageProgramsTests(SiteMixin, ModuleStoreTestCase):
     """
     def test_get_programs_with_type_called(self):
         views = [
-            (reverse('root'), 'student.views.get_programs_with_type'),
+            (reverse('root'), 'student.views.management.get_programs_with_type'),
             (reverse('courses'), 'courseware.views.views.get_programs_with_type'),
         ]
         for url, dotted_path in views:
diff --git a/lms/djangoapps/certificates/api.py b/lms/djangoapps/certificates/api.py
index 537318b3934..3e97daef619 100644
--- a/lms/djangoapps/certificates/api.py
+++ b/lms/djangoapps/certificates/api.py
@@ -467,8 +467,8 @@ def _certificate_download_url(user_id, course_id, user_certificate=None):
         except GeneratedCertificate.DoesNotExist:
             log.critical(
                 u'Unable to lookup certificate\n'
-                u'user id: %d\n'
-                u'course: %s', user_id, six.text_type(course_id)
+                u'user id: %s\n'
+                u'course: %s', six.text_type(user_id), six.text_type(course_id)
             )
 
     if user_certificate:
diff --git a/lms/djangoapps/certificates/tests/test_webview_views.py b/lms/djangoapps/certificates/tests/test_webview_views.py
index 651d0345934..81c6e4d85ba 100644
--- a/lms/djangoapps/certificates/tests/test_webview_views.py
+++ b/lms/djangoapps/certificates/tests/test_webview_views.py
@@ -431,23 +431,28 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
 
     @ddt.data(True, False)
     @patch('lms.djangoapps.certificates.views.webview.get_completion_badge')
-    @override_settings(FEATURES=FEATURES_WITH_BADGES_ENABLED)
     def test_fetch_badge_info(self, issue_badges, mock_get_completion_badge):
         """
         Test: Fetch badge class info if badges are enabled.
         """
-        badge_class = BadgeClassFactory(course_id=self.course_id, mode=self.cert.mode)
-        mock_get_completion_badge.return_value = badge_class
-
-        self._add_course_certificates(count=1, signatory_count=1, is_active=True)
-        test_url = get_certificate_url(course_id=self.cert.course_id, uuid=self.cert.verify_uuid)
-        response = self.client.get(test_url)
-        self.assertEqual(response.status_code, 200)
+        if issue_badges:
+            features = FEATURES_WITH_BADGES_ENABLED
+        else:
+            features = FEATURES_WITH_CERTS_ENABLED
+        with override_settings(FEATURES=features):
+            badge_class = BadgeClassFactory(course_id=self.course_id, mode=self.cert.mode)
+            mock_get_completion_badge.return_value = badge_class
+
+            self._add_course_certificates(count=1, signatory_count=1, is_active=True)
+            test_url = get_certificate_url(user_id=self.user.id, course_id=self.cert.course_id,
+                                           uuid=self.cert.verify_uuid)
+            response = self.client.get(test_url)
+            self.assertEqual(response.status_code, 200)
 
         if issue_badges:
-            mock_get_completion_badge.assertCalled()
+            mock_get_completion_badge.assert_called()
         else:
-            mock_get_completion_badge.assertNotCalled()
+            mock_get_completion_badge.assert_not_called()
 
     @override_settings(FEATURES=FEATURES_WITH_BADGES_ENABLED)
     @patch.dict("django.conf.settings.SOCIAL_SHARING_SETTINGS", {
diff --git a/lms/djangoapps/grades/signals/handlers.py b/lms/djangoapps/grades/signals/handlers.py
index 9933f7c8bef..c6be5b58ec5 100644
--- a/lms/djangoapps/grades/signals/handlers.py
+++ b/lms/djangoapps/grades/signals/handlers.py
@@ -39,7 +39,7 @@ from .signals import (
 log = getLogger(__name__)
 
 
-@receiver(score_set)
+@receiver(score_set, dispatch_uid='submissions_score_set_handler')
 def submissions_score_set_handler(sender, **kwargs):  # pylint: disable=unused-argument
     """
     Consume the score_set signal defined in the Submissions API, and convert it
@@ -79,7 +79,7 @@ def submissions_score_set_handler(sender, **kwargs):  # pylint: disable=unused-a
     )
 
 
-@receiver(score_reset)
+@receiver(score_reset, dispatch_uid='submissions_score_reset_handler')
 def submissions_score_reset_handler(sender, **kwargs):  # pylint: disable=unused-argument
     """
     Consume the score_reset signal defined in the Submissions API, and convert
@@ -120,16 +120,18 @@ def disconnect_submissions_signal_receiver(signal):
     """
     if signal == score_set:
         handler = submissions_score_set_handler
+        dispatch_uid = 'submissions_score_set_handler'
     else:
         if signal != score_reset:
             raise ValueError("This context manager only handles score_set and score_reset signals.")
         handler = submissions_score_reset_handler
+        dispatch_uid = 'submissions_score_reset_handler'
 
-    signal.disconnect(handler)
+    signal.disconnect(dispatch_uid=dispatch_uid)
     try:
         yield
     finally:
-        signal.connect(handler)
+        signal.connect(handler, dispatch_uid=dispatch_uid)
 
 
 @receiver(SCORE_PUBLISHED)
diff --git a/lms/djangoapps/grades/tests/test_signals.py b/lms/djangoapps/grades/tests/test_signals.py
index 31c564839e0..0a61cc6247e 100644
--- a/lms/djangoapps/grades/tests/test_signals.py
+++ b/lms/djangoapps/grades/tests/test_signals.py
@@ -218,23 +218,26 @@ class ScoreChangedSignalRelayTest(TestCase):
         self.signal_mock.assert_called_with(**expected_set_kwargs)
 
     @ddt.data(
-        ['score_set', 'lms.djangoapps.grades.signals.handlers.submissions_score_set_handler',
+        ['score_set', SUBMISSION_KWARGS[SUBMISSION_SET_KWARGS]['points_earned'],
          SUBMISSION_SET_KWARGS],
-        ['score_reset', 'lms.djangoapps.grades.signals.handlers.submissions_score_reset_handler',
+        ['score_reset', 0,
          SUBMISSION_RESET_KWARGS]
     )
     @ddt.unpack
-    def test_disconnect_manager(self, signal_name, handler, kwargs):
+    def test_disconnect_manager(self, signal_name, weighted_earned, kwargs):
         """
         Tests to confirm the disconnect_submissions_signal_receiver context manager is working correctly.
         """
         signal = self.SIGNALS[signal_name]
         kwargs = SUBMISSION_KWARGS[kwargs].copy()
-        handler_mock = self.setup_patch(handler, None)
+        handler_mock = self.setup_patch('lms.djangoapps.grades.signals.handlers.PROBLEM_WEIGHTED_SCORE_CHANGED.send',
+                                        None)
 
         # Receiver connected before we start
         signal.send(None, **kwargs)
         handler_mock.assert_called_once()
+        # Make sure the correct handler was called
+        assert handler_mock.call_args[1]['weighted_earned'] == weighted_earned
         handler_mock.reset_mock()
 
         # Disconnect is functioning
@@ -246,6 +249,7 @@ class ScoreChangedSignalRelayTest(TestCase):
         # And we reconnect properly afterwards
         signal.send(None, **kwargs)
         handler_mock.assert_called_once()
+        assert handler_mock.call_args[1]['weighted_earned'] == weighted_earned
 
     def test_disconnect_manager_bad_arg(self):
         """
diff --git a/lms/djangoapps/grades/tests/test_tasks.py b/lms/djangoapps/grades/tests/test_tasks.py
index cd17c1187a9..6d92d19b487 100644
--- a/lms/djangoapps/grades/tests/test_tasks.py
+++ b/lms/djangoapps/grades/tests/test_tasks.py
@@ -47,18 +47,6 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, chec
 from .utils import mock_get_score
 
 
-class MockGradesService(GradesService):
-    """
-    A mock grades service.
-    """
-    def __init__(self, mocked_return_value=None):
-        super(MockGradesService, self).__init__()
-        self.mocked_return_value = mocked_return_value
-
-    def get_subsection_grade_override(self, user_id, course_key_or_id, usage_key_or_id):
-        return self.mocked_return_value
-
-
 class HasCourseWithProblemsMixin(object):
     """
     Mixin to provide tests with a sample course with graded subsections
@@ -651,16 +639,13 @@ class FreezeGradingAfterCourseEndTest(HasCourseWithProblemsMixin, ModuleStoreTes
 
         with override_waffle_flag(self.freeze_grade_flag, active=freeze_flag_value):
             modified_datetime = datetime.utcnow().replace(tzinfo=pytz.UTC) - timedelta(days=1)
-            with patch('lms.djangoapps.grades.api') as mock_grade_service:
-                mock_grade_service.get_subsection_grade_override = MagicMock(
-                    return_value=MagicMock(modified=modified_datetime)
-                )
+            with patch('lms.djangoapps.grades.tasks._has_db_updated_with_new_score') as mock_has_db_updated:
                 result = recalculate_subsection_grade_v3.apply_async(kwargs=self.recalculate_subsection_grade_kwargs)
                 self._assert_for_freeze_grade_flag(
                     result,
                     freeze_flag_value,
                     end_date_adjustment,
                     mock_log,
-                    mock_grade_service,
+                    mock_has_db_updated,
                     '_recalculate_subsection_grade'
                 )
diff --git a/lms/djangoapps/instructor/tests/test_enrollment.py b/lms/djangoapps/instructor/tests/test_enrollment.py
index 250b5307425..721604dddf4 100644
--- a/lms/djangoapps/instructor/tests/test_enrollment.py
+++ b/lms/djangoapps/instructor/tests/test_enrollment.py
@@ -397,9 +397,7 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
     # Disable the score change signal to prevent other components from being
     # pulled into tests.
     @patch('lms.djangoapps.grades.signals.handlers.PROBLEM_WEIGHTED_SCORE_CHANGED.send')
-    @patch('lms.djangoapps.grades.signals.handlers.submissions_score_set_handler')
-    @patch('lms.djangoapps.grades.signals.handlers.submissions_score_reset_handler')
-    def test_delete_submission_scores(self, _mock_send_signal, mock_set_receiver, mock_reset_receiver):
+    def test_delete_submission_scores(self, mock_send_signal):
         user = UserFactory()
         problem_location = self.course_key.make_usage_key('dummy', 'module')
 
@@ -422,6 +420,7 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
         sub_api.set_score(submission['uuid'], 1, 2)
 
         # Delete student state using the instructor dash
+        mock_send_signal.reset_mock()
         reset_student_attempts(
             self.course_key, user, problem_location,
             requesting_user=user,
@@ -429,8 +428,8 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
         )
 
         # Make sure our grades signal receivers handled the reset properly
-        mock_set_receiver.assert_not_called()
-        mock_reset_receiver.assert_called_once()
+        mock_send_signal.assert_called_once()
+        assert mock_send_signal.call_args[1]['weighted_earned'] == 0
 
         # Verify that the student's scores have been reset in the submissions API
         score = sub_api.get_score(student_item)
diff --git a/lms/djangoapps/instructor_task/tests/test_tasks.py b/lms/djangoapps/instructor_task/tests/test_tasks.py
index f5295b7fce1..603d6acfbd0 100644
--- a/lms/djangoapps/instructor_task/tests/test_tasks.py
+++ b/lms/djangoapps/instructor_task/tests/test_tasks.py
@@ -678,8 +678,10 @@ class TestOra2ResponsesInstructorTask(TestInstructorTasks):
 
         with patch('lms.djangoapps.instructor_task.tasks.run_main_task') as mock_main_task:
             export_ora2_data(task_entry.id, task_xmodule_args)
-
             action_name = ugettext_noop('generated')
-            task_fn = partial(upload_ora2_data, task_xmodule_args)
 
-            mock_main_task.assert_called_once_with_args(task_entry.id, task_fn, action_name)
+            assert mock_main_task.call_count == 1
+            args = mock_main_task.call_args[0]
+            assert args[0] == task_entry.id
+            assert callable(args[1])
+            assert args[2] == action_name
diff --git a/openedx/core/djangoapps/course_groups/tests/test_cohorts.py b/openedx/core/djangoapps/course_groups/tests/test_cohorts.py
index a40a3daf998..dbb791c5940 100644
--- a/openedx/core/djangoapps/course_groups/tests/test_cohorts.py
+++ b/openedx/core/djangoapps/course_groups/tests/test_cohorts.py
@@ -4,7 +4,6 @@ Tests for cohorts
 # pylint: disable=no-member
 from __future__ import absolute_import
 
-import before_after
 import ddt
 from django.contrib.auth.models import AnonymousUser, User
 from django.db import IntegrityError
@@ -691,45 +690,6 @@ class TestCohorts(ModuleStoreTestCase):
             lambda: cohorts.add_user_to_cohort(first_cohort, "non_existent_username")
         )
 
-    @patch("openedx.core.djangoapps.course_groups.cohorts.tracker")
-    def add_user_to_cohorts_race_condition(self, mock_tracker):
-        """
-        Makes use of before_after to force a race condition, in order to
-        confirm handling of such conditions is done correctly.
-        """
-        course_user = UserFactory(username="Username", email="a@b.com")
-        course = modulestore().get_course(self.toy_course_key)
-        CourseEnrollment.enroll(course_user, self.toy_course_key)
-        first_cohort = CohortFactory(course_id=course.id, name="FirstCohort")
-        second_cohort = CohortFactory(course_id=course.id, name="SecondCohort")
-
-        # This before_after contextmanager allows for reliable reproduction of a race condition.
-        # It will break before the first save() call creates an entry, and then run add_user_to_cohort again.
-        # Because this second call will write before control is returned, the first call will be writing stale data.
-        # This test confirms that the first add_user_to_cohort call can handle this stale read condition properly.
-        # Proper handling is defined as treating calls as sequential, with write time deciding the order.
-        with before_after.before_after(
-            'django.db.models.Model.save',
-            after_ftn=cohorts.add_user_to_cohort(second_cohort, course_user.username),
-            autospec=True
-        ):
-            # This method will read, then break, then try to write stale data.
-            # It should fail at that, then retry with refreshed data
-            cohorts.add_user_to_cohort(first_cohort, course_user.username)
-
-        mock_tracker.emit.assert_any_call(
-            "edx.cohort.user_add_requested",
-            {
-                "user_id": course_user.id,
-                "cohort_id": first_cohort.id,
-                "cohort_name": first_cohort.name,
-                "previous_cohort_id": second_cohort.id,
-                "previous_cohort_name": second_cohort.name,
-            }
-        )
-        # Note that the following get() will fail with MultipleObjectsReturned if race condition is not handled.
-        self.assertEqual(first_cohort.users.get(), course_user)
-
     def test_set_cohorted_with_invalid_data_type(self):
         """
         Test that cohorts.set_course_cohorted raises exception if argument is not a boolean.
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 d9da31b8b94..0af148540f0 100644
--- a/openedx/core/djangoapps/programs/tasks/v1/tests/test_tasks.py
+++ b/openedx/core/djangoapps/programs/tasks/v1/tests/test_tasks.py
@@ -145,7 +145,7 @@ class AwardProgramCertificatesTestCase(CatalogIntegrationMixin, CredentialsApiCo
         programs.
         """
         tasks.award_program_certificates.delay(self.student.username).get()
-        mock_get_completed_programs.assert_called(self.site, self.student)
+        mock_get_completed_programs.assert_any_call(self.site, self.student)
 
     @ddt.data(
         ([1], [2, 3]),
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 9e081dffd03..b882bd89906 100644
--- a/openedx/core/djangoapps/programs/tests/test_backpopulate_program_credentials.py
+++ b/openedx/core/djangoapps/programs/tests/test_backpopulate_program_credentials.py
@@ -343,7 +343,6 @@ class BackpopulateProgramCredentialsTests(CatalogIntegrationMixin, CredentialsAp
         call_command('backpopulate_program_credentials', commit=True)
 
         mock_task.assert_called_once_with(self.alice.username)
-        mock_task.assert_not_called(self.bob.username)
 
     @mock.patch(COMMAND_MODULE + '.logger.exception')
     def test_handle_enqueue_failure(self, mock_log, mock_task, mock_get_programs):
diff --git a/openedx/core/djangoapps/schedules/management/commands/tests/test_send_course_update.py b/openedx/core/djangoapps/schedules/management/commands/tests/test_send_course_update.py
index 04de220568d..4ec60c6ac4e 100644
--- a/openedx/core/djangoapps/schedules/management/commands/tests/test_send_course_update.py
+++ b/openedx/core/djangoapps/schedules/management/commands/tests/test_send_course_update.py
@@ -8,7 +8,7 @@ from unittest import skipUnless
 import ddt
 from django.conf import settings
 from edx_ace.utils.date import serialize
-from mock import _is_started, patch
+from mock import patch
 from six.moves import range
 
 from openedx.core.djangoapps.schedules import resolvers, tasks
@@ -60,7 +60,7 @@ class TestSendCourseUpdate(ScheduleUpsellTestMixin, ScheduleSendEmailTestMixin,
         Stops the patcher for the get_week_highlights method
         if the patch is still in progress.
         """
-        if _is_started(self.highlights_patcher):
+        if self.highlights_patcher is not None:
             self.highlights_patcher.stop()
 
     @ddt.data(
@@ -75,6 +75,7 @@ class TestSendCourseUpdate(ScheduleUpsellTestMixin, ScheduleSendEmailTestMixin,
     @patch('openedx.core.djangoapps.schedules.signals.get_current_site')
     def test_with_course_data(self, mock_get_current_site):
         self.highlights_patcher.stop()
+        self.highlights_patcher = None
         mock_get_current_site.return_value = self.site_config.site
 
         course = CourseFactory(highlights_enabled_for_messaging=True, self_paced=True)
diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py b/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py
index 8e20e9a621b..cc84860454f 100644
--- a/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py
+++ b/openedx/core/djangoapps/user_api/accounts/tests/test_retirement_views.py
@@ -200,8 +200,9 @@ class TestDeactivateLogout(RetirementTestCase):
     def build_post(self, password):
         return {'password': password}
 
-    @mock.patch('openedx.core.djangolib.oauth2_retirement_utils')
-    def test_user_can_deactivate_self(self, retirement_utils_mock):
+    @mock.patch('openedx.core.djangoapps.user_api.accounts.views.retire_dot_oauth2_models')
+    @mock.patch('openedx.core.djangoapps.user_api.accounts.views.retire_dop_oauth2_models')
+    def test_user_can_deactivate_self(self, mock_retire_dop, mock_retire_dot):
         """
         Verify a user calling the deactivation endpoint logs out the user, deletes all their SSO tokens,
         and creates a user retirement row.
@@ -218,8 +219,8 @@ class TestDeactivateLogout(RetirementTestCase):
         self.assertEqual(list(Registration.objects.filter(user=self.test_user)), [])
         self.assertEqual(len(UserRetirementStatus.objects.filter(user_id=self.test_user.id)), 1)
         # these retirement utils are tested elsewhere; just make sure we called them
-        retirement_utils_mock.retire_dop_oauth2_models.assertCalledWith(self.test_user)
-        retirement_utils_mock.retire_dot_oauth2_models.assertCalledWith(self.test_user)
+        mock_retire_dop.assert_called_with(self.test_user)
+        mock_retire_dot.assert_called_with(self.test_user)
         # make sure the user cannot log in
         self.assertFalse(self.client.login(username=self.test_user.username, password=self.test_password))
         # make sure that an email has been sent
diff --git a/openedx/features/enterprise_support/tests/test_api.py b/openedx/features/enterprise_support/tests/test_api.py
index 2b236f0a4a7..87c94fd204c 100644
--- a/openedx/features/enterprise_support/tests/test_api.py
+++ b/openedx/features/enterprise_support/tests/test_api.py
@@ -364,8 +364,6 @@ class TestEnterpriseApi(EnterpriseServiceMockMixin, CacheIsolationTestCase):
         self.check_data_sharing_consent(consent_required=True, consent_url=consent_url)
 
         mock_get_consent_url.assert_called_once()
-        mock_enterprise_enabled.assert_called_once()
-        mock_consent_necessary.assert_called_once()
 
     @httpretty.activate
     @mock.patch('openedx.features.enterprise_support.api.enterprise_customer_uuid_for_request')
diff --git a/openedx/tests/completion_integration/test_handlers.py b/openedx/tests/completion_integration/test_handlers.py
index 46445552fca..344d52eb3dc 100644
--- a/openedx/tests/completion_integration/test_handlers.py
+++ b/openedx/tests/completion_integration/test_handlers.py
@@ -121,7 +121,7 @@ class ScorableCompletionHandlerTestCase(CompletionSetUpMixin, TestCase):
         self.assertFalse(completion.exists())
 
     def test_signal_calls_handler(self):
-        with patch('completion.handlers.scorable_block_completion') as mock_handler:
+        with patch('completion.handlers.BlockCompletion.objects.submit_completion') as mock_handler:
             grades_signals.PROBLEM_WEIGHTED_SCORE_CHANGED.send_robust(
                 sender=self,
                 user_id=self.user.id,
diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt
index e0df8b36d13..091c67a87ae 100644
--- a/requirements/edx/base.txt
+++ b/requirements/edx/base.txt
@@ -128,6 +128,7 @@ event-tracking==0.2.9
 feedparser==5.1.3
 fs-s3fs==0.1.8
 fs==2.0.18
+funcsigs==1.0.2
 future==0.17.1            # via edx-celeryutils, edx-enterprise, pyjwkest
 futures==3.3.0 ; python_version == "2.7"  # via django-pipeline, python-swiftclient, s3transfer, xblock-utils
 geoip2==2.9.0
@@ -159,7 +160,7 @@ markdown==2.6.11
 markey==0.8               # via django-babel-underscore
 markupsafe==1.1.1
 maxminddb==1.4.1          # via geoip2
-mock==1.0.1
+mock==3.0.5
 git+https://github.com/edx/MongoDBProxy.git@d92bafe9888d2940f647a7b2b2383b29c752f35a#egg=MongoDBProxy==0.1.0+edx.2
 mongoengine==0.10.0
 mpmath==1.1.0             # via sympy
diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt
index fbc5de20c2c..216ae99b18c 100644
--- a/requirements/edx/development.txt
+++ b/requirements/edx/development.txt
@@ -39,7 +39,6 @@ backports.ssl-match-hostname==3.7.0.1
 backports.tempfile==1.0
 backports.weakref==1.0.post1
 beautifulsoup4==4.8.0
-before-after==1.0.1
 billiard==3.3.0.23
 bleach==2.1.4
 bok-choy==1.0.0
@@ -206,7 +205,7 @@ markey==0.8
 markupsafe==1.1.1
 maxminddb==1.4.1
 mccabe==0.6.1
-mock==1.0.1
+mock==3.0.5
 modernize==0.7
 git+https://github.com/edx/MongoDBProxy.git@d92bafe9888d2940f647a7b2b2383b29c752f35a#egg=MongoDBProxy==0.1.0+edx.2
 mongoengine==0.10.0
diff --git a/requirements/edx/paver.in b/requirements/edx/paver.in
index b6baa175ff3..a8fb579c861 100644
--- a/requirements/edx/paver.in
+++ b/requirements/edx/paver.in
@@ -14,7 +14,7 @@ edx-opaque-keys                     # Create and introspect course and xblock id
 lazy==1.1                           # Lazily-evaluated attributes for Python objects
 libsass==0.10.0                     # Python bindings for the LibSass CSS compiler
 markupsafe                          # XML/HTML/XHTML Markup safe strings
-mock==1.0.1                         # Stub out code with mock objects and make assertions about how they have been used
+mock                                # Stub out code with mock objects and make assertions about how they have been used
 path.py==8.2.1                      # Easier manipulation of filesystem paths
 paver                               # Build, distribution and deployment scripting tool
 psutil==1.2.1                       # Library for retrieving information on running processes and system utilization
diff --git a/requirements/edx/paver.txt b/requirements/edx/paver.txt
index e3df7dbca39..fa3a7344531 100644
--- a/requirements/edx/paver.txt
+++ b/requirements/edx/paver.txt
@@ -8,11 +8,12 @@ argh==0.26.2              # via watchdog
 certifi==2019.9.11        # via requests
 chardet==3.0.4            # via requests
 edx-opaque-keys==2.0.0
+funcsigs==1.0.2           # via mock
 idna==2.8                 # via requests
 lazy==1.1
 libsass==0.10.0
 markupsafe==1.1.1
-mock==1.0.1
+mock==3.0.5
 path.py==8.2.1
 pathtools==0.1.2          # via watchdog
 paver==1.3.4
@@ -22,7 +23,7 @@ pymongo==2.9.1
 python-memcached==1.59
 pyyaml==5.1.2             # via watchdog
 requests==2.22.0
-six==1.12.0               # via edx-opaque-keys, libsass, paver, python-memcached, stevedore
+six==1.12.0               # via edx-opaque-keys, libsass, mock, paver, python-memcached, stevedore
 stevedore==1.31.0
 urllib3==1.25.5           # via requests
 watchdog==0.9.0
diff --git a/requirements/edx/testing.in b/requirements/edx/testing.in
index 197c8abacae..269bcdaf4b4 100644
--- a/requirements/edx/testing.in
+++ b/requirements/edx/testing.in
@@ -18,7 +18,6 @@
 -r coverage.txt           # Utilities for calculating test coverage
 
 beautifulsoup4            # Library for extracting data from HTML and XML files
-before_after              # Syntactic sugar for mock, only used in one test case, not Python 3 compatible
 bok-choy                  # Framework for browser automation tests, based on selenium
 caniusepython3            # Library for checking the ability to upgrade to python3
 code-annotations          # Perform code annotation checking, such as for PII annotations
diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt
index 9b30ec6d724..f9bb612c8bf 100644
--- a/requirements/edx/testing.txt
+++ b/requirements/edx/testing.txt
@@ -38,7 +38,6 @@ backports.ssl-match-hostname==3.7.0.1  # via docker
 backports.tempfile==1.0   # via moto
 backports.weakref==1.0.post1  # via backports.tempfile
 beautifulsoup4==4.8.0
-before-after==1.0.1
 billiard==3.3.0.23
 bleach==2.1.4
 bok-choy==1.0.0
@@ -158,7 +157,7 @@ flake8==3.7.8             # via flake8-polyfill
 freezegun==0.3.12
 fs-s3fs==0.1.8
 fs==2.0.18
-funcsigs==1.0.2           # via pytest
+funcsigs==1.0.2
 functools32==3.2.3.post2 ; python_version == "2.7"  # via flake8
 future==0.17.1
 futures==3.3.0 ; python_version == "2.7"
@@ -200,7 +199,7 @@ markey==0.8
 markupsafe==1.1.1
 maxminddb==1.4.1
 mccabe==0.6.1             # via flake8, pylint
-mock==1.0.1
+mock==3.0.5
 git+https://github.com/edx/MongoDBProxy.git@d92bafe9888d2940f647a7b2b2383b29c752f35a#egg=MongoDBProxy==0.1.0+edx.2
 mongoengine==0.10.0
 more-itertools==5.0.0     # via pytest, zipp
-- 
GitLab