def test_canvas_course_id_saved_to_course_instance_bulk(
            self, course_generation_job__objects__filter,
            update_course_generation_workflow_state, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Ensures that the canvas course id is saved to the CourseInstance
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        query_set = Mock(get=Mock(return_value=job))
        course_generation_job__objects__filter.return_value = query_set

        # don't edit the class-wide create_new_course mocks
        with contextlib.nested(
                patch('canvas_course_site_wizard.controller.get_course_data'),
                patch('canvas_course_site_wizard.controller.create_new_course')
        ) as (get_course_data, create_new_course):
            course_data = MagicMock(spec=SISCourseData())
            get_course_data.return_value = course_data
            create_new_course().json.return_value = {
                'id': self.canvas_course_id
            }
            get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
                self.school_id)
            controller.create_canvas_course(self.sis_course_id,
                                            self.sis_user_id, self.bulk_job)
            self.assertEqual(course_data.canvas_course_id,
                             self.canvas_course_id)
            course_data.save.assert_called_with(
                update_fields=['canvas_course_id'])
    def test_canvas_section_error_sends_support_email(
            self, send_failure_msg_to_support,
            course_generation_job__objects__filter,
            course_generation_job__objects__create,
            update_course_generation_workflow_state, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Test to assert that a support email is sent when there is a
        CanvasAPIError resulting in CanvasSectionCreateError.
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        query_set = Mock(get=Mock(return_value=job))
        course_generation_job__objects__filter.return_value = query_set
        create_course_section.side_effect = CanvasAPIError(status_code=400)

        exception_data = CanvasSectionCreateError(self.sis_course_id)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            self.school_id)
        with self.assertRaises(CanvasSectionCreateError):
            controller.create_canvas_course(self.sis_course_id,
                                            self.sis_user_id)

        send_failure_msg_to_support.assert_called_with(
            self.sis_course_id, self.sis_user_id, exception_data.display_text)
    def test_canvas_course_id_saved_to_canvas_course_generation_job_bulk(
            self, course_generation_job__objects__filter,
            update_course_generation_workflow_state, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Ensures that the canvas course id is saved to the
        CanvasCourseGenerationJob
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        query_set = Mock(get=Mock(return_value=job))
        course_generation_job__objects__filter.return_value = query_set
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            self.school_id)

        # don't edit the class-wide create_new_course mock
        with patch('canvas_course_site_wizard.controller.create_new_course'
                   ) as create_new_course:
            create_new_course().json.return_value = {
                'id': self.canvas_course_id
            }
            controller.create_canvas_course(self.sis_course_id,
                                            self.sis_user_id, self.bulk_job)
            self.assertEqual(job.canvas_course_id, self.canvas_course_id)
            job.save.assert_called_with(update_fields=['canvas_course_id'])
 def test_404_exception_n_create_new_course_method_invokes_update_workflow_state_with_bulk_job_id(
         self, update_mock, course_generation_job__objects__filter,
         get_course_data, create_course_section, create_new_course,
         get_default_template_for_school):
     """
     Test to assert that a CanvasCourseCreateError is raised when the 
     create_new_course SDK call throws a CanvasAPIError,
     and update_content_migration_workflow_state is invoked to update the
     status to STATUS_SETUP_FAILED
     """
     query_set = Mock(get=Mock(return_value=Mock(
         spec=CanvasCourseGenerationJob)))
     course_generation_job__objects__filter.return_value = query_set
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     create_new_course.side_effect = CanvasAPIError(status_code=404)
     with self.assertRaises(CanvasCourseCreateError):
         controller.create_canvas_course(self.sis_course_id,
                                         self.sis_user_id,
                                         bulk_job=self.bulk_job)
     update_mock.assert_called_with(
         self.sis_course_id,
         CanvasCourseGenerationJob.STATUS_SETUP_FAILED,
         course_job_id=None,
         bulk_job_id=self.bulk_job_id)
    def test_create_new_course_called_with_no_default_template_params(
            self, SDK_CONTEXT, logger, course_generation_job__objects__filter,
            course_generation_job__objects__create,
            update_course_generation_workflow_state, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Test to assert that create_new_course method is called by
        create_canvas_course controller method with appropriate arguments
        (collapses a bunch of individual parameter tests)
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        query_set = Mock(get=Mock(return_value=job))
        course_generation_job__objects__filter.return_value = query_set
        course_model_mock = self.get_mock_of_get_course_data()
        get_course_data.return_value = course_model_mock
        sis_account_id_argument = 'sis_account_id:' + course_model_mock.sis_account_id
        course_code_argument = course_model_mock.course_code
        course_name_argument = course_model_mock.course_name
        course_term_id_argument = 'sis_term_id:' + course_model_mock.sis_term_id
        course_sis_course_id_argument = self.sis_course_id

        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            school_id=self.school_id)
        controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
        create_new_course.assert_called_with(
            request_ctx=SDK_CONTEXT,
            account_id=sis_account_id_argument,
            course_name=course_name_argument,
            course_course_code=course_code_argument,
            course_term_id=course_term_id_argument,
            course_sis_course_id=course_sis_course_id_argument,
            course_is_public_to_auth_users=False)
    def test_create_new_course_called_with_no_bulk_template_params(self,
            SDK_CONTEXT, logger, course_generation_job__objects__filter,
            course_generation_job__objects__create,
            update_course_generation_workflow_state, get_template_course, get_course_data,
            create_course_section, create_new_course, get_default_template_for_school):
        """
        Test to assert that create_new_course method is called by
        create_canvas_course controller method with appropriate arguments
        (collapses a bunch of individual parameter tests)
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        query_set = Mock(get=Mock(return_value=job))
        course_generation_job__objects__filter.return_value = query_set
        course_model_mock = self.get_mock_of_get_course_data()
        get_course_data.return_value = course_model_mock
        sis_account_id_argument = 'sis_account_id:' + course_model_mock.sis_account_id
        course_code_argument = course_model_mock.course_code
        course_name_argument = course_model_mock.course_name
        course_term_id_argument = 'sis_term_id:' + course_model_mock.sis_term_id
        course_sis_course_id_argument = self.sis_course_id
        bulk_job = BulkCanvasCourseCreationJob(id=self.bulk_job_id, template_canvas_course_id=None)

        controller.create_canvas_course(self.sis_course_id, self.sis_user_id, bulk_job)
        assert not get_default_template_for_school.called
        assert not get_template_course.called
        create_new_course.assert_called_with(
            request_ctx=SDK_CONTEXT,
            account_id=sis_account_id_argument,
            course_name=course_name_argument,
            course_course_code=course_code_argument,
            course_term_id=course_term_id_argument,
            course_sis_course_id=course_sis_course_id_argument,
            course_is_public_to_auth_users=False
        )
 def test_custome_error_raised_when_job_creation_has_exception(self, canvas_content_gen_db_mock, get_course_data,
                                                               create_course_section, create_new_course,
                                                               get_default_template_for_school):
     """
     Test to assert that a CourseGenerationJobCreationError is raised when CanvasCourseGenerationJob creation has an exception
     """
     canvas_content_gen_db_mock.side_effect= Exception
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     with self.assertRaises(CourseGenerationJobCreationError):
         controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
 def test_exception_when_create_new_course_method_raises_api_400(self, get_course_data, create_course_section,
                                                                 create_new_course, get_default_template_for_school):
     """
     Test to assert that a CanvasCourseAlreadyExistsError is raised when the create_new_course method
     throws a CanvasAPIError
     """
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     create_new_course.side_effect = CanvasAPIError(status_code=400)
     with self.assertRaises(CanvasCourseAlreadyExistsError):
         controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
 def test_exception_when_create_new_course_method_raises_api_404(self, send_failure_msg_to_support, get_course_data,
                                                                 create_course_section, create_new_course,
                                                                 get_default_template_for_school):
     """
     Test to assert that a RenderableException is raised when the create_new_course SDK call
     throws an CanvasAPIError
     """
     create_new_course.side_effect = CanvasAPIError(status_code=404)
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     with self.assertRaises(CanvasCourseCreateError):
         controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
    def test_canvas_course_already_exists_error_doesnt_set_support_notified(self, send_failure_msg_to_support,
                                                                            get_course_data, create_course_section,
                                                                            create_new_course, get_default_template_for_school):
        """
        Test to assert that support_notified is NOT set on CanvasCourseAlreadyExistsError
        """
        create_new_course.side_effect = CanvasAPIError(status_code=400)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
        with self.assertRaises(CanvasCourseAlreadyExistsError) as cm:
            controller.create_canvas_course(self.sis_course_id, self.sis_user_id)

        self.assertTrue('support_notified' not in cm.exception)
 def test_create_canvas_course_method_logs_on_job_creation_exception(self, canvas_content_gen_db_mock, logger,
                                                                     get_course_data,
                                                                     create_course_section, create_new_course,
                                                                     get_default_template_for_school, **kwargs):
     """
     Test that create_canvas_course method logs an error when CanvasCourseGenerationJob creation has an exception
     """
     canvas_content_gen_db_mock.side_effect= Exception
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     with self.assertRaises(Exception):
         controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
     self.assertTrue(logger.exception.called)
 def test_object_not_found_exception_in_get_course_data_logs_error(
         self, send_failure_msg_to_support, log_replacement,
         get_course_data, create_course_section, create_new_course, get_default_template_for_school):
     """
     Test that the logger.error logs error when when get_course_data throws
     an ObjectDoesNotExist exception.
     """
     get_course_data.side_effect = ObjectDoesNotExist
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     with self.assertRaises(SISCourseDoesNotExistError):
         controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
     self.assertTrue(log_replacement.error.called)
 def test_create_canvas_course_method_invokes_create_generation_record(self, canvas_content_gen_create,
                                                                       get_course_data, create_course_section,
                                                                       create_new_course, get_default_template_for_school,
                                                                       **kwargs):
     """
     Test that create_canvas_course method invokes a creation of CanvasCourseGenerationJob record
     with  workflow_state to STATUS_SETUP
     """
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
     self.assertTrue(canvas_content_gen_create.called)
     canvas_content_gen_create.assert_called_with(sis_course_id=self.sis_course_id, created_by_user_id=self.sis_user_id,
                                                   workflow_state=CanvasCourseGenerationJob.STATUS_SETUP)
 def test_exception_when_create_new_course_method_raises_api_400(
         self, get_course_data, create_course_section, create_new_course,
         get_default_template_for_school):
     """
     Test to assert that a CanvasCourseAlreadyExistsError is raised when the create_new_course method
     throws a CanvasAPIError
     """
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     create_new_course.side_effect = CanvasAPIError(status_code=400)
     with self.assertRaises(CanvasCourseAlreadyExistsError):
         controller.create_canvas_course(self.sis_course_id,
                                         self.sis_user_id)
 def test_custome_error_raised_when_job_creation_has_exception(
         self, canvas_content_gen_db_mock, get_course_data,
         create_course_section, create_new_course,
         get_default_template_for_school):
     """
     Test to assert that a CourseGenerationJobCreationError is raised when CanvasCourseGenerationJob creation has an exception
     """
     canvas_content_gen_db_mock.side_effect = Exception
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     with self.assertRaises(CourseGenerationJobCreationError):
         controller.create_canvas_course(self.sis_course_id,
                                         self.sis_user_id)
    def test_canvas_course_create_error_sets_support_notified(self, send_failure_msg_to_support, get_course_data,
                                                              create_course_section, create_new_course,
                                                              get_default_template_for_school):
        """
        Test to assert that support_notified is set on CanvasCourseCreateError
        """
        create_new_course.side_effect = CanvasAPIError(status_code=404)
        exception_data = CanvasCourseCreateError(msg_details=self.sis_course_id)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
        with self.assertRaises(CanvasCourseCreateError):
            controller.create_canvas_course(self.sis_course_id, self.sis_user_id)

        self.assertTrue(exception_data.support_notified)
 def test_when_create_course_section_method_raises_api_error(self,
         course_generation_job__objects__create,
         update_course_generation_workflow_state, send_failure_msg_to_support,
         get_course_data, create_course_section, create_new_course, get_default_template_for_school):
     """
     Test to assert that a RenderableException is raised when the create_course_section SDK call
     throws an CanvasAPIError
     """
     job = Mock(spec=CanvasCourseGenerationJob())
     course_generation_job__objects__create.return_value = job
     create_course_section.side_effect = CanvasAPIError(status_code=400)
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     with self.assertRaises(RenderableException):
         controller.create_canvas_course(self.sis_course_id, self.sis_user_id, None)
 def test_exception_when_create_new_course_method_raises_api_404(
         self, send_failure_msg_to_support, get_course_data,
         create_course_section, create_new_course,
         get_default_template_for_school):
     """
     Test to assert that a RenderableException is raised when the create_new_course SDK call
     throws an CanvasAPIError
     """
     create_new_course.side_effect = CanvasAPIError(status_code=404)
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     with self.assertRaises(CanvasCourseCreateError):
         controller.create_canvas_course(self.sis_course_id,
                                         self.sis_user_id)
 def test_create_canvas_course_method_logs_on_job_creation_exception(
         self, canvas_content_gen_db_mock, logger, get_course_data,
         create_course_section, create_new_course,
         get_default_template_for_school, **kwargs):
     """
     Test that create_canvas_course method logs an error when CanvasCourseGenerationJob creation has an exception
     """
     canvas_content_gen_db_mock.side_effect = Exception
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     with self.assertRaises(Exception):
         controller.create_canvas_course(self.sis_course_id,
                                         self.sis_user_id)
     self.assertTrue(logger.exception.called)
    def test_object_not_found_exception_in_get_course_data_sends_support_email(self, send_failure_msg_to_support,
                                                                               get_course_data, create_course_section,
                                                                               create_new_course, get_default_template_for_school):
        """
        Test to assert that a support email is sent  when get_course_data raises an ObjectDoesNotExist
        """

        get_course_data.side_effect = ObjectDoesNotExist
        exception_data = SISCourseDoesNotExistError(self.sis_course_id)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)

        with self.assertRaises(SISCourseDoesNotExistError):
            controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
        send_failure_msg_to_support.assert_called_with(self.sis_course_id, self.sis_user_id, exception_data.display_text)
    def test_create_canvas_course_method_creates_generation_record(self, canvas_content_gen_db_mock, get_course_data,
                                                                   create_course_section, create_new_course,
                                                                   get_default_template_for_school, **kwargs):
        """
        Test that create_canvas_course method creates a CanvasCourseGenerationJob record with right parameters
        """
        workflow_mock = MagicMock(workflow_status=CanvasCourseGenerationJob.STATUS_SETUP)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)

        controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
        args, kwargs = canvas_content_gen_db_mock.objects.create.call_args
        canvas_content_gen_db_mock.objects.create.assert_called_with(sis_course_id=self.sis_course_id,
                                                                      created_by_user_id=self.sis_user_id,
                                                                      workflow_state=ANY)
    def test_canvas_course_exists_error_doesnt_send_support_email(self, send_failure_msg_to_support, get_course_data,
                                                                  create_course_section, create_new_course,
                                                                  get_default_template_for_school):
        """
        Test to assert that a support email is NOT sent when canvas course already exists
        (there is a CanvasCourseAlreadyExistsError)

        """
        create_new_course.side_effect = CanvasAPIError(status_code=400)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
        with self.assertRaises(CanvasCourseAlreadyExistsError):
            controller.create_canvas_course(self.sis_course_id, self.sis_user_id)

        self.assertFalse(send_failure_msg_to_support.called)
 def test_object_not_found_exception_in_get_course_data_logs_error(
         self, send_failure_msg_to_support, log_replacement,
         get_course_data, create_course_section, create_new_course,
         get_default_template_for_school):
     """
     Test that the logger.error logs error when when get_course_data throws
     an ObjectDoesNotExist exception.
     """
     get_course_data.side_effect = ObjectDoesNotExist
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     with self.assertRaises(SISCourseDoesNotExistError):
         controller.create_canvas_course(self.sis_course_id,
                                         self.sis_user_id)
     self.assertTrue(log_replacement.error.called)
 def test_create_course_section_method_is_called(self, SDK_CONTEXT, get_course_data,
                                                 create_course_section, create_new_course, get_default_template_for_school):
     """
     Test to assert that create_new_course method is called by create_canvas_course controller method
     """
     course_model_mock = self.get_mock_of_get_course_data()
     get_course_data.return_value = course_model_mock
     mock_canvas_course_id = '12345'
     mock_primary_section_name = course_model_mock.primary_section_name.return_value
     create_new_course.return_value.json.return_value = {'id': mock_canvas_course_id}
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
     create_course_section.assert_called_with(request_ctx=SDK_CONTEXT, course_id=mock_canvas_course_id,
                                              course_section_name=mock_primary_section_name,
                                              course_section_sis_section_id=self.sis_course_id)
 def test_create_canvas_course_method_does_not_invoke_create_generation_record_for_bulk_job(
         self, canvas_content_gen_create,
         course_generation_job__objects__filter,
         update_course_generation_workflow_state, get_course_data,
         create_course_section, create_new_course, get_default_template_for_school, **kwargs):
     """
     Test that create_canvas_course method does not try to create
     CanvasCourseGenerationJob record for courses created by bulk job as well
     """
     query_set = Mock(get=Mock(return_value=Mock(spec=CanvasCourseGenerationJob)))
     course_generation_job__objects__filter.return_value = query_set
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     controller.create_canvas_course(self.sis_course_id, self.sis_user_id,
                                     self.bulk_job)
     self.assertFalse(canvas_content_gen_create.called)
    def test_canvas_course_already_exists_error_doesnt_set_support_notified(
            self, send_failure_msg_to_support, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Test to assert that support_notified is NOT set on CanvasCourseAlreadyExistsError
        """
        create_new_course.side_effect = CanvasAPIError(status_code=400)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            self.school_id)
        with self.assertRaises(CanvasCourseAlreadyExistsError) as cm:
            controller.create_canvas_course(self.sis_course_id,
                                            self.sis_user_id)

        self.assertTrue('support_notified' not in cm.exception)
    def test_canvas_course_create_error_sends_support_email(self, send_failure_msg_to_support, get_course_data,
                                                            create_course_section, create_new_course,
                                                            get_default_template_for_school):
        """
        Test to assert that a support email is sent  when  there is an CanvasAPIError resulting in CanvasCourseCreateError
        and that the correct error message from the exception is sent as a param  to the mail helper method
        """
        create_new_course.side_effect = CanvasAPIError(status_code=404)
        exception_data = CanvasCourseCreateError(msg_details=self.sis_course_id)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
        with self.assertRaises(CanvasCourseCreateError):
            controller.create_canvas_course(self.sis_course_id, self.sis_user_id)

        send_failure_msg_to_support.assert_called_with(self.sis_course_id, self.sis_user_id, exception_data.display_text)
        self.assertTrue('Error: SIS ID not applied for CID' in exception_data.display_text)
 def test_create_canvas_course_method_invokes_create_generation_record(
         self, canvas_content_gen_create, get_course_data,
         create_course_section, create_new_course,
         get_default_template_for_school, **kwargs):
     """
     Test that create_canvas_course method invokes a creation of CanvasCourseGenerationJob record
     with  workflow_state to STATUS_SETUP
     """
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
     self.assertTrue(canvas_content_gen_create.called)
     canvas_content_gen_create.assert_called_with(
         sis_course_id=self.sis_course_id,
         created_by_user_id=self.sis_user_id,
         workflow_state=CanvasCourseGenerationJob.STATUS_SETUP)
    def test_get_course_data_method_called_with_right_params(self,
            course_generation_job__objects__filter,
            course_generation_job__objects__create,
            update_course_generation_workflow_state,
            get_course_data, create_course_section, create_new_course, get_default_template_for_school):
        """
        Test that controller method makes a call to get_course_data api with expected args
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        query_set = Mock(get=Mock(return_value=job))
        course_generation_job__objects__filter.return_value = query_set
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)

        controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
        get_course_data.assert_called_with(self.sis_course_id)
    def test_canvas_course_create_error_sets_support_notified(
            self, send_failure_msg_to_support, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Test to assert that support_notified is set on CanvasCourseCreateError
        """
        create_new_course.side_effect = CanvasAPIError(status_code=404)
        exception_data = CanvasCourseCreateError(
            msg_details=self.sis_course_id)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            self.school_id)
        with self.assertRaises(CanvasCourseCreateError):
            controller.create_canvas_course(self.sis_course_id,
                                            self.sis_user_id)

        self.assertTrue(exception_data.support_notified)
    def test_canvas_course_exists_error_doesnt_send_support_email(
            self, send_failure_msg_to_support, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Test to assert that a support email is NOT sent when canvas course already exists
        (there is a CanvasCourseAlreadyExistsError)
        
        """
        create_new_course.side_effect = CanvasAPIError(status_code=400)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            self.school_id)
        with self.assertRaises(CanvasCourseAlreadyExistsError):
            controller.create_canvas_course(self.sis_course_id,
                                            self.sis_user_id)

        self.assertFalse(send_failure_msg_to_support.called)
 def test_create_canvas_course_method_does_not_invoke_create_generation_record_for_bulk_job(
         self, canvas_content_gen_create,
         course_generation_job__objects__filter,
         update_course_generation_workflow_state, get_course_data,
         create_course_section, create_new_course,
         get_default_template_for_school, **kwargs):
     """
     Test that create_canvas_course method does not try to create 
     CanvasCourseGenerationJob record for courses created by bulk job as well
     """
     query_set = Mock(get=Mock(return_value=Mock(
         spec=CanvasCourseGenerationJob)))
     course_generation_job__objects__filter.return_value = query_set
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     controller.create_canvas_course(self.sis_course_id, self.sis_user_id,
                                     self.bulk_job)
     self.assertFalse(canvas_content_gen_create.called)
    def test_create_canvas_course_method_creates_generation_record(
            self, canvas_content_gen_db_mock, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school, **kwargs):
        """
        Test that create_canvas_course method creates a CanvasCourseGenerationJob record with right parameters
        """
        workflow_mock = MagicMock(
            workflow_status=CanvasCourseGenerationJob.STATUS_SETUP)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            self.school_id)

        controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
        args, kwargs = canvas_content_gen_db_mock.objects.create.call_args
        canvas_content_gen_db_mock.objects.create.assert_called_with(
            sis_course_id=self.sis_course_id,
            created_by_user_id=self.sis_user_id,
            workflow_state=ANY)
    def test_canvas_course_id_saved_to_canvas_course_generation_job_single(self,
            course_generation_job__objects__create,
            update_course_generation_workflow_state, get_course_data,
            create_course_section, create_new_course, get_default_template_for_school):
        """
        Ensures that the canvas course id is saved to the
        CanvasCourseGenerationJob
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)

        # don't edit the class-wide create_new_course mock
        with patch('canvas_course_site_wizard.controller.create_new_course') as create_new_course:
            create_new_course().json.return_value = {'id': self.canvas_course_id}
            controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
            self.assertEqual(job.canvas_course_id, self.canvas_course_id)
            job.save.assert_called_with(update_fields=['canvas_course_id'])
    def test_object_not_found_exception_in_get_course_data_doesnt_send_support_email_for_bulk_created_course(
            self, course_generation_job__objects__create,
            send_failure_msg_to_support,
            get_course_data, create_course_section, create_new_course, get_default_template_for_school):
        """
        Test to assert that for a course that is created as part of a bulk job,
        the support email is not sent when get_course_data raises an
        ObjectDoesNotExist
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        get_course_data.side_effect = ObjectDoesNotExist
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)

        with self.assertRaises(CourseGenerationJobNotFoundError):
            controller.create_canvas_course(self.sis_course_id, self.sis_user_id,
                                            self.bulk_job)
        self.assertFalse(send_failure_msg_to_support.called)
 def test_when_create_course_section_method_raises_api_error(
         self, course_generation_job__objects__create,
         update_course_generation_workflow_state,
         send_failure_msg_to_support, get_course_data,
         create_course_section, create_new_course,
         get_default_template_for_school):
     """
     Test to assert that a RenderableException is raised when the create_course_section SDK call
     throws an CanvasAPIError
     """
     job = Mock(spec=CanvasCourseGenerationJob())
     course_generation_job__objects__create.return_value = job
     create_course_section.side_effect = CanvasAPIError(status_code=400)
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     with self.assertRaises(RenderableException):
         controller.create_canvas_course(self.sis_course_id,
                                         self.sis_user_id, None)
    def test_object_not_found_exception_in_get_course_data_sends_support_email(
            self, send_failure_msg_to_support, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Test to assert that a support email is sent  when get_course_data raises an ObjectDoesNotExist
        """

        get_course_data.side_effect = ObjectDoesNotExist
        exception_data = SISCourseDoesNotExistError(self.sis_course_id)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            self.school_id)

        with self.assertRaises(SISCourseDoesNotExistError):
            controller.create_canvas_course(self.sis_course_id,
                                            self.sis_user_id)
        send_failure_msg_to_support.assert_called_with(
            self.sis_course_id, self.sis_user_id, exception_data.display_text)
 def test_canvas_course_create_error_doesnt_send_support_email_for_bulk_created_course(
         self, send_failure_msg_to_support,
         course_generation_job__objects__filter,
         update_course_generation_workflow_state, get_course_data,
         create_course_section, create_new_course, get_default_template_for_school):
     """
     Test to assert that a for a course that is created as part of a bulk
     job, the support email is not sent when there is an CanvasAPIError
     resulting in CanvasCourseCreateError.
     """
     query_set = Mock(get=Mock(return_value=Mock(spec=CanvasCourseGenerationJob)))
     course_generation_job__objects__filter.return_value = query_set
     create_new_course.side_effect = CanvasAPIError(status_code=404)
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     with self.assertRaises(CanvasCourseCreateError):
         controller.create_canvas_course(self.sis_course_id, self.sis_user_id,
                                         self.bulk_job)
     self.assertFalse(send_failure_msg_to_support.called)
    def test_get_course_data_method_called_with_right_params(
            self, course_generation_job__objects__filter,
            course_generation_job__objects__create,
            update_course_generation_workflow_state, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Test that controller method makes a call to get_course_data api with expected args
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        query_set = Mock(get=Mock(return_value=job))
        course_generation_job__objects__filter.return_value = query_set
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            self.school_id)

        controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
        get_course_data.assert_called_with(self.sis_course_id)
    def test_create_new_course_called_with_bulk_template_params(
            self, SDK_CONTEXT, logger, course_generation_job__objects__filter,
            course_generation_job__objects__create,
            update_course_generation_workflow_state, get_template_course,
            get_course_data, create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Test to assert that create_new_course method is called by
        create_canvas_course controller method with appropriate arguments
        (collapses a bunch of individual parameter tests)
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        query_set = Mock(get=Mock(return_value=job))
        course_generation_job__objects__filter.return_value = query_set
        course_model_mock = self.get_mock_of_get_course_data()
        get_template_course.return_value = Bunch(
            json=lambda: {
                'is_public': True,
                'public_syllabus': True,
                'is_public_to_auth_users': True
            })
        get_course_data.return_value = course_model_mock
        sis_account_id_argument = 'sis_account_id:' + course_model_mock.sis_account_id
        course_code_argument = course_model_mock.course_code
        course_name_argument = course_model_mock.course_name
        course_term_id_argument = 'sis_term_id:' + course_model_mock.sis_term_id
        course_sis_course_id_argument = self.sis_course_id
        bulk_job = BulkCanvasCourseCreationJob(id=self.bulk_job_id,
                                               template_canvas_course_id=12345)

        controller.create_canvas_course(self.sis_course_id, self.sis_user_id,
                                        bulk_job)
        assert not get_default_template_for_school.called
        create_new_course.assert_called_with(
            request_ctx=SDK_CONTEXT,
            account_id=sis_account_id_argument,
            course_name=course_name_argument,
            course_course_code=course_code_argument,
            course_term_id=course_term_id_argument,
            course_sis_course_id=course_sis_course_id_argument,
            course_is_public_to_auth_users=True,
            course_is_public=True,
            course_public_syllabus=True)
 def test_404_exception_n_create_new_course_method_invokes_update_workflow_state_with_bulk_job_id(
         self, update_mock, course_generation_job__objects__filter,
         get_course_data, create_course_section, create_new_course, get_default_template_for_school):
     """
     Test to assert that a CanvasCourseCreateError is raised when the
     create_new_course SDK call throws a CanvasAPIError,
     and update_content_migration_workflow_state is invoked to update the
     status to STATUS_SETUP_FAILED
     """
     query_set = Mock(get=Mock(return_value=Mock(spec=CanvasCourseGenerationJob)))
     course_generation_job__objects__filter.return_value = query_set
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     create_new_course.side_effect = CanvasAPIError(status_code=404)
     with self.assertRaises(CanvasCourseCreateError):
         controller.create_canvas_course(self.sis_course_id, self.sis_user_id,
                                         bulk_job=self.bulk_job)
     update_mock.assert_called_with(
         self.sis_course_id, CanvasCourseGenerationJob.STATUS_SETUP_FAILED,
         course_job_id=None, bulk_job_id=self.bulk_job_id)
    def test_object_not_found_exception_in_get_course_data_doesnt_send_support_email_for_bulk_created_course(
            self, course_generation_job__objects__create,
            send_failure_msg_to_support, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Test to assert that for a course that is created as part of a bulk job,
        the support email is not sent when get_course_data raises an
        ObjectDoesNotExist
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        get_course_data.side_effect = ObjectDoesNotExist
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            self.school_id)

        with self.assertRaises(CourseGenerationJobNotFoundError):
            controller.create_canvas_course(self.sis_course_id,
                                            self.sis_user_id, self.bulk_job)
        self.assertFalse(send_failure_msg_to_support.called)
    def test_canvas_section_error_sets_support_notified(self,
            send_failure_msg_to_support,
            course_generation_job__objects__filter,
            course_generation_job__objects__create,
            update_course_generation_workflow_state, get_course_data,
            create_course_section, create_new_course, get_default_template_for_school):
        """
        Test to assert that support_notified is set on CanvasSectionCreateError
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        query_set = Mock(get=Mock(return_value=job))
        course_generation_job__objects__filter.return_value = query_set
        create_course_section.side_effect = CanvasAPIError(status_code=400)
        exception_data = CanvasSectionCreateError(self.sis_course_id)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
        with self.assertRaises(CanvasSectionCreateError):
            controller.create_canvas_course(self.sis_course_id, self.sis_user_id)

        self.assertTrue(exception_data.support_notified)
 def test_404_exception_n_create_new_course_method_invokes_update_workflow_state(
         self, update_mock, get_course_data, create_course_section,
         create_new_course, get_default_template_for_school):
     """
     A RenderableException should be raised and and
     update_content_generation_workflow_state() is invoked
     when the create_new_course SDK call throws an CanvasAPIError
     """
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     create_new_course.side_effect = CanvasAPIError(status_code=404)
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     with self.assertRaises(CanvasCourseCreateError):
         controller.create_canvas_course(self.sis_course_id,
                                         self.sis_user_id)
     update_mock.assert_called_with(
         self.sis_course_id,
         CanvasCourseGenerationJob.STATUS_SETUP_FAILED,
         course_job_id=ANY,
         bulk_job_id=None)
 def test_create_course_section_method_is_called(
         self, SDK_CONTEXT, get_course_data, create_course_section,
         create_new_course, get_default_template_for_school):
     """
     Test to assert that create_new_course method is called by create_canvas_course controller method
     """
     course_model_mock = self.get_mock_of_get_course_data()
     get_course_data.return_value = course_model_mock
     mock_canvas_course_id = '12345'
     mock_primary_section_name = course_model_mock.primary_section_name.return_value
     create_new_course.return_value.json.return_value = {
         'id': mock_canvas_course_id
     }
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
     create_course_section.assert_called_with(
         request_ctx=SDK_CONTEXT,
         course_id=mock_canvas_course_id,
         course_section_name=mock_primary_section_name,
         course_section_sis_section_id=self.sis_course_id)
    def test_canvas_course_create_error_sends_support_email(
            self, send_failure_msg_to_support, get_course_data,
            create_course_section, create_new_course,
            get_default_template_for_school):
        """
        Test to assert that a support email is sent  when  there is an CanvasAPIError resulting in CanvasCourseCreateError
        and that the correct error message from the exception is sent as a param  to the mail helper method
        """
        create_new_course.side_effect = CanvasAPIError(status_code=404)
        exception_data = CanvasCourseCreateError(
            msg_details=self.sis_course_id)
        get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
            self.school_id)
        with self.assertRaises(CanvasCourseCreateError):
            controller.create_canvas_course(self.sis_course_id,
                                            self.sis_user_id)

        send_failure_msg_to_support.assert_called_with(
            self.sis_course_id, self.sis_user_id, exception_data.display_text)
        self.assertTrue(
            'Error: SIS ID not applied for CID' in exception_data.display_text)
 def test_canvas_course_create_error_doesnt_send_support_email_for_bulk_created_course(
         self, send_failure_msg_to_support,
         course_generation_job__objects__filter,
         update_course_generation_workflow_state, get_course_data,
         create_course_section, create_new_course,
         get_default_template_for_school):
     """
     Test to assert that a for a course that is created as part of a bulk 
     job, the support email is not sent when there is an CanvasAPIError
     resulting in CanvasCourseCreateError.
     """
     query_set = Mock(get=Mock(return_value=Mock(
         spec=CanvasCourseGenerationJob)))
     course_generation_job__objects__filter.return_value = query_set
     create_new_course.side_effect = CanvasAPIError(status_code=404)
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(
         self.school_id)
     with self.assertRaises(CanvasCourseCreateError):
         controller.create_canvas_course(self.sis_course_id,
                                         self.sis_user_id, self.bulk_job)
     self.assertFalse(send_failure_msg_to_support.called)
    def test_create_new_course_called_with_default_template_params(self,
            SDK_CONTEXT, logger, course_generation_job__objects__filter,
            course_generation_job__objects__create,
            update_course_generation_workflow_state, get_template_course, get_course_data,
            create_course_section, create_new_course, get_default_template_for_school):
        """
        Test to assert that create_new_course method is called by
        create_canvas_course controller method with appropriate arguments
        (collapses a bunch of individual parameter tests)
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job
        query_set = Mock(get=Mock(return_value=job))
        course_generation_job__objects__filter.return_value = query_set
        course_model_mock = self.get_mock_of_get_course_data()
        get_template_course.return_value = Bunch(json=lambda: {
            'is_public': True,
            'public_syllabus': True,
            'is_public_to_auth_users': True
        })
        get_course_data.return_value = course_model_mock
        sis_account_id_argument = 'sis_account_id:' + course_model_mock.sis_account_id
        course_code_argument = course_model_mock.course_code
        course_name_argument = course_model_mock.course_name
        course_term_id_argument = 'sis_term_id:' + course_model_mock.sis_term_id
        course_sis_course_id_argument = self.sis_course_id

        get_default_template_for_school.return_value = Bunch(template_id='12345')
        controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
        create_new_course.assert_called_with(
            request_ctx=SDK_CONTEXT,
            account_id=sis_account_id_argument,
            course_name=course_name_argument,
            course_course_code=course_code_argument,
            course_term_id=course_term_id_argument,
            course_sis_course_id=course_sis_course_id_argument,
            course_is_public_to_auth_users=True,
            course_is_public=True,
            course_public_syllabus=True
        )
    def test_canvas_course_id_saved_to_course_instance_single(self,
            course_generation_job__objects__create,
            update_course_generation_workflow_state, get_course_data,
            create_course_section, create_new_course, get_default_template_for_school):
        """
        Ensures that the canvas course id is saved to the CourseInstance
        """
        job = Mock(spec=CanvasCourseGenerationJob())
        course_generation_job__objects__create.return_value = job

        # don't edit the class-wide create_new_course mocks
        with contextlib.nested(
                patch('canvas_course_site_wizard.controller.get_course_data'),
                patch('canvas_course_site_wizard.controller.create_new_course')
                ) as (get_course_data, create_new_course):
            course_data = MagicMock(spec=SISCourseData())
            get_course_data.return_value = course_data
            create_new_course().json.return_value = {'id': self.canvas_course_id}
            get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
            controller.create_canvas_course(self.sis_course_id, self.sis_user_id)
            self.assertEqual(course_data.canvas_course_id, self.canvas_course_id)
            course_data.save.assert_called_with(update_fields=['canvas_course_id'])
 def test_404_exception_n_create_new_course_method_invokes_update_workflow_state(self, update_mock,
                                                                                 get_course_data,
                                                                                 create_course_section,
                                                                                 create_new_course,
                                                                                 get_default_template_for_school):
     """
     A RenderableException should be raised and and
     update_content_generation_workflow_state() is invoked
     when the create_new_course SDK call throws an CanvasAPIError
     """
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     create_new_course.side_effect = CanvasAPIError(status_code=404)
     get_default_template_for_school.side_effect = NoTemplateExistsForSchool(self.school_id)
     with self.assertRaises(CanvasCourseCreateError):
         controller.create_canvas_course(
             self.sis_course_id,
             self.sis_user_id
         )
     update_mock.assert_called_with(
         self.sis_course_id,
         CanvasCourseGenerationJob.STATUS_SETUP_FAILED,
         course_job_id=ANY,
         bulk_job_id=None
     )
def _init_courses_with_status_setup():
    """
    get all records in the canvas course generation job table that have the status 'setup'.
    These are courses that have not been created, they only have a CanvasCourseGenerationJob with a 'setup' status.
    This method will create the course and update the status to QUEUED
    """

    create_jobs = CanvasCourseGenerationJob.objects.filter_setup_for_bulkjobs()
    # Get the bulk job parent for each course job and map by id for later use
    bulk_jobs = {
        b.id: b
        for b in BulkJob.objects.filter(
            id__in=[j.bulk_job_id for j in create_jobs])
    }

    # for each or the records above, create the course and update the status
    for create_job in create_jobs:
        # for each job we need to get the bulk_job_id, user, and course id, these are
        # needed by the calls to create the course below. If any of these break, mark the course as failed
        # and continue to the next course.
        bulk_job = bulk_jobs.get(create_job.bulk_job_id)
        if not bulk_job:
            create_job.update_workflow_state(
                CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
            continue
        bulk_job_id = bulk_job.id

        sis_user_id = create_job.created_by_user_id
        if not sis_user_id:
            create_job.update_workflow_state(
                CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
            continue

        sis_course_id = create_job.sis_course_id
        if not sis_course_id:
            create_job.update_workflow_state(
                CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
            continue

        # try to create the canvas course - create_canvas_course has been modified so it will not
        # try to create a new CanvasCourseGenerationJob record if a bulk_job is present
        try:
            logger.info('calling create_canvas_course(%s, %s, bulk_job_id=%s)',
                        sis_course_id, sis_user_id, bulk_job_id)
            course = create_canvas_course(
                sis_course_id,
                sis_user_id,
                bulk_job=bulk_job,
            )
        except (CanvasCourseAlreadyExistsError,
                CourseGenerationJobCreationError, CanvasCourseCreateError,
                CanvasSectionCreateError):
            message = 'content migration error for course with id %s' % sis_course_id
            logger.exception(message)
            create_job.update_workflow_state(
                CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
            continue

        # get the course data - this is needed for the start_course_template_copy method
        try:
            sis_course_data = get_course_data(sis_course_id)
        except ObjectDoesNotExist:
            message = 'Course id %s does not exist, skipping....' % sis_course_id
            logger.exception(message)
            create_job.update_workflow_state(
                CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
            continue

        # Initiate the async job to copy the course template, if a template was selected for the bulk job
        if bulk_job.template_canvas_course_id:
            try:
                start_course_template_copy(
                    sis_course_data,
                    course['id'],
                    sis_user_id,
                    course_job_id=create_job.pk,
                    bulk_job_id=bulk_job_id,
                    template_id=bulk_job.template_canvas_course_id)
            except Exception:
                logger.exception(
                    'template migration failed for course instance id %s' %
                    sis_course_id)
                create_job.update_workflow_state(
                    CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
        else:
            logger.info('no template selected for  %s' % sis_course_id)
            # When there's no template, it doesn't need any migration and the job is ready to be finalized
            create_job.update_workflow_state(
                CanvasCourseGenerationJob.STATUS_PENDING_FINALIZE)
def _init_courses_with_status_setup():
    """
    get all records in the canvas course generation job table that have the status 'setup'.
    These are courses that have not been created, they only have a CanvasCourseGenerationJob with a 'setup' status.
    This method will create the course and update the status to QUEUED
    """

    create_jobs = CanvasCourseGenerationJob.objects.filter_setup_for_bulkjobs()
    # Get the bulk job parent for each course job and map by id for later use
    bulk_jobs = {b.id: b for b in BulkJob.objects.filter(id__in=[j.bulk_job_id for j in create_jobs])}

    # for each or the records above, create the course and update the status
    for create_job in create_jobs:
        # for each job we need to get the bulk_job_id, user, and course id, these are
        # needed by the calls to create the course below. If any of these break, mark the course as failed
        # and continue to the next course.
        bulk_job = bulk_jobs.get(create_job.bulk_job_id)
        if not bulk_job:
            create_job.update_workflow_state(CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
            continue
        bulk_job_id = bulk_job.id

        sis_user_id = create_job.created_by_user_id
        if not sis_user_id:
            create_job.update_workflow_state(CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
            continue

        sis_course_id = create_job.sis_course_id
        if not sis_course_id:
            create_job.update_workflow_state(CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
            continue

        # try to create the canvas course - create_canvas_course has been modified so it will not
        # try to create a new CanvasCourseGenerationJob record if a bulk_job is present
        try:
            logger.info(
                'calling create_canvas_course(%s, %s, bulk_job_id=%s)',
                sis_course_id, sis_user_id,
                bulk_job_id
            )
            course = create_canvas_course(
                sis_course_id,
                sis_user_id,
                bulk_job=bulk_job,
            )
        except (CanvasCourseAlreadyExistsError, CourseGenerationJobCreationError, CanvasCourseCreateError,
                CanvasSectionCreateError):
            message = 'content migration error for course with id %s' % sis_course_id
            logger.exception(message)
            create_job.update_workflow_state(CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
            continue

        # get the course data - this is needed for the start_course_template_copy method
        try:
            sis_course_data = get_course_data(sis_course_id)
        except ObjectDoesNotExist as ex:
            message = 'Course id %s does not exist, skipping....' % sis_course_id
            logger.exception(message)
            create_job.update_workflow_state(CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
            continue

        # Initiate the async job to copy the course template, if a template was selected for the bulk job
        if bulk_job.template_canvas_course_id:
            try:
                start_course_template_copy(
                    sis_course_data,
                    course['id'],
                    sis_user_id,
                    course_job_id=create_job.pk,
                    bulk_job_id=bulk_job_id,
                    template_id=bulk_job.template_canvas_course_id
                )
            except:
                logger.exception('template migration failed for course instance id %s' % sis_course_id)
                create_job.update_workflow_state(CanvasCourseGenerationJob.STATUS_SETUP_FAILED)
        else:
            logger.info('no template selected for  %s' % sis_course_id)
            # When there's no template, it doesn't need any migration and the job is ready to be finalized
            create_job.update_workflow_state(CanvasCourseGenerationJob.STATUS_PENDING_FINALIZE)