Пример #1
0
    def test_successful_client_update(self):
        """
        Test the full workflow of a Canvas integrated channel client update request
        """
        course_to_update = json.dumps({
            "course": {
                "integration_id": self.integration_id,
                "name": "test_course"
            }
        }).encode()
        course_id = 1
        mock_all_courses_resp = [{
            'name': 'test course',
            'integration_id': self.integration_id,
            'id': course_id
        }, {
            'name': 'wrong course',
            'integration_id': 'wrong integration id',
            'id': 2
        }]
        canvas_api_client = CanvasAPIClient(self.enterprise_config)

        with responses.RequestsMock() as request_mock:
            request_mock.add(responses.GET,
                             self.get_all_courses_url,
                             json=mock_all_courses_resp,
                             status=200)
            request_mock.add(responses.POST,
                             self.oauth_url,
                             json={'access_token': self.access_token},
                             status=200)
            request_mock.add(responses.PUT,
                             self.update_url + str(course_id),
                             body=b'Mock update response text')
            canvas_api_client.update_content_metadata(course_to_update)
Пример #2
0
    def test_course_completion_with_no_canvas_user(self):
        """Test that we properly raise exceptions if the client can't find the edx user in Canvas"""

        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                self.canvas_users_url,
                body="[]",
                status=200
            )
            rsps.add(
                responses.POST,
                self.oauth_url,
                json=self._token_response(),
                status=200
            )
            canvas_api_client = CanvasAPIClient(self.enterprise_config)

            with pytest.raises(ClientError) as client_error:
                canvas_api_client.create_course_completion(self.canvas_email, self.course_completion_payload)
                assert client_error.value.message == \
                    "Course: {course_id} not found registered in Canvas for Edx " \
                    "learner: {canvas_email}/Canvas learner: {canvas_user_id}.".format(
                        course_id=self.course_id,
                        canvas_email=self.canvas_email,
                        canvas_user_id=self.canvas_user_id
                    )
Пример #3
0
 def test_course_completion_grade_submission_500s(self):
     """Test that we raise the error if Canvas experiences a 500 while posting course completion data"""
     with responses.RequestsMock() as rsps:
         rsps.add(responses.POST,
                  self.oauth_url,
                  json={"access_token": self.access_token},
                  status=200)
         rsps.add(responses.GET,
                  self.canvas_users_url,
                  json=[{
                      'sortable_name': 'test user',
                      'login_id': self.canvas_email,
                      'id': self.canvas_user_id
                  }],
                  status=200)
         rsps.add(responses.GET,
                  self.canvas_user_courses_url,
                  json=[{
                      'integration_id': self.integration_id,
                      'id': self.canvas_course_id
                  }])
         rsps.add(responses.GET,
                  self.canvas_course_assignments_url,
                  json=[{
                      'integration_id': self.integration_id,
                      'id': self.canvas_assignment_id
                  }])
         rsps.add(responses.PUT,
                  self.canvas_assignment_url,
                  body=Exception('something went wrong'))
         canvas_api_client = CanvasAPIClient(self.enterprise_config)
         with pytest.raises(Exception) as client_error:
             canvas_api_client.create_course_completion(
                 self.canvas_email, self.course_completion_payload)
         assert client_error.value.__str__() == 'something went wrong'
Пример #4
0
    def test_create_course_success_with_image_url(self):
        canvas_api_client = CanvasAPIClient(self.enterprise_config)
        course_to_create = json.dumps({
            "course": {
                "integration_id": self.integration_id,
                "name": "test_course_create",
                "image_url": "http://image.one/url.png"
            }
        }).encode('utf-8')

        with responses.RequestsMock() as request_mock:
            request_mock.add(responses.POST,
                             self.oauth_url,
                             json={'access_token': self.access_token},
                             status=200)

            expected_resp = '{"id": 1111}'
            request_mock.add(responses.POST,
                             CanvasAPIClient.course_create_endpoint(
                                 self.url_base, self.account_id),
                             status=201,
                             body=expected_resp)
            request_mock.add(responses.PUT,
                             CanvasAPIClient.course_update_endpoint(
                                 self.url_base, 1111),
                             status=200)
            status_code, response_text = canvas_api_client.create_content_metadata(
                course_to_create)
            assert status_code == 201
            assert response_text == expected_resp
Пример #5
0
    def test_course_completion_with_no_matching_canvas_course(self):
        """Test that we properly raise exceptions for when a course is not found in canvas."""
        with responses.RequestsMock() as rsps:
            rsps.add(responses.POST,
                     self.oauth_url,
                     json={"access_token": self.access_token},
                     status=200)
            rsps.add(responses.GET,
                     self.canvas_users_url,
                     json=[{
                         'sortable_name': 'test user',
                         'login_id': self.canvas_email,
                         'id': self.canvas_user_id
                     }],
                     status=200)
            rsps.add(responses.GET, self.canvas_user_courses_url, json=[])
            canvas_api_client = CanvasAPIClient(self.enterprise_config)
            with pytest.raises(CanvasClientError) as client_error:
                canvas_api_client.create_course_completion(
                    self.canvas_email, self.course_completion_payload)

            assert client_error.value.__str__() == \
                "Canvas Client Error: Course: {course_id} not found registered in Canvas for Edx " \
                "learner: {canvas_email}/Canvas learner: {canvas_user_id}.".format(
                    course_id=self.course_id,
                    canvas_email=self.canvas_email,
                    canvas_user_id=self.canvas_user_id
                )  # noqa
Пример #6
0
 def test_client_instantiation_fails_without_refresh_token(self):
     with pytest.raises(ClientError) as client_error:
         self.enterprise_config.refresh_token = None
         canvas_api_client = CanvasAPIClient(self.enterprise_config)
         canvas_api_client._create_session()  # pylint: disable=protected-access
     assert client_error.value.__str__(
     ) == "Failed to generate oauth access token: Refresh token required."
Пример #7
0
    def test_create_course_success(self):
        canvas_api_client = CanvasAPIClient(self.enterprise_config)
        course_to_create = json.dumps({
            "course": {
                "integration_id": self.integration_id,
                "name": "test_course_create"
            }
        }).encode()

        with responses.RequestsMock() as request_mock:
            request_mock.add(responses.POST,
                             self.oauth_url,
                             json=self._token_response(),
                             status=200)

            expected_resp = '{"id": 1}'
            request_mock.add(responses.POST,
                             CanvasAPIClient.course_create_endpoint(
                                 self.url_base, self.account_id),
                             status=201,
                             body=expected_resp)
            status_code, response_text = canvas_api_client.create_content_metadata(
                course_to_create)
            assert status_code == 201
            assert response_text == expected_resp
Пример #8
0
    def test_create_client_session_with_oauth_access_key(self):
        """ Test instantiating the client will fetch and set the session's oauth access key"""
        with responses.RequestsMock() as rsps:
            rsps.add(responses.POST,
                     self.oauth_url,
                     json={"access_token": self.access_token},
                     status=200)
            canvas_api_client = CanvasAPIClient(self.enterprise_config)
            canvas_api_client._create_session()  # pylint: disable=protected-access

            assert canvas_api_client.session.headers[
                "Authorization"] == "Bearer " + self.access_token
Пример #9
0
    def update_fails_when_course_id_not_found(self, request_type):
        """
        Helper method to test error handling when no course ID is found
        """
        course_to_update = '{{"course": {{"integration_id": "{}", "name": "test_course"}}}}'.format(
            self.integration_id).encode()
        mock_all_courses_resp = [{
            'name': 'wrong course',
            'integration_id': 'wrong integration id',
            'id': 2
        }]
        canvas_api_client = CanvasAPIClient(self.enterprise_config)

        with pytest.raises(CanvasClientError) as client_error:
            with responses.RequestsMock() as request_mock:
                request_mock.add(responses.GET,
                                 self.get_all_courses_url,
                                 json=mock_all_courses_resp,
                                 status=200)
                request_mock.add(responses.POST,
                                 self.oauth_url,
                                 json={'access_token': self.access_token},
                                 status=200)
                transmitter_method = getattr(canvas_api_client, request_type)
                transmitter_method(course_to_update)

        assert client_error.value.__str__() == 'Canvas Client Error: No Canvas courses found' \
                                               ' with associated integration ID: {}.'.format(self.integration_id)
Пример #10
0
    def test_course_completion_with_no_canvas_user(self):
        """Test that we properly raise exceptions if the client can't find the edx user in Canvas"""

        with responses.RequestsMock() as rsps:
            rsps.add(responses.GET,
                     self.canvas_users_url,
                     body="[]",
                     status=200)
            rsps.add(responses.POST,
                     self.oauth_url,
                     json={"access_token": self.access_token},
                     status=200)
            canvas_api_client = CanvasAPIClient(self.enterprise_config)
            with pytest.raises(CanvasClientError) as client_error:
                canvas_api_client.create_course_completion(
                    self.canvas_email, self.course_completion_payload)

            assert client_error.value.__str__() == 'Canvas Client Error: No Canvas user ID ' \
                                                   'found associated with email: {}'.format(self.canvas_email)
Пример #11
0
    def test_assessment_reporting_with_no_canvas_course_found(self):
        """
        Test that reporting assessment level data raises the proper exception when no Canvas course is found.
        """
        with responses.RequestsMock() as rsps:
            rsps.add(responses.GET, self.canvas_user_courses_url, json=[])

            # Creating a Canvas assignment will require the session to be created
            rsps.add(responses.POST,
                     self.oauth_url,
                     json=self._token_response(),
                     status=200)

            canvas_api_client = CanvasAPIClient(self.enterprise_config)
            canvas_api_client._create_session()  # pylint: disable=protected-access

            with pytest.raises(ClientError) as client_error:
                canvas_api_client._handle_get_user_canvas_course(
                    self.canvas_user_id, self.course_id)  # pylint: disable=protected-access
                assert client_error.value.message == \
                    "Course: {course_id} not found registered in Canvas for Edx " \
                    "learner: {canvas_email}/Canvas learner: {canvas_user_id}.".format(
                        course_id=self.course_id,
                        canvas_email=self.canvas_email,
                        canvas_user_id=self.canvas_user_id
                    )
Пример #12
0
    def test_grade_reporting_post_submission_500s(self):
        """
        Test that the client raises the appropriate error if Canvas returns an error after the client posts grade data
        in the form of a Canvas submission.
        """
        with responses.RequestsMock() as rsps:
            rsps.add(responses.PUT,
                     self.canvas_submission_url,
                     json={'errors': [{
                         'message': 'Something went wrong.'
                     }]},
                     status=400)
            canvas_api_client = CanvasAPIClient(self.enterprise_config)

            # Submitting a Canvas assignment will require the session to be created
            rsps.add(responses.POST,
                     self.oauth_url,
                     json=self._token_response(),
                     status=200)
            canvas_api_client._create_session()  # pylint: disable=protected-access

            with pytest.raises(ClientError) as client_error:
                canvas_api_client._handle_canvas_assignment_submission(  # pylint: disable=protected-access
                    '100', self.canvas_course_id, self.canvas_assignment_id,
                    self.canvas_user_id)
            assert client_error.value.message == (
                'Something went wrong while posting a submission to Canvas '
                'assignment: {} under Canvas course: {}. Recieved response '
                '{{"errors": [{{"message": "Something went wrong."}}]}} with the '
                'status code: 400').format(str(self.canvas_assignment_id),
                                           str(self.canvas_course_id))
Пример #13
0
    def test_grade_reporting_post_assignment_500s(self):
        """
        Test that the client raises the appropriate error if Canvas returns an error after the client posts an
        assignment.
        """
        with responses.RequestsMock() as rsps:
            rsps.add(responses.GET, self.canvas_assignment_url, json=[])
            rsps.add(responses.POST,
                     self.canvas_assignment_url,
                     json={
                         'errors': [{
                             'message':
                             'The specified resource does not exist.'
                         }]
                     })
            canvas_api_client = CanvasAPIClient(self.enterprise_config)

            # Creating a Canvas assignment will require the session to be created
            rsps.add(responses.POST,
                     self.oauth_url,
                     json=self._token_response(),
                     status=200)
            canvas_api_client._create_session()  # pylint: disable=protected-access

            with pytest.raises(ClientError) as client_error:
                canvas_api_client._handle_canvas_assignment_retrieval(  # pylint: disable=protected-access
                    'integration_id_1', self.canvas_course_id,
                    'assignment_name')

            assert client_error.value.message == 'Something went wrong creating an assignment on Canvas. Got ' \
                                                 'response: {"errors": [{"message": "The specified resource does not ' \
                                                 'exist."}]}'
Пример #14
0
    def test_grade_reporting_get_assignment_500s(self):
        """
        Test that the client raises the appropriate error if Canvas responds with an error after the client requests
        course assignments.
        """
        with responses.RequestsMock() as rsps:
            rsps.add(responses.GET,
                     self.canvas_assignment_url,
                     json={'error': 'something went wrong'},
                     status=400)
            canvas_api_client = CanvasAPIClient(self.enterprise_config)

            # Creating a Canvas assignment will require the session to be created
            rsps.add(responses.POST,
                     self.oauth_url,
                     json=self._token_response(),
                     status=200)
            canvas_api_client._create_session()  # pylint: disable=protected-access

            with pytest.raises(ClientError) as client_error:
                canvas_api_client._handle_canvas_assignment_retrieval(  # pylint: disable=protected-access
                    'integration_id_1', self.canvas_course_id,
                    'assignment_name')

            assert client_error.value.message == 'Something went wrong retrieving assignments from Canvas. Got' \
                                                 ' response: {"error": "something went wrong"}'
Пример #15
0
    def test_search_for_canvas_user_with_400(self):
        """
        Test that we properly raise exceptions if the client can't find the edx user in Canvas while reporting
        grades (assessment and course level reporting both use the same method of retrieval).
        """
        with responses.RequestsMock() as rsps:
            rsps.add(responses.GET,
                     self.canvas_users_url,
                     body="[]",
                     status=200)
            canvas_api_client = CanvasAPIClient(self.enterprise_config)

            # Searching for canvas users will require the session to be created
            rsps.add(responses.POST,
                     self.oauth_url,
                     json=self._token_response(),
                     status=200)
            canvas_api_client._create_session()  # pylint: disable=protected-access

            with pytest.raises(ClientError) as client_error:
                canvas_api_client._search_for_canvas_user_by_email(
                    self.canvas_email)  # pylint: disable=protected-access
                assert client_error.value.message == \
                    "Course: {course_id} not found registered in Canvas for Edx " \
                    "learner: {canvas_email}/Canvas learner: {canvas_user_id}.".format(
                        course_id=self.course_id,
                        canvas_email=self.canvas_email,
                        canvas_user_id=self.canvas_user_id
                    )
Пример #16
0
    def update_fails_with_poorly_formatted_data(self, request_type):
        """
        Helper method to test error handling with poorly formatted data
        """
        poorly_formatted_data = 'this is a string, not a bytearray'
        canvas_api_client = CanvasAPIClient(self.enterprise_config)

        with pytest.raises(ClientError) as client_error:
            with responses.RequestsMock() as request_mock:
                request_mock.add(responses.POST,
                                 self.oauth_url,
                                 json=self._token_response(),
                                 status=200)
                transmitter_method = getattr(canvas_api_client, request_type)
                transmitter_method(poorly_formatted_data)

        assert client_error.value.message == 'Unable to decode data.'
Пример #17
0
    def update_fails_with_poorly_constructed_data(self, request_type):
        """
        Helper method to test error handling with poorly constructed data
        """
        bad_course_to_update = '{"course": {"name": "test_course"}}'.encode()
        canvas_api_client = CanvasAPIClient(self.enterprise_config)

        with pytest.raises(ClientError) as client_error:
            with responses.RequestsMock() as request_mock:
                request_mock.add(responses.POST,
                                 self.oauth_url,
                                 json=self._token_response(),
                                 status=200)
                transmitter_method = getattr(canvas_api_client, request_type)
                transmitter_method(bad_course_to_update)

        assert client_error.value.message == 'Could not transmit data, no integration ID present.'
Пример #18
0
    def transmission_with_empty_data(self, request_type):
        """
        Helper method to test error handling with empty data
        """
        empty_data = ''
        canvas_api_client = CanvasAPIClient(self.enterprise_config)

        with pytest.raises(ClientError) as client_error:
            with responses.RequestsMock() as request_mock:
                request_mock.add(responses.POST,
                                 self.oauth_url,
                                 json=self._token_response(),
                                 status=200)
                transmitter_method = getattr(canvas_api_client, request_type)
                transmitter_method(empty_data)

        assert client_error.value.message == 'No data to transmit.'
Пример #19
0
    def test_expires_at_is_updated_after_session_expiry(self):
        canvas_api_client = CanvasAPIClient(self.enterprise_config)

        with responses.RequestsMock() as rsps:
            orig_time = datetime.datetime.utcnow()
            rsps.add(
                responses.POST,
                self.oauth_url,
                json={'access_token': self.access_token, 'expires_in': 1},
                status=200
            )
            canvas_api_client._create_session()  # pylint: disable=protected-access
            assert canvas_api_client.expires_at is not None
            orig_expires_at = canvas_api_client.expires_at

            # let's call again sometime later ensuring expiry
            with freeze_time(orig_time + datetime.timedelta(seconds=1.1)):
                canvas_api_client._create_session()  # pylint: disable=protected-access
                assert canvas_api_client.expires_at > orig_expires_at
Пример #20
0
 def test_client_instantiation_fails_without_client_secret(self):
     with pytest.raises(ClientError) as client_error:
         self.enterprise_config.client_secret = None
         canvas_api_client = CanvasAPIClient(self.enterprise_config)
         canvas_api_client._create_session()  # pylint: disable=protected-access
     assert client_error.value.message == "Failed to generate oauth access token: Client secret required."