示例#1
0
    def test_view_learner(self, status):
        """
        Test that the detail view works correctly for non-ADMINS, and that
        unpublished and deleted Programs are filtered out.
        """
        filtered_statuses = (ProgramStatus.DELETED, ProgramStatus.UNPUBLISHED)
        program = ProgramFactory.create(status=status)
        response = self._make_request(program_id=program.id)

        self.assertEqual(response.status_code, 404 if status in filtered_statuses else 200)

        if status not in filtered_statuses:
            self.assertEqual(
                response.data,
                {
                    'name': program.name,
                    'subtitle': program.subtitle,
                    'category': program.category,
                    'status': status,
                    'organizations': [],
                    'course_codes': [],
                    'id': program.id,
                    'created': program.created.strftime(DRF_DATE_FORMAT),
                    'modified': program.modified.strftime(DRF_DATE_FORMAT),
                    'marketing_slug': program.marketing_slug,
                    'banner_image_urls': {},
                    'uuid': str(program.uuid),
                }
            )
示例#2
0
 def test_view_admin(self, status):
     """
     Test that the detail view works correctly for ADMINS, and that deleted
     Programs are filtered out.
     """
     program = ProgramFactory.create(status=status)
     response = self._make_request(program_id=program.id, admin=True)
     self.assertEqual(response.status_code, 404 if status == ProgramStatus.DELETED else 200)
     if status != ProgramStatus.DELETED:
         self.assertEqual(
             response.data,
             {
                 u"name": program.name,
                 u"subtitle": program.subtitle,
                 u"category": program.category,
                 u"status": status,
                 u"organizations": [],
                 u"course_codes": [],
                 u"id": program.id,
                 u"created": program.created.strftime(DRF_DATE_FORMAT),
                 u"modified": program.modified.strftime(DRF_DATE_FORMAT),
                 u'marketing_slug': program.marketing_slug,
                 u'banner_image_urls': {}
             }
         )
示例#3
0
    def test_invalid_nested_run_modes(self, invalid_mode):
        """
        Ensure that invalid nested run mode data causes a 400 response.
        """
        org = OrganizationFactory.create()
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        course_code = CourseCodeFactory.create(organization=org)

        patch_data = {
            u'course_codes': [
                {
                    u'key': course_code.key,
                    u'organization': {
                        u'key': course_code.organization.key,
                    },
                    u'run_modes': [invalid_mode],
                },
            ],
        }
        response = self._make_request(program_id=program.id,
                                      admin=True,
                                      method='patch',
                                      data=patch_data)
        self.assertEqual(response.status_code, 400)
示例#4
0
    def assert_correct_default_banner_image_urls(self,
                                                 url_prepend='',
                                                 set_program_banner=False):
        """
        DRY test helper.  Ensure that the serializer generates a complete set
        of absolute URLs for the default banner_image when the banner image on program is not set.
        If the flag set_program_banner is defined, then make sure the banner image for program is set
        and returned
        """
        default_program_value = ProgramDefaultFactory.create()
        default_program_value.banner_image = make_banner_image_file(
            'default_test_filename.jpg')
        default_program_value.save()

        program = ProgramFactory.create(status=ProgramStatus.ACTIVE)
        if set_program_banner:
            program.banner_image = make_banner_image_file('test_filename.jpg')
            program.save()

        response = self._make_request(program_id=program.id)
        self.assertEqual(response.status_code, 200)

        banner_image_instance = default_program_value.banner_image
        if set_program_banner:
            banner_image_instance = program.banner_image

        expected_urls = {
            'w{}h{}'.format(*size):
            '{}{}__{}x{}.jpg'.format(url_prepend, banner_image_instance.url,
                                     *size)
            for size in banner_image_instance.field.sizes
        }
        self.assertEqual(response.data[u'banner_image_urls'], expected_urls)
示例#5
0
 def test_view_admin(self, status):
     """
     Test that the detail view works correctly for ADMINS, and that deleted
     Programs are filtered out.
     """
     program = ProgramFactory.create(status=status)
     response = self._make_request(program_id=program.id, admin=True)
     self.assertEqual(response.status_code,
                      404 if status == ProgramStatus.DELETED else 200)
     if status != ProgramStatus.DELETED:
         self.assertEqual(
             response.data, {
                 'name': program.name,
                 'subtitle': program.subtitle,
                 'category': program.category,
                 'status': status,
                 'organizations': [],
                 'course_codes': [],
                 'id': program.id,
                 'created': program.created.strftime(DRF_DATE_FORMAT),
                 'modified': program.modified.strftime(DRF_DATE_FORMAT),
                 'marketing_slug': program.marketing_slug,
                 'banner_image_urls': {},
                 'uuid': str(program.uuid),
             })
示例#6
0
    def assert_correct_default_banner_image_urls(self, url_prepend='', set_program_banner=False):
        """
        DRY test helper.  Ensure that the serializer generates a complete set
        of absolute URLs for the default banner_image when the banner image on program is not set.
        If the flag set_program_banner is defined, then make sure the banner image for program is set
        and returned
        """
        default_program_value = ProgramDefaultFactory.create()
        default_program_value.banner_image = make_banner_image_file('default_test_filename.jpg')
        default_program_value.save()

        program = ProgramFactory.create(status=ProgramStatus.ACTIVE)
        if set_program_banner:
            program.banner_image = make_banner_image_file('test_filename.jpg')
            program.save()

        response = self._make_request(program_id=program.id)
        self.assertEqual(response.status_code, 200)

        banner_image_instance = default_program_value.banner_image
        if set_program_banner:
            banner_image_instance = program.banner_image

        expected_urls = {
            'w{}h{}'.format(*size): '{}{}__{}x{}.jpg'.format(
                url_prepend,
                banner_image_instance.url,
                *size)
            for size in banner_image_instance.field.sizes
        }
        self.assertEqual(response.data['banner_image_urls'], expected_urls)
示例#7
0
 def test_view_admin(self, status):
     """
     Test that the detail view works correctly for ADMINS, and that deleted
     Programs are filtered out.
     """
     program = ProgramFactory.create(status=status)
     response = self._make_request(program_id=program.id, admin=True)
     self.assertEqual(response.status_code, 404 if status == ProgramStatus.DELETED else 200)
     if status != ProgramStatus.DELETED:
         self.assertEqual(
             response.data,
             {
                 'name': program.name,
                 'subtitle': program.subtitle,
                 'category': program.category,
                 'status': status,
                 'organizations': [],
                 'course_codes': [],
                 'id': program.id,
                 'created': program.created.strftime(DRF_DATE_FORMAT),
                 'modified': program.modified.strftime(DRF_DATE_FORMAT),
                 'marketing_slug': program.marketing_slug,
                 'banner_image_urls': {},
                 'uuid': str(program.uuid),
             }
         )
示例#8
0
 def test_view_learner(self, status):
     """
     Test that the detail view works correctly for non-ADMINS, and that
     unpublished and deleted Programs are filtered out.
     """
     filtered_statuses = (ProgramStatus.DELETED, ProgramStatus.UNPUBLISHED)
     program = ProgramFactory.create(status=status)
     response = self._make_request(program_id=program.id)
     self.assertEqual(response.status_code,
                      404 if status in filtered_statuses else 200)
     if status not in filtered_statuses:
         self.assertEqual(
             response.data, {
                 u"name": program.name,
                 u"subtitle": program.subtitle,
                 u"category": program.category,
                 u"status": status,
                 u"organizations": [],
                 u"course_codes": [],
                 u"id": program.id,
                 u"created": program.created.strftime(DRF_DATE_FORMAT),
                 u"modified": program.modified.strftime(DRF_DATE_FORMAT),
                 u'marketing_slug': program.marketing_slug,
                 u'banner_image_urls': {}
             })
示例#9
0
    def test_program_completion_filtering(self, status, is_admin):
        """Verify that program candidates for completion are filtered."""
        program = ProgramFactory.create(status=status)
        org = OrganizationFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)

        course_code = CourseCodeFactory.create(organization=org)
        program_course_code = ProgramCourseCodeFactory.create(
            program=program,
            course_code=course_code
        )

        course_key = 'org/code/run'
        ProgramCourseRunModeFactory.create(
            course_key=course_key,
            program_course_code=program_course_code,
        )

        complete_run_modes = {'completed_courses': [
            {'course_id': course_key, 'mode': 'verified'},
        ]}

        response = self._make_request(method='post', complete=True, data=complete_run_modes, admin=is_admin)

        self.assertEqual(response.status_code, 200)

        program_ids = response.data['program_ids']
        if status in [ProgramStatus.ACTIVE, ProgramStatus.RETIRED]:
            self.assertEqual(program_ids, [1])
        else:
            # No one should be able to complete deleted or unpublished programs.
            self.assertEqual(program_ids, [])
示例#10
0
    def test_update_run_modes(self):
        """
        Ensure that nested run modes can be updated.
        """
        org = OrganizationFactory.create()
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        course_code = CourseCodeFactory.create(organization=org)
        program_course_code = ProgramCourseCodeFactory.create(
            program=program, course_code=course_code)

        for n in range(2):
            ProgramCourseRunModeFactory.create(
                program_course_code=program_course_code,
                course_key='course-v1:org+course+run-{}'.format(n))

        # PATCH the course code's run modes: send one matching an existing record and a second new one
        patch_data = {
            u'course_codes': [
                {
                    u'key':
                    course_code.key,
                    u'organization': {
                        u'key': course_code.organization.key,
                    },
                    u'run_modes': [
                        {
                            u'course_key': u'course-v1:org+course+run-0',
                            u'mode_slug': u'verified',
                        },
                        {
                            u'course_key': u'course-v1:org+course+run-2',
                            u'mode_slug': u'verified',
                            u'start_date': u'2015-12-09T21:20:26.491639Z',
                        },
                    ],
                },
            ],
        }
        response = self._make_request(program_id=program.id,
                                      admin=True,
                                      method='patch',
                                      data=patch_data)
        self.assertEqual(response.status_code, 200)

        # check response data
        patched_run_modes = response.data['course_codes'][0]['run_modes']
        self.assertEqual(
            [u'course-v1:org+course+run-0', u'course-v1:org+course+run-2'],
            sorted([rm[u'course_key'] for rm in patched_run_modes]))

        # check models (ensure things were saved properly)
        db_run_modes = ProgramCourseRunMode.objects.filter(
            program_course_code=program_course_code)
        self.assertEqual(
            [u'course-v1:org+course+run-0', u'course-v1:org+course+run-2'],
            sorted([rm.course_key for rm in db_run_modes]))
示例#11
0
 def test_patch_non_admin(self):
     """
     Verify that the API only allows admins to issue PATCH requests.
     """
     # Only allow admin to update program
     program = ProgramFactory.create()
     data = json.dumps({"name": "dummy-name"})
     response = self._make_request(method="patch", program_id=program.id, data=data)
     self.assertEqual(response.status_code, 403)
示例#12
0
 def test_create_duplicated_name(self):
     """
     Ensure that it is not allowed to create a Program with a duplicate name
     """
     ProgramFactory(name="duplicated name")  # saved directly to db
     data = self._build_post_data(name="duplicated name")
     response = self._make_request(method='post', data=data, admin=True)
     self.assertEqual(response.status_code, 400)
     self.assertIn("must be unique", response.data["name"][0])
示例#13
0
    def test_update_run_modes(self):
        """
        Ensure that nested run modes can be updated.
        """
        org = OrganizationFactory.create()
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        course_code = CourseCodeFactory.create(organization=org)
        program_course_code = ProgramCourseCodeFactory.create(program=program, course_code=course_code)

        for n in range(2):
            ProgramCourseRunModeFactory.create(
                program_course_code=program_course_code,
                course_key='course-v1:org+course+run-{}'.format(n)
            )

        # PATCH the course code's run modes: send one matching an existing record and a second new one
        patch_data = {
            'course_codes': [
                {
                    'key': course_code.key,
                    'organization': {
                        'key': course_code.organization.key,
                    },
                    'run_modes': [
                        {
                            'course_key': 'course-v1:org+course+run-0',
                            'mode_slug': 'verified',
                        },
                        {
                            'course_key': 'course-v1:org+course+run-2',
                            'mode_slug': 'verified',
                            'start_date': '2015-12-09T21:20:26.491639Z',
                        },
                    ],
                },
            ],
        }
        response = self._make_request(program_id=program.id, admin=True, method='patch', data=patch_data)
        self.assertEqual(response.status_code, 200)

        # check response data
        patched_run_modes = response.data['course_codes'][0]['run_modes']
        self.assertEqual(
            ['course-v1:org+course+run-0', 'course-v1:org+course+run-2'],
            sorted([rm['course_key'] for rm in patched_run_modes])
        )

        # check models (ensure things were saved properly)
        db_run_modes = ProgramCourseRunMode.objects.filter(program_course_code=program_course_code)
        self.assertEqual(
            ['course-v1:org+course+run-0', 'course-v1:org+course+run-2'],
            sorted([rm.course_key for rm in db_run_modes])
        )
示例#14
0
 def test_patch_non_admin(self):
     """
     Verify that the API only allows admins to issue PATCH requests.
     """
     # Only allow admin to update program
     program = ProgramFactory.create()
     data = json.dumps({"name": "dummy-name"})
     response = self._make_request(method="patch",
                                   program_id=program.id,
                                   data=data)
     self.assertEqual(response.status_code, 403)
示例#15
0
    def test_patch(self, patch_data):
        """
        Verify that the API is able to apply PATCH requests.
        """
        program = ProgramFactory.create()
        response = self._make_request(method="patch", program_id=program.id, data=patch_data, admin=True)

        self.assertEqual(response.status_code, 200)

        program = Program.objects.get(id=program.id)
        for field, value in patch_data.viewitems():
            self.assertEqual(getattr(program, field), value)
示例#16
0
    def test_update_course_codes(self):
        """
        Ensure that nested program course codes can be updated.
        """
        org = OrganizationFactory.create(key='test-org-key')
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        for n in range(3):
            course_code = CourseCodeFactory.create(
                key='test-course-key-{}'.format(n),
                display_name='test-course-display_name-{}'.format(n),
                organization=org,
            )
            # associate the first and second course codes, not the third.
            if n < 2:
                ProgramCourseCodeFactory.create(program=program,
                                                course_code=course_code)

        # PATCH the course codes: send one already associated, and another not yet associated
        patch_data = {
            u'course_codes': [
                {
                    u'key': 'test-course-key-0',
                    u'organization': {
                        u'key': 'test-org-key',
                    },
                },
                {
                    u'key': 'test-course-key-2',
                    u'organization': {
                        u'key': 'test-org-key',
                    },
                },
            ],
        }
        response = self._make_request(program_id=program.id,
                                      admin=True,
                                      method='patch',
                                      data=patch_data)
        self.assertEqual(response.status_code, 200)

        # check response data
        patched_course_codes = response.data['course_codes']
        self.assertEqual([u'test-course-key-0', u'test-course-key-2'],
                         sorted([cc[u'key'] for cc in patched_course_codes]))

        # check models (ensure things were saved properly)
        db_course_codes = ProgramCourseCode.objects.filter(
            program__id=program.id)
        self.assertEqual([u'test-course-key-0', u'test-course-key-2'],
                         sorted(
                             [pcc.course_code.key for pcc in db_course_codes]))
示例#17
0
    def test_invalid_nested_course_codes(self, invalid_code):
        """
        Ensure that invalid nested course code data causes a 400 response.
        """
        org = OrganizationFactory.create(key='test-org-key')
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        CourseCodeFactory.create(key='test-course-key', organization=org)

        patch_data = {
            'course_codes': [invalid_code],
        }
        response = self._make_request(program_id=program.id, admin=True, method='patch', data=patch_data)
        self.assertEqual(response.status_code, 400)
示例#18
0
    def test_update_course_codes(self):
        """
        Ensure that nested program course codes can be updated.
        """
        org = OrganizationFactory.create(key='test-org-key')
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        for n in range(3):
            course_code = CourseCodeFactory.create(
                key='test-course-key-{}'.format(n),
                display_name='test-course-display_name-{}'.format(n),
                organization=org,
            )
            # associate the first and second course codes, not the third.
            if n < 2:
                ProgramCourseCodeFactory.create(program=program, course_code=course_code)

        # PATCH the course codes: send one already associated, and another not yet associated
        patch_data = {
            'course_codes': [
                {
                    'key': 'test-course-key-0',
                    'organization': {
                        'key': 'test-org-key',
                    },
                },
                {
                    'key': 'test-course-key-2',
                    'organization': {
                        'key': 'test-org-key',
                    },
                },
            ],
        }
        response = self._make_request(program_id=program.id, admin=True, method='patch', data=patch_data)
        self.assertEqual(response.status_code, 200)

        # check response data
        patched_course_codes = response.data['course_codes']
        self.assertEqual(
            ['test-course-key-0', 'test-course-key-2'],
            sorted([cc['key'] for cc in patched_course_codes])
        )

        # check models (ensure things were saved properly)
        db_course_codes = ProgramCourseCode.objects.filter(program__id=program.id)
        self.assertEqual(
            ['test-course-key-0', 'test-course-key-2'],
            sorted([pcc.course_code.key for pcc in db_course_codes])
        )
示例#19
0
    def test_list_admin(self):
        """
        Verify the list includes all Programs, except those with DELETED status, for ADMINS.
        """
        # create one Program of each status
        for status in STATUSES:
            ProgramFactory(name="{} program".format(status), status=status)

        response = self._make_request(admin=True)
        self.assertEqual(response.status_code, 200)
        results = response.data['results']
        self.assertEqual(len(results), 3)
        self.assertNotIn(ProgramStatus.DELETED,
                         set(obj["status"] for obj in results))
示例#20
0
    def test_status_list_filter(self, query_status):
        """
        Verify that list results can be filtered by a 'status' query string argument.
        """
        # create one Program of each status
        for status in STATUSES:
            ProgramFactory(name="{} program".format(status), status=status)

        response = self._make_request(admin=True,
                                      data={'status': query_status})
        self.assertEqual(response.status_code, 200)
        results = response.data['results']
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0]['status'], query_status)
示例#21
0
    def test_patch(self, patch_data):
        """
        Verify that the API is able to apply PATCH requests.
        """
        program = ProgramFactory.create()
        response = self._make_request(method="patch",
                                      program_id=program.id,
                                      data=patch_data,
                                      admin=True)

        self.assertEqual(response.status_code, 200)

        program = Program.objects.get(id=program.id)
        for field, value in patch_data.viewitems():
            self.assertEqual(getattr(program, field), value)
示例#22
0
    def test_list_learner(self):
        """
        Verify the list includes only UNPUBLISHED and RETIRED Programs, for LEARNERS.
        """
        # create one Program of each status
        for status in STATUSES:
            ProgramFactory(name="{} program".format(status), status=status)

        response = self._make_request()
        self.assertEqual(response.status_code, 200)
        results = response.data['results']
        self.assertEqual(len(results), 2)
        statuses = set(obj["status"] for obj in results)
        self.assertNotIn(ProgramStatus.DELETED, statuses)
        self.assertNotIn(ProgramStatus.UNPUBLISHED, statuses)
示例#23
0
    def test_org_list_filter(self):
        """
        Verify that list results can be filtered by an 'organization' query string argument.
        """
        org_keys = ("org1", "org2")
        for org_key in org_keys:
            org = OrganizationFactory.create(key=org_key)
            program = ProgramFactory.create()
            ProgramOrganizationFactory.create(organization=org, program=program)

        for org_key in org_keys:
            response = self._make_request(admin=True, data={'organization': org_key})
            self.assertEqual(response.status_code, 200)
            results = response.data['results']
            self.assertEqual(len(results), 1)
            self.assertEqual(results[0]['organizations'][0]['key'], org_key)
示例#24
0
    def assert_correct_banner_image_urls(self, url_prepend=''):
        """
        DRY test helper.  Ensure that the serializer generates a complete set
        of absolute URLs for the banner_image when one is set.
        """
        program = ProgramFactory.create(status=ProgramStatus.ACTIVE)
        program.banner_image = make_banner_image_file('test_filename.jpg')
        program.save()

        response = self._make_request(program_id=program.id)
        self.assertEqual(response.status_code, 200)

        expected_urls = {
            'w{}h{}'.format(*size): '{}{}__{}x{}.jpg'.format(url_prepend, program.banner_image.url, *size)
            for size in program.banner_image.field.sizes
        }
        self.assertEqual(response.data['banner_image_urls'], expected_urls)
示例#25
0
    def test_invalid_nested_course_codes(self, invalid_code):
        """
        Ensure that invalid nested course code data causes a 400 response.
        """
        org = OrganizationFactory.create(key='test-org-key')
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        CourseCodeFactory.create(key='test-course-key', organization=org)

        patch_data = {
            u'course_codes': [invalid_code],
        }
        response = self._make_request(program_id=program.id,
                                      admin=True,
                                      method='patch',
                                      data=patch_data)
        self.assertEqual(response.status_code, 400)
示例#26
0
    def test_org_list_filter(self):
        """
        Verify that list results can be filtered by an 'organization' query string argument.
        """
        org_keys = ("org1", "org2")
        for org_key in org_keys:
            org = OrganizationFactory.create(key=org_key)
            program = ProgramFactory.create()
            ProgramOrganizationFactory.create(organization=org,
                                              program=program)

        for org_key in org_keys:
            response = self._make_request(admin=True,
                                          data={'organization': org_key})
            self.assertEqual(response.status_code, 200)
            results = response.data['results']
            self.assertEqual(len(results), 1)
            self.assertEqual(results[0]['organizations'][0]['key'], org_key)
示例#27
0
    def assert_correct_banner_image_urls(self, url_prepend=''):
        """
        DRY test helper.  Ensure that the serializer generates a complete set
        of absolute URLs for the banner_image when one is set.
        """
        program = ProgramFactory.create(status=ProgramStatus.ACTIVE)
        program.banner_image = make_banner_image_file('test_filename.jpg')
        program.save()

        response = self._make_request(program_id=program.id)
        self.assertEqual(response.status_code, 200)

        expected_urls = {
            'w{}h{}'.format(*size):
            '{}{}__{}x{}.jpg'.format(url_prepend, program.banner_image.url,
                                     *size)
            for size in program.banner_image.field.sizes
        }
        self.assertEqual(response.data[u'banner_image_urls'], expected_urls)
示例#28
0
    def test_create_course_codes(self):
        """
        Ensure that course codes can be created on the fly from request data
        when referenced as part of nested program updates.
        """
        org = OrganizationFactory.create(key='test-org-key')
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)

        patch_data = {
            'course_codes': [
                {
                    'key': 'test-course-code-key',
                    'display_name': 'test-course-code-name',
                    'organization': {
                        'key': 'test-org-key',
                    },
                },
            ],
        }
        response = self._make_request(program_id=program.id,
                                      admin=True,
                                      method='patch',
                                      data=patch_data)
        self.assertEqual(response.status_code, 200)

        # check response data
        response_course_code = response.data['course_codes'][0]
        self.assertEqual(response_course_code['key'], 'test-course-code-key')
        self.assertEqual(response_course_code['display_name'],
                         'test-course-code-name')
        self.assertEqual(response_course_code['organization']['key'],
                         'test-org-key')

        # check models (ensure things were saved properly)
        db_course_code = CourseCode.objects.get(
            key='test-course-code-key',
            display_name='test-course-code-name',
            organization__key='test-org-key',
        )
        self.assertEqual(db_course_code.programs.count(), 1)
        self.assertEqual(db_course_code.programs.first(), program)
示例#29
0
    def test_update_course_code_display_name(self):
        """
        Ensure that course codes' display names can be updated on the fly from
        request data when referenced as part of nested program updates.
        """
        org = OrganizationFactory.create(key='test-org-key')
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        CourseCodeFactory.create(
            key='test-course-code-key',
            display_name='original-display-name',
            organization=org,
        )

        patch_data = {
            u'course_codes': [
                {
                    u'key': 'test-course-code-key',
                    u'display_name': 'changed-display-name',
                    u'organization': {
                        u'key': 'test-org-key',
                    },
                },
            ],
        }
        response = self._make_request(program_id=program.id,
                                      admin=True,
                                      method='patch',
                                      data=patch_data)
        self.assertEqual(response.status_code, 200)

        # check response data
        response_course_code = response.data['course_codes'][0]
        self.assertEqual(response_course_code['display_name'],
                         'changed-display-name')

        # check models (ensure things were saved properly)
        CourseCode.objects.get(
            key='test-course-code-key',
            display_name='changed-display-name',
            organization__key='test-org-key',
        )
示例#30
0
    def test_invalid_nested_run_modes(self, invalid_mode):
        """
        Ensure that invalid nested run mode data causes a 400 response.
        """
        org = OrganizationFactory.create()
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        course_code = CourseCodeFactory.create(organization=org)

        patch_data = {
            'course_codes': [
                {
                    'key': course_code.key,
                    'organization': {
                        'key': course_code.organization.key,
                    },
                    'run_modes': [invalid_mode],
                },
            ],
        }
        response = self._make_request(program_id=program.id, admin=True, method='patch', data=patch_data)
        self.assertEqual(response.status_code, 400)
示例#31
0
    def test_program_completion_filtering(self, status, is_admin):
        """Verify that program candidates for completion are filtered."""
        program = ProgramFactory.create(status=status)
        org = OrganizationFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)

        course_code = CourseCodeFactory.create(organization=org)
        program_course_code = ProgramCourseCodeFactory.create(
            program=program, course_code=course_code)

        course_key = 'org/code/run'
        ProgramCourseRunModeFactory.create(
            course_key=course_key,
            program_course_code=program_course_code,
        )

        complete_run_modes = {
            'completed_courses': [
                {
                    'course_id': course_key,
                    'mode': 'verified'
                },
            ]
        }

        response = self._make_request(method='post',
                                      complete=True,
                                      data=complete_run_modes,
                                      admin=is_admin)

        self.assertEqual(response.status_code, 200)

        program_ids = response.data['program_ids']
        if status in [ProgramStatus.ACTIVE, ProgramStatus.RETIRED]:
            self.assertEqual(program_ids, [1])
        else:
            # No one should be able to complete deleted or unpublished programs.
            self.assertEqual(program_ids, [])
示例#32
0
    def test_update_course_code_display_name(self):
        """
        Ensure that course codes' display names can be updated on the fly from
        request data when referenced as part of nested program updates.
        """
        org = OrganizationFactory.create(key='test-org-key')
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        CourseCodeFactory.create(
            key='test-course-code-key',
            display_name='original-display-name',
            organization=org,
        )

        patch_data = {
            'course_codes': [
                {
                    'key': 'test-course-code-key',
                    'display_name': 'changed-display-name',
                    'organization': {
                        'key': 'test-org-key',
                    },
                },
            ],
        }
        response = self._make_request(program_id=program.id, admin=True, method='patch', data=patch_data)
        self.assertEqual(response.status_code, 200)

        # check response data
        response_course_code = response.data['course_codes'][0]
        self.assertEqual(response_course_code['display_name'], 'changed-display-name')

        # check models (ensure things were saved properly)
        CourseCode.objects.get(
            key='test-course-code-key',
            display_name='changed-display-name',
            organization__key='test-org-key',
        )
示例#33
0
    def test_create_course_codes(self):
        """
        Ensure that course codes can be created on the fly from request data
        when referenced as part of nested program updates.
        """
        org = OrganizationFactory.create(key='test-org-key')
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)

        patch_data = {
            u'course_codes': [
                {
                    u'key': 'test-course-code-key',
                    u'display_name': 'test-course-code-name',
                    u'organization': {
                        u'key': 'test-org-key',
                    },
                },
            ],
        }
        response = self._make_request(program_id=program.id, admin=True, method='patch', data=patch_data)
        self.assertEqual(response.status_code, 200)

        # check response data
        response_course_code = response.data['course_codes'][0]
        self.assertEqual(response_course_code['key'], 'test-course-code-key')
        self.assertEqual(response_course_code['display_name'], 'test-course-code-name')
        self.assertEqual(response_course_code['organization']['key'], 'test-org-key')

        # check models (ensure things were saved properly)
        db_course_code = CourseCode.objects.get(
            key='test-course-code-key',
            display_name='test-course-code-name',
            organization__key='test-org-key',
        )
        self.assertEqual(db_course_code.programs.count(), 1)
        self.assertEqual(db_course_code.programs.first(), program)
示例#34
0
 def test_view_admin(self, status):
     """
     Test that the detail view works correctly for ADMINS, and that deleted
     Programs are filtered out.
     """
     program = ProgramFactory.create(status=status)
     response = self._make_request(program_id=program.id, admin=True)
     self.assertEqual(response.status_code,
                      404 if status == ProgramStatus.DELETED else 200)
     if status != ProgramStatus.DELETED:
         self.assertEqual(
             response.data, {
                 u"name": program.name,
                 u"subtitle": program.subtitle,
                 u"category": program.category,
                 u"status": status,
                 u"organizations": [],
                 u"course_codes": [],
                 u"id": program.id,
                 u"created": program.created.strftime(DRF_DATE_FORMAT),
                 u"modified": program.modified.strftime(DRF_DATE_FORMAT),
                 u'marketing_slug': program.marketing_slug,
                 u'banner_image_urls': {}
             })
示例#35
0
    def test_view_with_nested(self):
        """
        Ensure that nested serializers are working in program detail views.
        """
        start_date = datetime.datetime.now(tz=pytz.UTC)
        course_key = "edX/DemoX/Demo_Course"
        run_key = "Demo_Course"

        org = OrganizationFactory.create(key="test-org-key", display_name="test-org-display_name")
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        course_code = CourseCodeFactory.create(
            key="test-course-key",
            display_name="test-course-display_name",
            organization=org,
        )

        program_course_code = ProgramCourseCodeFactory.create(program=program, course_code=course_code)

        ProgramCourseRunModeFactory.create(
            course_key=course_key,
            program_course_code=program_course_code,
            start_date=start_date
        )

        response = self._make_request(program_id=program.id, admin=True)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(
            response.data,
            {
                'name': program.name,
                'subtitle': program.subtitle,
                'category': program.category,
                'status': ProgramStatus.UNPUBLISHED,
                'organizations': [
                    {
                        'key': 'test-org-key',
                        'display_name': 'test-org-display_name',
                    }
                ],
                'course_codes': [
                    {
                        'key': 'test-course-key',
                        'display_name': 'test-course-display_name',
                        'organization': {
                            'key': 'test-org-key',
                            'display_name': 'test-org-display_name',
                        },
                        'run_modes': [
                            {
                                'course_key': course_key,
                                'run_key': run_key,
                                'mode_slug': 'verified',
                                'sku': '',
                                'start_date': start_date.strftime(DRF_DATE_FORMAT)
                            }
                        ],
                    }
                ],
                'id': program.id,
                'created': program.created.strftime(DRF_DATE_FORMAT),
                'modified': program.modified.strftime(DRF_DATE_FORMAT),
                'marketing_slug': program.marketing_slug,
                'banner_image_urls': {},
                'uuid': unicode(program.uuid),
            }
        )
示例#36
0
 def _build_post_data(**kwargs):
     """
     Build and return a dict representation to use for POST / create.
     """
     instance = ProgramFactory.build(**kwargs)
     return {k: getattr(instance, k) for k in POST_FIELDS}
示例#37
0
    def test_create_course_code_with_run_modes(self):
        """
        Ensure that nested program course codes and run modes can be correctly
        created during updates.
        """
        org = OrganizationFactory.create()
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)

        course_codes = [
            CourseCodeFactory.create(organization=org,
                                     key='test-cc-{}'.format(i))
            for i in range(2)
        ]

        # associate two course codes with two run modes each, in one PATCH request.
        patch_data = {
            u'course_codes': [
                {
                    u'key':
                    course_codes[0].key,
                    u'organization': {
                        u'key': course_codes[0].organization.key,
                    },
                    u'run_modes': [
                        {
                            u'course_key':
                            u'course-v1:org+{}+run-0'.format(
                                course_codes[0].key),
                            u'mode_slug':
                            u'verified',
                            u'start_date':
                            u'2015-12-09T21:20:26.491639Z',
                        },
                        {
                            u'course_key':
                            u'course-v1:org+{}+run-1'.format(
                                course_codes[0].key),
                            u'mode_slug':
                            u'verified',
                            u'start_date':
                            u'2015-12-09T21:20:26.491639Z',
                        },
                    ],
                },
                {
                    u'key':
                    course_codes[1].key,
                    u'organization': {
                        u'key': course_codes[1].organization.key,
                    },
                    u'run_modes': [
                        {
                            u'course_key':
                            u'course-v1:org+{}+run-0'.format(
                                course_codes[1].key),
                            u'mode_slug':
                            u'verified',
                            u'start_date':
                            u'2015-12-09T21:20:26.491639Z',
                        },
                        {
                            u'course_key':
                            u'course-v1:org+{}+run-1'.format(
                                course_codes[1].key),
                            u'mode_slug':
                            u'verified',
                            u'start_date':
                            u'2015-12-09T21:20:26.491639Z',
                        },
                    ],
                },
            ],
        }
        response = self._make_request(program_id=program.id,
                                      admin=True,
                                      method='patch',
                                      data=patch_data)
        self.assertEqual(response.status_code, 200)

        # check response data
        response_course_codes = response.data['course_codes']
        response_course_codes = sorted(response_course_codes,
                                       key=lambda d: d['key'])
        for course_code, response_course_code in zip(course_codes,
                                                     response_course_codes):
            self.assertEqual(response_course_code['key'], course_code.key)
            self.assertEqual(response_course_code['organization']['key'],
                             course_code.organization.key)
            self.assertEqual(len(response_course_code['run_modes']), 2)

            # check db values. the following call should throw DoesNotExist if things didn't go as expected
            db_program_course_code = ProgramCourseCode.objects.get(
                program=program, course_code=course_code)
            run_modes = sorted(db_program_course_code.run_modes.all(),
                               key=lambda o: o.course_key)
            for i, run_mode in enumerate(run_modes):
                self.assertEqual(
                    'course-v1:org+{}+run-{}'.format(course_code.key, i),
                    run_mode.course_key)
示例#38
0
    def test_create_course_code_with_run_modes(self):
        """
        Ensure that nested program course codes and run modes can be correctly
        created during updates.
        """
        org = OrganizationFactory.create()
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)

        course_codes = [CourseCodeFactory.create(organization=org, key='test-cc-{}'.format(i)) for i in range(2)]

        # associate two course codes with two run modes each, in one PATCH request.
        patch_data = {
            'course_codes': [
                {
                    'key': course_codes[0].key,
                    'organization': {
                        'key': course_codes[0].organization.key,
                    },
                    'run_modes': [
                        {
                            'course_key': 'course-v1:org+{}+run-0'.format(course_codes[0].key),
                            'mode_slug': 'verified',
                            'start_date': '2015-12-09T21:20:26.491639Z',
                        },
                        {
                            'course_key': 'course-v1:org+{}+run-1'.format(course_codes[0].key),
                            'mode_slug': 'verified',
                            'start_date': '2015-12-09T21:20:26.491639Z',
                        },
                    ],
                },
                {
                    'key': course_codes[1].key,
                    'organization': {
                        'key': course_codes[1].organization.key,
                    },
                    'run_modes': [
                        {
                            'course_key': 'course-v1:org+{}+run-0'.format(course_codes[1].key),
                            'mode_slug': 'verified',
                            'start_date': '2015-12-09T21:20:26.491639Z',
                        },
                        {
                            'course_key': 'course-v1:org+{}+run-1'.format(course_codes[1].key),
                            'mode_slug': 'verified',
                            'start_date': '2015-12-09T21:20:26.491639Z',
                        },
                    ],
                },
            ],
        }
        response = self._make_request(program_id=program.id, admin=True, method='patch', data=patch_data)
        self.assertEqual(response.status_code, 200)

        # check response data
        response_course_codes = response.data['course_codes']
        response_course_codes = sorted(response_course_codes, key=lambda d: d['key'])
        for course_code, response_course_code in zip(course_codes, response_course_codes):
            self.assertEqual(response_course_code['key'], course_code.key)
            self.assertEqual(response_course_code['organization']['key'], course_code.organization.key)
            self.assertEqual(len(response_course_code['run_modes']), 2)

            # check db values. the following call should throw DoesNotExist if things didn't go as expected
            db_program_course_code = ProgramCourseCode.objects.get(program=program, course_code=course_code)
            run_modes = sorted(db_program_course_code.run_modes.all(), key=lambda o: o.course_key)
            for i, run_mode in enumerate(run_modes):
                self.assertEqual('course-v1:org+{}+run-{}'.format(course_code.key, i), run_mode.course_key)
示例#39
0
    def test_view_with_nested(self):
        """
        Ensure that nested serializers are working in program detail views.
        """
        start_date = datetime.datetime.now(tz=pytz.UTC)
        course_key = "edX/DemoX/Demo_Course"
        run_key = "Demo_Course"

        org = OrganizationFactory.create(key="test-org-key",
                                         display_name="test-org-display_name")
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        course_code = CourseCodeFactory.create(
            key="test-course-key",
            display_name="test-course-display_name",
            organization=org,
        )

        program_course_code = ProgramCourseCodeFactory.create(
            program=program, course_code=course_code)

        ProgramCourseRunModeFactory.create(
            course_key=course_key,
            program_course_code=program_course_code,
            start_date=start_date)

        response = self._make_request(program_id=program.id, admin=True)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(
            response.data, {
                u"name":
                program.name,
                u"subtitle":
                program.subtitle,
                u"category":
                program.category,
                u"status":
                ProgramStatus.UNPUBLISHED,
                u"organizations": [{
                    u"key": "test-org-key",
                    u"display_name": "test-org-display_name",
                }],
                u"course_codes": [{
                    u"key":
                    "test-course-key",
                    u"display_name":
                    "test-course-display_name",
                    u"organization": {
                        u"key": "test-org-key",
                        u"display_name": "test-org-display_name",
                    },
                    u"run_modes":
                    [{
                        u"course_key": course_key,
                        u"run_key": run_key,
                        u"mode_slug": "verified",
                        u"sku": '',
                        u"start_date": start_date.strftime(DRF_DATE_FORMAT)
                    }],
                }],
                u"id":
                program.id,
                u"created":
                program.created.strftime(DRF_DATE_FORMAT),
                u"modified":
                program.modified.strftime(DRF_DATE_FORMAT),
                u'marketing_slug':
                program.marketing_slug,
                u'banner_image_urls': {}
            })
示例#40
0
 def _build_post_data(**kwargs):
     """
     Build and return a dict representation to use for POST / create.
     """
     instance = ProgramFactory.build(**kwargs)
     return {k: getattr(instance, k) for k in POST_FIELDS}
示例#41
0
    def test_view_with_nested(self):
        """
        Ensure that nested serializers are working in program detail views.
        """
        start_date = datetime.datetime.now(tz=pytz.UTC)
        course_key = "edX/DemoX/Demo_Course"
        run_key = "Demo_Course"

        org = OrganizationFactory.create(key="test-org-key",
                                         display_name="test-org-display_name")
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        course_code = CourseCodeFactory.create(
            key="test-course-key",
            display_name="test-course-display_name",
            organization=org,
        )

        program_course_code = ProgramCourseCodeFactory.create(
            program=program, course_code=course_code)

        ProgramCourseRunModeFactory.create(
            course_key=course_key,
            program_course_code=program_course_code,
            start_date=start_date)

        response = self._make_request(program_id=program.id, admin=True)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(
            response.data, {
                'name':
                program.name,
                'subtitle':
                program.subtitle,
                'category':
                program.category,
                'status':
                ProgramStatus.UNPUBLISHED,
                'organizations': [{
                    'key': 'test-org-key',
                    'display_name': 'test-org-display_name',
                }],
                'course_codes': [{
                    'key':
                    'test-course-key',
                    'display_name':
                    'test-course-display_name',
                    'organization': {
                        'key': 'test-org-key',
                        'display_name': 'test-org-display_name',
                    },
                    'run_modes':
                    [{
                        'course_key': course_key,
                        'run_key': run_key,
                        'mode_slug': 'verified',
                        'sku': '',
                        'start_date': start_date.strftime(DRF_DATE_FORMAT)
                    }],
                }],
                'id':
                program.id,
                'created':
                program.created.strftime(DRF_DATE_FORMAT),
                'modified':
                program.modified.strftime(DRF_DATE_FORMAT),
                'marketing_slug':
                program.marketing_slug,
                'banner_image_urls': {},
                'uuid':
                unicode(program.uuid),
            })
示例#42
0
    def test_view_with_nested(self):
        """
        Ensure that nested serializers are working in program detail views.
        """
        start_date = datetime.datetime.now(tz=pytz.UTC)
        course_key = "edX/DemoX/Demo_Course"
        run_key = "Demo_Course"

        org = OrganizationFactory.create(key="test-org-key", display_name="test-org-display_name")
        program = ProgramFactory.create()
        ProgramOrganizationFactory.create(program=program, organization=org)
        course_code = CourseCodeFactory.create(
            key="test-course-key",
            display_name="test-course-display_name",
            organization=org,
        )

        program_course_code = ProgramCourseCodeFactory.create(program=program, course_code=course_code)

        ProgramCourseRunModeFactory.create(
            course_key=course_key,
            program_course_code=program_course_code,
            start_date=start_date
        )

        response = self._make_request(program_id=program.id, admin=True)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(
            response.data,
            {
                u"name": program.name,
                u"subtitle": program.subtitle,
                u"category": program.category,
                u"status": ProgramStatus.UNPUBLISHED,
                u"organizations": [
                    {
                        u"key": "test-org-key",
                        u"display_name": "test-org-display_name",
                    }
                ],
                u"course_codes": [
                    {
                        u"key": "test-course-key",
                        u"display_name": "test-course-display_name",
                        u"organization": {
                            u"key": "test-org-key",
                            u"display_name": "test-org-display_name",
                        },
                        u"run_modes": [
                            {
                                u"course_key": course_key,
                                u"run_key": run_key,
                                u"mode_slug": "verified",
                                u"sku": '',
                                u"start_date": start_date.strftime(DRF_DATE_FORMAT)
                            }
                        ],
                    }
                ],
                u"id": program.id,
                u"created": program.created.strftime(DRF_DATE_FORMAT),
                u"modified": program.modified.strftime(DRF_DATE_FORMAT),
                u'marketing_slug': program.marketing_slug,
                u'banner_image_urls': {}
            }
        )