Esempio n. 1
0
    def test_basic(self):
        upload_date = datetime(2013, 6, 1, 10, 30, tzinfo=UTC)

        course_key = SlashSeparatedCourseKey('org', 'class', 'run')
        location = course_key.make_asset_key('asset', 'my_file_name.jpg')
        thumbnail_location = course_key.make_asset_key(
            'thumbnail', 'my_file_name_thumb.jpg')

        # pylint: disable=protected-access
        output = assets._get_asset_json("my_file", upload_date, location,
                                        thumbnail_location, True)

        self.assertEquals(output["display_name"], "my_file")
        self.assertEquals(output["date_added"], "Jun 01, 2013 at 10:30 UTC")
        self.assertEquals(output["url"],
                          "/c4x/org/class/asset/my_file_name.jpg")
        self.assertEquals(output["external_url"],
                          "lms_base_url/c4x/org/class/asset/my_file_name.jpg")
        self.assertEquals(output["portable_url"], "/static/my_file_name.jpg")
        self.assertEquals(output["thumbnail"],
                          "/c4x/org/class/thumbnail/my_file_name_thumb.jpg")
        self.assertEquals(output["id"], unicode(location))
        self.assertEquals(output['locked'], True)

        output = assets._get_asset_json("name", upload_date, location, None,
                                        False)
        self.assertIsNone(output["thumbnail"])
Esempio n. 2
0
    def test_basic(self):
        upload_date = datetime(2013, 6, 1, 10, 30, tzinfo=UTC)

        course_key = SlashSeparatedCourseKey('org', 'class', 'run')
        location = course_key.make_asset_key('asset', 'my_file_name.jpg')
        thumbnail_location = course_key.make_asset_key('thumbnail', 'my_file_name_thumb.jpg')

        output = assets._get_asset_json("my_file", upload_date, location, thumbnail_location, True)

        self.assertEquals(output["display_name"], "my_file")
        self.assertEquals(output["date_added"], "Jun 01, 2013 at 10:30 UTC")
        self.assertEquals(output["url"], "/c4x/org/class/asset/my_file_name.jpg")
        self.assertEquals(output["external_url"], "lms_base_url/c4x/org/class/asset/my_file_name.jpg")
        self.assertEquals(output["portable_url"], "/static/my_file_name.jpg")
        self.assertEquals(output["thumbnail"], "/c4x/org/class/thumbnail/my_file_name_thumb.jpg")
        self.assertEquals(output["id"], unicode(location))
        self.assertEquals(output['locked'], True)

        output = assets._get_asset_json("name", upload_date, location, None, False)
        self.assertIsNone(output["thumbnail"])
    def test_basic(self):
        upload_date = datetime(2013, 6, 1, 10, 30, tzinfo=UTC)
        content_type = "image/jpg"
        course_key = SlashSeparatedCourseKey("org", "class", "run")
        location = course_key.make_asset_key("asset", "my_file_name.jpg")
        thumbnail_location = course_key.make_asset_key("thumbnail", "my_file_name_thumb.jpg")

        # pylint: disable=protected-access
        output = assets._get_asset_json("my_file", content_type, upload_date, location, thumbnail_location, True)

        self.assertEquals(output["display_name"], "my_file")
        self.assertEquals(output["date_added"], "Jun 01, 2013 at 10:30 UTC")
        self.assertEquals(output["url"], "/c4x/org/class/asset/my_file_name.jpg")
        self.assertEquals(output["external_url"], "lms_base_url/c4x/org/class/asset/my_file_name.jpg")
        self.assertEquals(output["portable_url"], "/static/my_file_name.jpg")
        self.assertEquals(output["thumbnail"], "/c4x/org/class/thumbnail/my_file_name_thumb.jpg")
        self.assertEquals(output["id"], unicode(location))
        self.assertEquals(output["locked"], True)

        output = assets._get_asset_json("name", content_type, upload_date, location, None, False)
        self.assertIsNone(output["thumbnail"])
Esempio n. 4
0
    def test_export_course_image(self, _from_json):
        """
        Test to make sure that we have a course image in the contentstore,
        then export it to ensure it gets copied to both file locations.
        """
        course_key = SlashSeparatedCourseKey('edX', 'simple', '2012_Fall')
        location = course_key.make_asset_key('asset', 'images_course_image.jpg')

        # This will raise if the course image is missing
        self.content_store.find(location)

        root_dir = path(mkdtemp())
        self.addCleanup(shutil.rmtree, root_dir)
        export_course_to_xml(self.draft_store, self.content_store, course_key, root_dir, 'test_export')
        self.assertTrue(path(root_dir / 'test_export/static/images/course_image.jpg').isfile())
        self.assertTrue(path(root_dir / 'test_export/static/images_course_image.jpg').isfile())
Esempio n. 5
0
    def test_export_course_image(self, _from_json):
        """
        Test to make sure that we have a course image in the contentstore,
        then export it to ensure it gets copied to both file locations.
        """
        course_key = SlashSeparatedCourseKey('edX', 'simple', '2012_Fall')
        location = course_key.make_asset_key('asset', 'images_course_image.jpg')

        # This will raise if the course image is missing
        self.content_store.find(location)

        root_dir = path(mkdtemp())
        self.addCleanup(shutil.rmtree, root_dir)
        export_course_to_xml(self.draft_store, self.content_store, course_key, root_dir, 'test_export')
        self.assertTrue(path(root_dir / 'test_export/static/images/course_image.jpg').isfile())
        self.assertTrue(path(root_dir / 'test_export/static/images_course_image.jpg').isfile())
    def test_copy_assets(self, deprecated):
        """
        copy_all_course_assets
        """
        self.set_up_assets(deprecated)
        dest_course = SlashSeparatedCourseKey('test', 'destination', 'copy')
        self.contentstore.copy_all_course_assets(self.course1_key, dest_course)
        for filename in self.course1_files:
            asset_key = self.course1_key.make_asset_key('asset', filename)
            dest_key = dest_course.make_asset_key('asset', filename)
            source = self.contentstore.find(asset_key)
            copied = self.contentstore.find(dest_key)
            for propname in ['name', 'content_type', 'length', 'locked']:
                self.assertEqual(getattr(source, propname), getattr(copied, propname))

        __, count = self.contentstore.get_all_content_for_course(dest_course)
        self.assertEqual(count, len(self.course1_files))
Esempio n. 7
0
    def test_copy_assets(self, deprecated):
        """
        copy_all_course_assets
        """
        self.set_up_assets(deprecated)
        dest_course = SlashSeparatedCourseKey('test', 'destination', 'copy')
        self.contentstore.copy_all_course_assets(self.course1_key, dest_course)
        for filename in self.course1_files:
            asset_key = self.course1_key.make_asset_key('asset', filename)
            dest_key = dest_course.make_asset_key('asset', filename)
            source = self.contentstore.find(asset_key)
            copied = self.contentstore.find(dest_key)
            for propname in ['name', 'content_type', 'length', 'locked']:
                self.assertEqual(getattr(source, propname),
                                 getattr(copied, propname))

        __, count = self.contentstore.get_all_content_for_course(dest_course)
        self.assertEqual(count, len(self.course1_files))
Esempio n. 8
0
    def test_export_course_image(self):
        """
        Test to make sure that we have a course image in the contentstore,
        then export it to ensure it gets copied to both file locations.
        """
        course_key = SlashSeparatedCourseKey("edX", "simple", "2012_Fall")
        location = course_key.make_asset_key("asset", "images_course_image.jpg")

        # This will raise if the course image is missing
        self.content_store.find(location)

        root_dir = path(mkdtemp())
        try:
            export_course_to_xml(self.draft_store, self.content_store, course_key, root_dir, "test_export")
            assert_true(path(root_dir / "test_export/static/images/course_image.jpg").isfile())
            assert_true(path(root_dir / "test_export/static/images_course_image.jpg").isfile())
        finally:
            shutil.rmtree(root_dir)
Esempio n. 9
0
    def test_static_url_generation(self):

        course_key = SlashSeparatedCourseKey('org', 'class', 'run')
        location = course_key.make_asset_key('asset', 'my_file_name.jpg')
        path = StaticContent.get_static_path_from_location(location)
        self.assertEquals(path, '/static/my_file_name.jpg')
Esempio n. 10
0
    def test_static_url_generation(self):

        course_key = SlashSeparatedCourseKey("org", "class", "run")
        location = course_key.make_asset_key("asset", "my_file_name.jpg")
        path = StaticContent.get_static_path_from_location(location)
        self.assertEquals(path, "/static/my_file_name.jpg")
Esempio n. 11
0
class ContentStoreToyCourseTest(ModuleStoreTestCase):
    """
    Tests that use the toy course.
    """

    def setUp(self):
        """
        Create user and login.
        """
        self.staff_pwd = super(ContentStoreToyCourseTest, self).setUp()
        self.staff_usr = self.user
        self.non_staff_usr, self.non_staff_pwd = self.create_non_staff_user()

        self.client = Client()
        self.contentstore = contentstore()

        self.course_key = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')

        import_from_xml(
            modulestore(), self.user.id, 'common/test/data/', ['toy'],
            static_content_store=self.contentstore, verbose=True
        )

        # A locked asset
        self.locked_asset = self.course_key.make_asset_key('asset', 'sample_static.txt')
        self.url_locked = self.locked_asset.to_deprecated_string()
        self.contentstore.set_attr(self.locked_asset, 'locked', True)

        # An unlocked asset
        self.unlocked_asset = self.course_key.make_asset_key('asset', 'another_static.txt')
        self.url_unlocked = self.unlocked_asset.to_deprecated_string()
        self.length_unlocked = self.contentstore.get_attr(self.unlocked_asset, 'length')

    def test_unlocked_asset(self):
        """
        Test that unlocked assets are being served.
        """
        self.client.logout()
        resp = self.client.get(self.url_unlocked)
        self.assertEqual(resp.status_code, 200)  # pylint: disable=E1103

    def test_locked_asset_not_logged_in(self):
        """
        Test that locked assets behave appropriately in case the user is not
        logged in.
        """
        self.client.logout()
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403)  # pylint: disable=E1103

    def test_locked_asset_not_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        in but not registered for the course.
        """
        self.client.login(username=self.non_staff_usr, password=self.non_staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403)  # pylint: disable=E1103

    def test_locked_asset_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        and registered for the course.
        """
        CourseEnrollment.enroll(self.non_staff_usr, self.course_key)
        self.assertTrue(CourseEnrollment.is_enrolled(self.non_staff_usr, self.course_key))

        self.client.login(username=self.non_staff_usr, password=self.non_staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200)  # pylint: disable=E1103

    def test_locked_asset_staff(self):
        """
        Test that locked assets behave appropriately in case user is staff.
        """
        self.client.login(username=self.staff_usr, password=self.staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200)  # pylint: disable=E1103

    def test_range_request_full_file(self):
        """
        Test that a range request from byte 0 to last,
        outputs partial content status code and valid Content-Range and Content-Length.
        """
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes=0-')

        self.assertEqual(resp.status_code, 206)  # HTTP_206_PARTIAL_CONTENT
        self.assertEqual(
            resp['Content-Range'],
            'bytes {first}-{last}/{length}'.format(
                first=0, last=self.length_unlocked - 1,
                length=self.length_unlocked
            )
        )
        self.assertEqual(resp['Content-Length'], str(self.length_unlocked))

    def test_range_request_partial_file(self):
        """
        Test that a range request for a partial file,
        outputs partial content status code and valid Content-Range and Content-Length.
        first_byte and last_byte are chosen to be simple but non trivial values.
        """
        first_byte = self.length_unlocked / 4
        last_byte = self.length_unlocked / 2
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes={first}-{last}'.format(
            first=first_byte, last=last_byte)
        )

        self.assertEqual(resp.status_code, 206)  # HTTP_206_PARTIAL_CONTENT
        self.assertEqual(resp['Content-Range'], 'bytes {first}-{last}/{length}'.format(
            first=first_byte, last=last_byte, length=self.length_unlocked))
        self.assertEqual(resp['Content-Length'], str(last_byte - first_byte + 1))

    def test_range_request_malformed_missing_equal(self):
        """
        Test that a range request with malformed Range (missing '=') outputs status 400.
        """
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes 0-')
        self.assertEqual(resp.status_code, 400)  # HTTP_400_BAD_REQUEST

    def test_range_request_malformed_not_bytes(self):
        """
        Test that a range request with malformed Range (not "bytes") outputs status 400.
        "Accept-Ranges: bytes" tells the user that only "bytes" ranges are allowed
        """
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bits=0-')
        self.assertEqual(resp.status_code, 400)  # HTTP_400_BAD_REQUEST

    def test_range_request_malformed_missing_minus(self):
        """
        Test that a range request with malformed Range (missing '-') outputs status 400.
        """
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes=0')
        self.assertEqual(resp.status_code, 400)  # HTTP_400_BAD_REQUEST

    def test_range_request_malformed_first_not_integer(self):
        """
        Test that a range request with malformed Range (first is not an integer) outputs status 400.
        """
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes=one-')
        self.assertEqual(resp.status_code, 400)  # HTTP_400_BAD_REQUEST

    def test_range_request_malformed_invalid_range(self):
        """
        Test that a range request with malformed Range (first_byte > last_byte) outputs status 400.
        """
        first_byte = self.length_unlocked / 2
        last_byte = self.length_unlocked / 4
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes={first}-{last}'.format(
            first=first_byte, last=last_byte)
        )

        self.assertEqual(resp.status_code, 400)  # HTTP_400_BAD_REQUEST

    def test_range_request_malformed_out_of_bounds(self):
        """
        Test that a range request with malformed Range (last_byte == totalLength, offset by 1 error)
        outputs status 400.
        """
        last_byte = self.length_unlocked
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes=0-{last}'.format(
            last=last_byte)
        )

        self.assertEqual(resp.status_code, 400)  # HTTP_400_BAD_REQUEST
Esempio n. 12
0
class ContentStoreToyCourseTest(ModuleStoreTestCase):
    """
    Tests that use the toy course.
    """

    def setUp(self):
        """
        Create user and login.
        """

        settings.MODULESTORE['default']['OPTIONS']['fs_root'] = path('common/test/data')
        settings.MODULESTORE['direct']['OPTIONS']['fs_root'] = path('common/test/data')

        self.client = Client()
        self.contentstore = contentstore()

        self.course_key = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')

        import_from_xml(modulestore('direct'), 'common/test/data/', ['toy'],
                static_content_store=self.contentstore, verbose=True)

        # A locked asset
        self.locked_asset = self.course_key.make_asset_key('asset', 'sample_static.txt')
        self.url_locked = self.locked_asset.to_deprecated_string()

        # An unlocked asset
        self.unlocked_asset = self.course_key.make_asset_key('asset', 'another_static.txt')
        self.url_unlocked = self.unlocked_asset.to_deprecated_string()

        self.contentstore.set_attr(self.locked_asset, 'locked', True)

        # Create user
        self.usr = '******'
        self.pwd = 'foo'
        email = '*****@*****.**'
        self.user = User.objects.create_user(self.usr, email, self.pwd)
        self.user.is_active = True
        self.user.save()

        # Create staff user
        self.staff_usr = '******'
        self.staff_pwd = 'foo'
        staff_email = '*****@*****.**'
        self.staff_user = User.objects.create_user(self.staff_usr, staff_email,
                self.staff_pwd)
        self.staff_user.is_active = True
        self.staff_user.is_staff = True
        self.staff_user.save()

    def tearDown(self):

        MongoClient().drop_database(TEST_DATA_CONTENTSTORE['DOC_STORE_CONFIG']['db'])
        _CONTENTSTORE.clear()

    def test_unlocked_asset(self):
        """
        Test that unlocked assets are being served.
        """
        self.client.logout()
        resp = self.client.get(self.url_unlocked)
        self.assertEqual(resp.status_code, 200) # pylint: disable=E1103

    def test_locked_asset_not_logged_in(self):
        """
        Test that locked assets behave appropriately in case the user is not
        logged in.
        """
        self.client.logout()
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403) # pylint: disable=E1103

    def test_locked_asset_not_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        in but not registered for the course.
        """
        self.client.login(username=self.usr, password=self.pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403) # pylint: disable=E1103

    def test_locked_asset_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        and registered for the course.
        """
        CourseEnrollment.enroll(self.user, self.course_key)
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))

        self.client.login(username=self.usr, password=self.pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200) # pylint: disable=E1103

    def test_locked_asset_staff(self):
        """
        Test that locked assets behave appropriately in case user is staff.
        """
        self.client.login(username=self.staff_usr, password=self.staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200) # pylint: disable=E1103
Esempio n. 13
0
class ContentStoreToyCourseTest(ModuleStoreTestCase):
    """
    Tests that use the toy course.
    """

    def setUp(self):
        """
        Create user and login.
        """
        self.staff_pwd = super(ContentStoreToyCourseTest, self).setUp()
        self.staff_usr = self.user
        self.non_staff_usr, self.non_staff_pwd = self.create_non_staff_user()

        self.client = Client()
        self.contentstore = contentstore()

        self.course_key = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')

        import_from_xml(modulestore(), self.user.id, 'common/test/data/', ['toy'],
                static_content_store=self.contentstore, verbose=True)

        # A locked asset
        self.locked_asset = self.course_key.make_asset_key('asset', 'sample_static.txt')
        self.url_locked = self.locked_asset.to_deprecated_string()

        # An unlocked asset
        self.unlocked_asset = self.course_key.make_asset_key('asset', 'another_static.txt')
        self.url_unlocked = self.unlocked_asset.to_deprecated_string()

        self.contentstore.set_attr(self.locked_asset, 'locked', True)

    def tearDown(self):

        contentstore().drop_database()
        _CONTENTSTORE.clear()

    def test_unlocked_asset(self):
        """
        Test that unlocked assets are being served.
        """
        self.client.logout()
        resp = self.client.get(self.url_unlocked)
        self.assertEqual(resp.status_code, 200) # pylint: disable=E1103

    def test_locked_asset_not_logged_in(self):
        """
        Test that locked assets behave appropriately in case the user is not
        logged in.
        """
        self.client.logout()
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403) # pylint: disable=E1103

    def test_locked_asset_not_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        in but not registered for the course.
        """
        self.client.login(username=self.non_staff_usr, password=self.non_staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403) # pylint: disable=E1103

    def test_locked_asset_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        and registered for the course.
        """
        CourseEnrollment.enroll(self.non_staff_usr, self.course_key)
        self.assertTrue(CourseEnrollment.is_enrolled(self.non_staff_usr, self.course_key))

        self.client.login(username=self.non_staff_usr, password=self.non_staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200) # pylint: disable=E1103

    def test_locked_asset_staff(self):
        """
        Test that locked assets behave appropriately in case user is staff.
        """
        self.client.login(username=self.staff_usr, password=self.staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200) # pylint: disable=E1103
Esempio n. 14
0
class ContentStoreToyCourseTest(ModuleStoreTestCase):
    """
    Tests that use the toy course.
    """

    def setUp(self):
        """
        Create user and login.
        """

        settings.MODULESTORE['default']['OPTIONS']['fs_root'] = path('common/test/data')
        settings.MODULESTORE['direct']['OPTIONS']['fs_root'] = path('common/test/data')

        self.client = Client()
        self.contentstore = contentstore()

        self.course_key = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')

        import_from_xml(modulestore('direct'), 'common/test/data/', ['toy'],
                static_content_store=self.contentstore, verbose=True)

        # A locked asset
        self.locked_asset = self.course_key.make_asset_key('asset', 'sample_static.txt')
        self.url_locked = self.locked_asset.to_deprecated_string()

        # An unlocked asset
        self.unlocked_asset = self.course_key.make_asset_key('asset', 'another_static.txt')
        self.url_unlocked = self.unlocked_asset.to_deprecated_string()

        self.contentstore.set_attr(self.locked_asset, 'locked', True)

        # Create user
        self.usr = '******'
        self.pwd = 'foo'
        email = '*****@*****.**'
        self.user = User.objects.create_user(self.usr, email, self.pwd)
        self.user.is_active = True
        self.user.save()

        # Create staff user
        self.staff_usr = '******'
        self.staff_pwd = 'foo'
        staff_email = '*****@*****.**'
        self.staff_user = User.objects.create_user(self.staff_usr, staff_email,
                self.staff_pwd)
        self.staff_user.is_active = True
        self.staff_user.is_staff = True
        self.staff_user.save()

    def tearDown(self):

        MongoClient().drop_database(TEST_DATA_CONTENTSTORE['DOC_STORE_CONFIG']['db'])
        _CONTENTSTORE.clear()

    def test_unlocked_asset(self):
        """
        Test that unlocked assets are being served.
        """
        self.client.logout()
        resp = self.client.get(self.url_unlocked)
        self.assertEqual(resp.status_code, 200) # pylint: disable=E1103

    def test_locked_asset_not_logged_in(self):
        """
        Test that locked assets behave appropriately in case the user is not
        logged in.
        """
        self.client.logout()
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403) # pylint: disable=E1103

    def test_locked_asset_not_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        in but not registered for the course.
        """
        self.client.login(username=self.usr, password=self.pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403) # pylint: disable=E1103

    def test_locked_asset_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        and registered for the course.
        """
        CourseEnrollment.enroll(self.user, self.course_key)
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))

        self.client.login(username=self.usr, password=self.pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200) # pylint: disable=E1103

    def test_locked_asset_staff(self):
        """
        Test that locked assets behave appropriately in case user is staff.
        """
        self.client.login(username=self.staff_usr, password=self.staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200) # pylint: disable=E1103
Esempio n. 15
0
class TestContentstore(unittest.TestCase):
    """
    Test the methods in contentstore.mongo using deprecated and non-deprecated keys
    """

    # don't use these 2 class vars as they restore behavior once the tests are done
    asset_deprecated = None
    ssck_deprecated = None

    @classmethod
    def tearDownClass(cls):
        """
        Restores deprecated values
        """
        if cls.asset_deprecated is not None:
            setattr(AssetLocation, 'deprecated', cls.asset_deprecated)
        else:
            delattr(AssetLocation, 'deprecated')
        if cls.ssck_deprecated is not None:
            setattr(SlashSeparatedCourseKey, 'deprecated', cls.ssck_deprecated)
        else:
            delattr(SlashSeparatedCourseKey, 'deprecated')
        return super(TestContentstore, cls).tearDownClass()

    def set_up_assets(self, deprecated):
        """
        Setup contentstore w/ proper overriding of deprecated.
        """
        # since MongoModuleStore and MongoContentStore are basically assumed to be together, create this class
        # as well
        self.contentstore = MongoContentStore(HOST, DB, port=PORT)
        self.addCleanup(self.contentstore._drop_database)  # pylint: disable=protected-access

        setattr(AssetLocation, 'deprecated', deprecated)
        setattr(SlashSeparatedCourseKey, 'deprecated', deprecated)

        self.course1_key = SlashSeparatedCourseKey('test', 'asset_test',
                                                   '2014_07')
        self.course2_key = SlashSeparatedCourseKey('test', 'asset_test2',
                                                   '2014_07')

        self.course1_files = ['contains.sh', 'picture1.jpg', 'picture2.jpg']
        self.course2_files = ['picture1.jpg', 'picture3.jpg', 'door_2.ogg']

        def load_assets(course_key, files):
            locked = False
            for filename in files:
                asset_key = course_key.make_asset_key('asset', filename)
                self.save_asset(filename, asset_key, filename, locked)
                locked = not locked

        load_assets(self.course1_key, self.course1_files)
        load_assets(self.course2_key, self.course2_files)

    def save_asset(self, filename, asset_key, displayname, locked):
        """
        Load and save the given file.
        """
        with open("{}/static/{}".format(DATA_DIR, filename), "rb") as f:
            content = StaticContent(asset_key,
                                    displayname,
                                    mimetypes.guess_type(filename)[0],
                                    f.read(),
                                    locked=locked)
            self.contentstore.save(content)

    @ddt.data(True, False)
    def test_delete(self, deprecated):
        """
        Test that deleting assets works
        """
        self.set_up_assets(deprecated)
        asset_key = self.course1_key.make_asset_key('asset',
                                                    self.course1_files[0])
        self.contentstore.delete(asset_key)

        with self.assertRaises(NotFoundError):
            self.contentstore.find(asset_key)

        # ensure deleting a non-existent file is a noop
        self.contentstore.delete(asset_key)

    @ddt.data(True, False)
    def test_find(self, deprecated):
        """
        Test using find
        """
        self.set_up_assets(deprecated)
        asset_key = self.course1_key.make_asset_key('asset',
                                                    self.course1_files[0])
        self.assertIsNotNone(self.contentstore.find(asset_key),
                             "Could not find {}".format(asset_key))

        self.assertIsNotNone(self.contentstore.find(asset_key, as_stream=True),
                             "Could not find {}".format(asset_key))

        unknown_asset = self.course1_key.make_asset_key(
            'asset', 'no_such_file.gif')
        with self.assertRaises(NotFoundError):
            self.contentstore.find(unknown_asset)
        self.assertIsNone(
            self.contentstore.find(unknown_asset, throw_on_not_found=False),
            "Found unknown asset {}".format(unknown_asset))

    @ddt.data(True, False)
    def test_export_for_course(self, deprecated):
        """
        Test export
        """
        self.set_up_assets(deprecated)
        root_dir = path.path(mkdtemp())
        try:
            self.contentstore.export_all_for_course(
                self.course1_key,
                root_dir,
                path.path(root_dir / "policy.json"),
            )
            for filename in self.course1_files:
                filepath = path.path(root_dir / filename)
                self.assertTrue(filepath.isfile(),
                                "{} is not a file".format(filepath))
            for filename in self.course2_files:
                if filename not in self.course1_files:
                    filepath = path.path(root_dir / filename)
                    self.assertFalse(
                        filepath.isfile(),
                        "{} is unexpected exported a file".format(filepath))
        finally:
            shutil.rmtree(root_dir)

    @ddt.data(True, False)
    def test_get_all_content(self, deprecated):
        """
        Test get_all_content_for_course
        """
        self.set_up_assets(deprecated)
        course1_assets, count = self.contentstore.get_all_content_for_course(
            self.course1_key)
        self.assertEqual(count, len(self.course1_files), course1_assets)
        for asset in course1_assets:
            parsed = AssetLocation.from_deprecated_string(asset['filename'])
            self.assertIn(parsed.name, self.course1_files)

        course1_assets, __ = self.contentstore.get_all_content_for_course(
            self.course1_key, 1, 1)
        self.assertEqual(len(course1_assets), 1, course1_assets)

        fake_course = SlashSeparatedCourseKey('test', 'fake', 'non')
        course_assets, count = self.contentstore.get_all_content_for_course(
            fake_course)
        self.assertEqual(count, 0)
        self.assertEqual(course_assets, [])

    @ddt.data(True, False)
    def test_attrs(self, deprecated):
        """
        Test setting and getting attrs
        """
        self.set_up_assets(deprecated)
        for filename in self.course1_files:
            asset_key = self.course1_key.make_asset_key('asset', filename)
            prelocked = self.contentstore.get_attr(asset_key, 'locked', False)
            self.contentstore.set_attr(asset_key, 'locked', not prelocked)
            self.assertEqual(
                self.contentstore.get_attr(asset_key, 'locked', False),
                not prelocked)

    @ddt.data(True, False)
    def test_copy_assets(self, deprecated):
        """
        copy_all_course_assets
        """
        self.set_up_assets(deprecated)
        dest_course = SlashSeparatedCourseKey('test', 'destination', 'copy')
        self.contentstore.copy_all_course_assets(self.course1_key, dest_course)
        for filename in self.course1_files:
            asset_key = self.course1_key.make_asset_key('asset', filename)
            dest_key = dest_course.make_asset_key('asset', filename)
            source = self.contentstore.find(asset_key)
            copied = self.contentstore.find(dest_key)
            for propname in ['name', 'content_type', 'length', 'locked']:
                self.assertEqual(getattr(source, propname),
                                 getattr(copied, propname))

        __, count = self.contentstore.get_all_content_for_course(dest_course)
        self.assertEqual(count, len(self.course1_files))

    @ddt.data(True, False)
    def test_delete_assets(self, deprecated):
        """
        delete_all_course_assets
        """
        self.set_up_assets(deprecated)
        self.contentstore.delete_all_course_assets(self.course1_key)
        __, count = self.contentstore.get_all_content_for_course(
            self.course1_key)
        self.assertEqual(count, 0)
        # ensure it didn't remove any from other course
        __, count = self.contentstore.get_all_content_for_course(
            self.course2_key)
        self.assertEqual(count, len(self.course2_files))
Esempio n. 16
0
    def test_static_url_generation(self):

        course_key = SlashSeparatedCourseKey('org', 'class', 'run')
        location = course_key.make_asset_key('asset', 'my_file_name.jpg')
        path = StaticContent.get_static_path_from_location(location)
        self.assertEquals(path, '/static/my_file_name.jpg')
class TestContentstore(unittest.TestCase):
    """
    Test the methods in contentstore.mongo using deprecated and non-deprecated keys
    """

    # don't use these 2 class vars as they restore behavior once the tests are done
    asset_deprecated = None
    ssck_deprecated = None

    @classmethod
    def tearDownClass(cls):
        """
        Restores deprecated values
        """
        if cls.asset_deprecated is not None:
            setattr(AssetLocation, 'deprecated', cls.asset_deprecated)
        else:
            delattr(AssetLocation, 'deprecated')
        if cls.ssck_deprecated is not None:
            setattr(SlashSeparatedCourseKey, 'deprecated', cls.ssck_deprecated)
        else:
            delattr(SlashSeparatedCourseKey, 'deprecated')
        return super(TestContentstore, cls).tearDownClass()

    def set_up_assets(self, deprecated):
        """
        Setup contentstore w/ proper overriding of deprecated.
        """
        # since MongoModuleStore and MongoContentStore are basically assumed to be together, create this class
        # as well
        self.contentstore = MongoContentStore(HOST, DB, port=PORT)
        self.addCleanup(self.contentstore._drop_database)  # pylint: disable=protected-access

        setattr(AssetLocation, 'deprecated', deprecated)
        setattr(SlashSeparatedCourseKey, 'deprecated', deprecated)

        self.course1_key = SlashSeparatedCourseKey('test', 'asset_test', '2014_07')
        self.course2_key = SlashSeparatedCourseKey('test', 'asset_test2', '2014_07')

        self.course1_files = ['contains.sh', 'picture1.jpg', 'picture2.jpg']
        self.course2_files = ['picture1.jpg', 'picture3.jpg', 'door_2.ogg']

        def load_assets(course_key, files):
            locked = False
            for filename in files:
                asset_key = course_key.make_asset_key('asset', filename)
                self.save_asset(filename, asset_key, filename, locked)
                locked = not locked

        load_assets(self.course1_key, self.course1_files)
        load_assets(self.course2_key, self.course2_files)

    def save_asset(self, filename, asset_key, displayname, locked):
        """
        Load and save the given file.
        """
        with open("{}/static/{}".format(DATA_DIR, filename), "rb") as f:
            content = StaticContent(
                asset_key, displayname, mimetypes.guess_type(filename)[0], f.read(),
                locked=locked
            )
            self.contentstore.save(content)

    @ddt.data(True, False)
    def test_delete(self, deprecated):
        """
        Test that deleting assets works
        """
        self.set_up_assets(deprecated)
        asset_key = self.course1_key.make_asset_key('asset', self.course1_files[0])
        self.contentstore.delete(asset_key)

        with self.assertRaises(NotFoundError):
            self.contentstore.find(asset_key)

        # ensure deleting a non-existent file is a noop
        self.contentstore.delete(asset_key)

    @ddt.data(True, False)
    def test_find(self, deprecated):
        """
        Test using find
        """
        self.set_up_assets(deprecated)
        asset_key = self.course1_key.make_asset_key('asset', self.course1_files[0])
        self.assertIsNotNone(self.contentstore.find(asset_key), "Could not find {}".format(asset_key))

        self.assertIsNotNone(self.contentstore.find(asset_key, as_stream=True), "Could not find {}".format(asset_key))

        unknown_asset = self.course1_key.make_asset_key('asset', 'no_such_file.gif')
        with self.assertRaises(NotFoundError):
            self.contentstore.find(unknown_asset)
        self.assertIsNone(
            self.contentstore.find(unknown_asset, throw_on_not_found=False),
            "Found unknown asset {}".format(unknown_asset)
        )

    @ddt.data(True, False)
    def test_export_for_course(self, deprecated):
        """
        Test export
        """
        self.set_up_assets(deprecated)
        root_dir = path.path(mkdtemp())
        try:
            self.contentstore.export_all_for_course(
                self.course1_key, root_dir,
                path.path(root_dir / "policy.json"),
            )
            for filename in self.course1_files:
                filepath = path.path(root_dir / filename)
                self.assertTrue(filepath.isfile(), "{} is not a file".format(filepath))
            for filename in self.course2_files:
                if filename not in self.course1_files:
                    filepath = path.path(root_dir / filename)
                    self.assertFalse(filepath.isfile(), "{} is unexpected exported a file".format(filepath))
        finally:
            shutil.rmtree(root_dir)

    @ddt.data(True, False)
    def test_get_all_content(self, deprecated):
        """
        Test get_all_content_for_course
        """
        self.set_up_assets(deprecated)
        course1_assets, count = self.contentstore.get_all_content_for_course(self.course1_key)
        self.assertEqual(count, len(self.course1_files), course1_assets)
        for asset in course1_assets:
            parsed = AssetLocation.from_deprecated_string(asset['filename'])
            self.assertIn(parsed.name, self.course1_files)

        course1_assets, __ = self.contentstore.get_all_content_for_course(self.course1_key, 1, 1)
        self.assertEqual(len(course1_assets), 1, course1_assets)

        fake_course = SlashSeparatedCourseKey('test', 'fake', 'non')
        course_assets, count = self.contentstore.get_all_content_for_course(fake_course)
        self.assertEqual(count, 0)
        self.assertEqual(course_assets, [])

    @ddt.data(True, False)
    def test_attrs(self, deprecated):
        """
        Test setting and getting attrs
        """
        self.set_up_assets(deprecated)
        for filename in self.course1_files:
            asset_key = self.course1_key.make_asset_key('asset', filename)
            prelocked = self.contentstore.get_attr(asset_key, 'locked', False)
            self.contentstore.set_attr(asset_key, 'locked', not prelocked)
            self.assertEqual(self.contentstore.get_attr(asset_key, 'locked', False), not prelocked)

    @ddt.data(True, False)
    def test_copy_assets(self, deprecated):
        """
        copy_all_course_assets
        """
        self.set_up_assets(deprecated)
        dest_course = SlashSeparatedCourseKey('test', 'destination', 'copy')
        self.contentstore.copy_all_course_assets(self.course1_key, dest_course)
        for filename in self.course1_files:
            asset_key = self.course1_key.make_asset_key('asset', filename)
            dest_key = dest_course.make_asset_key('asset', filename)
            source = self.contentstore.find(asset_key)
            copied = self.contentstore.find(dest_key)
            for propname in ['name', 'content_type', 'length', 'locked']:
                self.assertEqual(getattr(source, propname), getattr(copied, propname))

        __, count = self.contentstore.get_all_content_for_course(dest_course)
        self.assertEqual(count, len(self.course1_files))

    @ddt.data(True, False)
    def test_delete_assets(self, deprecated):
        """
        delete_all_course_assets
        """
        self.set_up_assets(deprecated)
        self.contentstore.delete_all_course_assets(self.course1_key)
        __, count = self.contentstore.get_all_content_for_course(self.course1_key)
        self.assertEqual(count, 0)
        # ensure it didn't remove any from other course
        __, count = self.contentstore.get_all_content_for_course(self.course2_key)
        self.assertEqual(count, len(self.course2_files))
Esempio n. 18
0
class ContentStoreToyCourseTest(ModuleStoreTestCase):
    """
    Tests that use the toy course.
    """
    def setUp(self):
        """
        Create user and login.
        """
        self.staff_pwd = super(ContentStoreToyCourseTest, self).setUp()
        self.staff_usr = self.user
        self.non_staff_usr, self.non_staff_pwd = self.create_non_staff_user()

        self.client = Client()
        self.contentstore = contentstore()

        self.course_key = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')

        import_from_xml(modulestore(),
                        self.user.id,
                        'common/test/data/', ['toy'],
                        static_content_store=self.contentstore,
                        verbose=True)

        # A locked asset
        self.locked_asset = self.course_key.make_asset_key(
            'asset', 'sample_static.txt')
        self.url_locked = self.locked_asset.to_deprecated_string()

        # An unlocked asset
        self.unlocked_asset = self.course_key.make_asset_key(
            'asset', 'another_static.txt')
        self.url_unlocked = self.unlocked_asset.to_deprecated_string()

        self.contentstore.set_attr(self.locked_asset, 'locked', True)

    def test_unlocked_asset(self):
        """
        Test that unlocked assets are being served.
        """
        self.client.logout()
        resp = self.client.get(self.url_unlocked)
        self.assertEqual(resp.status_code, 200)  # pylint: disable=E1103

    def test_locked_asset_not_logged_in(self):
        """
        Test that locked assets behave appropriately in case the user is not
        logged in.
        """
        self.client.logout()
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403)  # pylint: disable=E1103

    def test_locked_asset_not_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        in but not registered for the course.
        """
        self.client.login(username=self.non_staff_usr,
                          password=self.non_staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403)  # pylint: disable=E1103

    def test_locked_asset_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        and registered for the course.
        """
        CourseEnrollment.enroll(self.non_staff_usr, self.course_key)
        self.assertTrue(
            CourseEnrollment.is_enrolled(self.non_staff_usr, self.course_key))

        self.client.login(username=self.non_staff_usr,
                          password=self.non_staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200)  # pylint: disable=E1103

    def test_locked_asset_staff(self):
        """
        Test that locked assets behave appropriately in case user is staff.
        """
        self.client.login(username=self.staff_usr, password=self.staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200)  # pylint: disable=E1103
Esempio n. 19
0
class ContentStoreToyCourseTest(ModuleStoreTestCase):
    """
    Tests that use the toy course.
    """

    def setUp(self):
        """
        Create user and login.
        """
        self.staff_pwd = super(ContentStoreToyCourseTest, self).setUp()
        self.staff_usr = self.user
        self.non_staff_usr, self.non_staff_pwd = self.create_non_staff_user()

        self.client = Client()
        self.contentstore = contentstore()

        self.course_key = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')

        import_from_xml(
            modulestore(), self.user.id, TEST_DATA_DIR, ['toy'],
            static_content_store=self.contentstore, verbose=True
        )

        # A locked asset
        self.locked_asset = self.course_key.make_asset_key('asset', 'sample_static.txt')
        self.url_locked = self.locked_asset.to_deprecated_string()
        self.contentstore.set_attr(self.locked_asset, 'locked', True)

        # An unlocked asset
        self.unlocked_asset = self.course_key.make_asset_key('asset', 'another_static.txt')
        self.url_unlocked = self.unlocked_asset.to_deprecated_string()
        self.length_unlocked = self.contentstore.get_attr(self.unlocked_asset, 'length')

    def test_unlocked_asset(self):
        """
        Test that unlocked assets are being served.
        """
        self.client.logout()
        resp = self.client.get(self.url_unlocked)
        self.assertEqual(resp.status_code, 200)

    def test_locked_asset_not_logged_in(self):
        """
        Test that locked assets behave appropriately in case the user is not
        logged in.
        """
        self.client.logout()
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403)

    def test_locked_asset_not_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        in but not registered for the course.
        """
        self.client.login(username=self.non_staff_usr, password=self.non_staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 403)

    def test_locked_asset_registered(self):
        """
        Test that locked assets behave appropriately in case user is logged in
        and registered for the course.
        """
        CourseEnrollment.enroll(self.non_staff_usr, self.course_key)
        self.assertTrue(CourseEnrollment.is_enrolled(self.non_staff_usr, self.course_key))

        self.client.login(username=self.non_staff_usr, password=self.non_staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200)

    def test_locked_asset_staff(self):
        """
        Test that locked assets behave appropriately in case user is staff.
        """
        self.client.login(username=self.staff_usr, password=self.staff_pwd)
        resp = self.client.get(self.url_locked)
        self.assertEqual(resp.status_code, 200)

    def test_range_request_full_file(self):
        """
        Test that a range request from byte 0 to last,
        outputs partial content status code and valid Content-Range and Content-Length.
        """
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes=0-')

        self.assertEqual(resp.status_code, 206)  # HTTP_206_PARTIAL_CONTENT
        self.assertEqual(
            resp['Content-Range'],
            'bytes {first}-{last}/{length}'.format(
                first=0, last=self.length_unlocked - 1,
                length=self.length_unlocked
            )
        )
        self.assertEqual(resp['Content-Length'], str(self.length_unlocked))

    def test_range_request_partial_file(self):
        """
        Test that a range request for a partial file,
        outputs partial content status code and valid Content-Range and Content-Length.
        first_byte and last_byte are chosen to be simple but non trivial values.
        """
        first_byte = self.length_unlocked / 4
        last_byte = self.length_unlocked / 2
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes={first}-{last}'.format(
            first=first_byte, last=last_byte)
        )

        self.assertEqual(resp.status_code, 206)  # HTTP_206_PARTIAL_CONTENT
        self.assertEqual(resp['Content-Range'], 'bytes {first}-{last}/{length}'.format(
            first=first_byte, last=last_byte, length=self.length_unlocked))
        self.assertEqual(resp['Content-Length'], str(last_byte - first_byte + 1))

    def test_range_request_multiple_ranges(self):
        """
        Test that multiple ranges in request outputs the full content.
        """
        first_byte = self.length_unlocked / 4
        last_byte = self.length_unlocked / 2
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes={first}-{last}, -100'.format(
            first=first_byte, last=last_byte)
        )

        self.assertEqual(resp.status_code, 200)
        self.assertNotIn('Content-Range', resp)
        self.assertEqual(resp['Content-Length'], str(self.length_unlocked))

    @ddt.data(
        'bytes 0-',
        'bits=0-',
        'bytes=0',
        'bytes=one-',
    )
    def test_syntax_errors_in_range(self, header_value):
        """
        Test that syntactically invalid Range values result in a 200 OK full content response.
        """
        resp = self.client.get(self.url_unlocked, HTTP_RANGE=header_value)
        self.assertEqual(resp.status_code, 200)
        self.assertNotIn('Content-Range', resp)

    def test_range_request_malformed_invalid_range(self):
        """
        Test that a range request with malformed Range (first_byte > last_byte) outputs
        416 Requested Range Not Satisfiable.
        """
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes={first}-{last}'.format(
            first=(self.length_unlocked / 2), last=(self.length_unlocked / 4))
        )
        self.assertEqual(resp.status_code, 416)

    def test_range_request_malformed_out_of_bounds(self):
        """
        Test that a range request with malformed Range (first_byte, last_byte == totalLength, offset by 1 error)
        outputs 416 Requested Range Not Satisfiable.
        """
        resp = self.client.get(self.url_unlocked, HTTP_RANGE='bytes={first}-{last}'.format(
            first=(self.length_unlocked), last=(self.length_unlocked))
        )
        self.assertEqual(resp.status_code, 416)