Exemple #1
0
    def test_course_info_to_ccxcon_ok(self, mock_post):
        """
        Test for happy path
        """
        mock_response = mock.Mock()
        mock_response.status_code = 201
        mock_post.return_value = mock_response

        ccxconapi.course_info_to_ccxcon(self.course_key)

        assert mock_post.call_count == 1
        k_args, k_kwargs = mock_post.call_args
        # no args used for the call
        assert k_args == tuple()
        assert k_kwargs.get('url') ==\
               parse.urljoin(self.course.ccx_connector, ccxconapi.CCXCON_COURSEXS_URL)

        # second call with different status code
        mock_response.status_code = 200
        mock_post.return_value = mock_response

        ccxconapi.course_info_to_ccxcon(self.course_key)

        assert mock_post.call_count == 2
        k_args, k_kwargs = mock_post.call_args
        # no args used for the call
        assert k_args == tuple()
        assert k_kwargs.get('url') ==\
               parse.urljoin(self.course.ccx_connector, ccxconapi.CCXCON_COURSEXS_URL)
Exemple #2
0
    def test_course_info_to_ccxcon_ok(self, mock_post):
        """
        Test for happy path
        """
        mock_response = mock.Mock()
        mock_response.status_code = 201
        mock_post.return_value = mock_response

        ccxconapi.course_info_to_ccxcon(self.course_key)

        self.assertEqual(mock_post.call_count, 1)
        k_args, k_kwargs = mock_post.call_args
        # no args used for the call
        self.assertEqual(k_args, tuple())
        self.assertEqual(
            k_kwargs.get('url'),
            six.moves.urllib.parse.urljoin(self.course.ccx_connector,
                                           ccxconapi.CCXCON_COURSEXS_URL))

        # second call with different status code
        mock_response.status_code = 200
        mock_post.return_value = mock_response

        ccxconapi.course_info_to_ccxcon(self.course_key)

        self.assertEqual(mock_post.call_count, 2)
        k_args, k_kwargs = mock_post.call_args
        # no args used for the call
        self.assertEqual(k_args, tuple())
        self.assertEqual(
            k_kwargs.get('url'),
            six.moves.urllib.parse.urljoin(self.course.ccx_connector,
                                           ccxconapi.CCXCON_COURSEXS_URL))
Exemple #3
0
def update_ccxcon(course_id, cur_retry=0):
    """
    Pass through function to update course information on CCXCon.
    Takes care of retries in case of some specific exceptions.

    Args:
        course_id (str): string representing a course key
        cur_retry (int): integer representing the current task retry
    """
    course_key = CourseKey.from_string(course_id)
    try:
        api.course_info_to_ccxcon(course_key)
        log.info(u'Course update to CCXCon returned no errors. Course key: %s',
                 course_id)
    except (ConnectionError, HTTPError, RequestException, TooManyRedirects,
            api.CCXConnServerError) as exp:
        log.error(
            u'Course update to CCXCon failed for course_id %s with error: %s',
            course_id, exp)
        # in case the maximum amount of retries has not been reached,
        # insert another task delayed exponentially up to 5 retries
        if cur_retry < 5:
            update_ccxcon.apply_async(
                kwargs={
                    'course_id': course_id,
                    'cur_retry': cur_retry + 1
                },
                countdown=10**
                cur_retry  # number of seconds the task should be delayed
            )
            log.info(u'Requeued celery task for course key %s ; retry # %s',
                     course_id, cur_retry + 1)
    def test_course_info_to_ccxcon_ok(self, mock_post):
        """
        Test for happy path
        """
        mock_response = mock.Mock()
        mock_response.status_code = 201
        mock_post.return_value = mock_response

        ccxconapi.course_info_to_ccxcon(self.course_key)

        self.assertEqual(mock_post.call_count, 1)
        k_args, k_kwargs = mock_post.call_args
        # no args used for the call
        self.assertEqual(k_args, tuple())
        self.assertEqual(
            k_kwargs.get('url'),
            urlparse.urljoin(self.course.ccx_connector, ccxconapi.CCXCON_COURSEXS_URL)
        )

        # second call with different status code
        mock_response.status_code = 200
        mock_post.return_value = mock_response

        ccxconapi.course_info_to_ccxcon(self.course_key)

        self.assertEqual(mock_post.call_count, 2)
        k_args, k_kwargs = mock_post.call_args
        # no args used for the call
        self.assertEqual(k_args, tuple())
        self.assertEqual(
            k_kwargs.get('url'),
            urlparse.urljoin(self.course.ccx_connector, ccxconapi.CCXCON_COURSEXS_URL)
        )
Exemple #5
0
    def test_course_info_to_ccxcon_500_error(self, mock_post):
        """
        Test for 500 error: a CCXConnServerError exception is raised
        """
        mock_response = mock.Mock()
        mock_response.status_code = 500
        mock_post.return_value = mock_response

        with pytest.raises(ccxconapi.CCXConnServerError):
            ccxconapi.course_info_to_ccxcon(self.course_key)
    def test_course_info_to_ccxcon_500_error(self, mock_post):
        """
        Test for 500 error: a CCXConnServerError exception is raised
        """
        mock_response = mock.Mock()
        mock_response.status_code = 500
        mock_post.return_value = mock_response

        with self.assertRaises(ccxconapi.CCXConnServerError):
            ccxconapi.course_info_to_ccxcon(self.course_key)
Exemple #7
0
 def test_course_info_to_ccxcon_invalid_ccx_connector(self, mock_post):
     """
     Test for a course with invalid CCX connector URL
     """
     # no connector at all
     self.course.ccx_connector = ""
     self.mstore.update_item(self.course, self.instructor.id)
     assert ccxconapi.course_info_to_ccxcon(self.course_key) is None
     assert mock_post.call_count == 0
     # invalid url
     self.course.ccx_connector = "www.foo"
     self.mstore.update_item(self.course, self.instructor.id)
     assert ccxconapi.course_info_to_ccxcon(self.course_key) is None
     assert mock_post.call_count == 0
 def test_course_info_to_ccxcon_invalid_ccx_connector(self, mock_post):
     """
     Test for a course with invalid CCX connector URL
     """
     # no connector at all
     self.course.ccx_connector = ""
     self.mstore.update_item(self.course, self.instructor.id)
     self.assertIsNone(ccxconapi.course_info_to_ccxcon(self.course_key))
     self.assertEqual(mock_post.call_count, 0)
     # invalid url
     self.course.ccx_connector = "www.foo"
     self.mstore.update_item(self.course, self.instructor.id)
     self.assertIsNone(ccxconapi.course_info_to_ccxcon(self.course_key))
     self.assertEqual(mock_post.call_count, 0)
 def test_course_info_to_ccxcon_no_valid_course_key(self, mock_post):
     """
     Test for an invalid course key
     """
     missing_course_key = CourseKey.from_string('course-v1:FakeOrganization+CN999+CR-FALL99')
     self.assertIsNone(ccxconapi.course_info_to_ccxcon(missing_course_key))
     self.assertEqual(mock_post.call_count, 0)
Exemple #10
0
 def test_course_info_to_ccxcon_no_valid_course_key(self, mock_post):
     """
     Test for an invalid course key
     """
     missing_course_key = CourseKey.from_string('course-v1:FakeOrganization+CN999+CR-FALL99')
     self.assertIsNone(ccxconapi.course_info_to_ccxcon(missing_course_key))
     self.assertEqual(mock_post.call_count, 0)
 def test_course_info_to_ccxcon_no_ccx_enabled(self, mock_post):
     """
     Test for a course without CCX enabled
     """
     self.course.enable_ccx = False
     self.mstore.update_item(self.course, self.instructor.id)
     self.assertIsNone(ccxconapi.course_info_to_ccxcon(self.course_key))
     self.assertEqual(mock_post.call_count, 0)
 def test_course_info_to_ccxcon_no_config(self, mock_post):
     """
     Test for course with ccx connector credentials not configured
     """
     self.course.ccx_connector = "https://www.foo.com"
     self.mstore.update_item(self.course, self.instructor.id)
     self.assertIsNone(ccxconapi.course_info_to_ccxcon(self.course_key))
     self.assertEqual(mock_post.call_count, 0)
Exemple #13
0
 def test_course_info_to_ccxcon_no_config(self, mock_post):
     """
     Test for course with ccx connector credentials not configured
     """
     self.course.ccx_connector = "https://www.foo.com"
     self.mstore.update_item(self.course, self.instructor.id)
     assert ccxconapi.course_info_to_ccxcon(self.course_key) is None
     assert mock_post.call_count == 0
Exemple #14
0
 def test_course_info_to_ccxcon_no_ccx_enabled(self, mock_post):
     """
     Test for a course without CCX enabled
     """
     self.course.enable_ccx = False
     self.mstore.update_item(self.course, self.instructor.id)
     assert ccxconapi.course_info_to_ccxcon(self.course_key) is None
     assert mock_post.call_count == 0
Exemple #15
0
 def test_course_info_to_ccxcon_other_status_codes(self, mock_post):
     """
     Test for status codes different from >= 500 and 201:
     The called function doesn't raise any exception and simply returns None.
     """
     mock_response = mock.Mock()
     for status_code in (204, 300, 304, 400, 404):
         mock_response.status_code = status_code
         mock_post.return_value = mock_response
         assert ccxconapi.course_info_to_ccxcon(self.course_key) is None
 def test_course_info_to_ccxcon_other_status_codes(self, mock_post):
     """
     Test for status codes different from >= 500 and 201:
     The called function doesn't raise any exception and simply returns None.
     """
     mock_response = mock.Mock()
     for status_code in (204, 300, 304, 400, 404):
         mock_response.status_code = status_code
         mock_post.return_value = mock_response
         self.assertIsNone(ccxconapi.course_info_to_ccxcon(self.course_key))
Exemple #17
0
def update_ccxcon(course_id, cur_retry=0):
    """
    Pass through function to update course information on CCXCon.
    Takes care of retries in case of some specific exceptions.

    Args:
        course_id (str): string representing a course key
        cur_retry (int): integer representing the current task retry
    """
    course_key = CourseKey.from_string(course_id)
    try:
        api.course_info_to_ccxcon(course_key)
        log.info('Course update to CCXCon returned no errors. Course key: %s', course_id)
    except (ConnectionError, HTTPError, RequestException, TooManyRedirects, api.CCXConnServerError) as exp:
        log.error('Course update to CCXCon failed for course_id %s with error: %s', course_id, exp)
        # in case the maximum amount of retries has not been reached,
        # insert another task delayed exponentially up to 5 retries
        if cur_retry < 5:
            update_ccxcon.apply_async(
                kwargs={'course_id': course_id, 'cur_retry': cur_retry + 1},
                countdown=10 ** cur_retry  # number of seconds the task should be delayed
            )
            log.info('Requeued celery task for course key %s ; retry # %s', course_id, cur_retry + 1)