Example #1
0
class SqlaFilesTests(unittest.TestCase):

    def setUp(self):

        self.transient_root = tempfile.mkdtemp()
        self.persistent_root = tempfile.mkdtemp()
        self.transient_url = '/transient/'
        self.persistent_url = '/media/'

        self.file_manager = FileManager(self.transient_root,
                                        self.persistent_root,
                                        self.transient_url,
                                        self.persistent_url)

        self.ro_file_manager = ReadonlyFileManager(self.persistent_root,
                                                   self.persistent_url)

    def tearDown(self):
        shutil.rmtree(self.transient_root)
        shutil.rmtree(self.persistent_root)


    def test_file_attrs(self):
        with open(os.path.join(self.transient_root, 'testfile.html'), 'w') as f:
            f.write('<html></html>')

        fl = TransientFile(self.transient_root, 'testfile.html', self.file_manager)

        self.assertEqual(fl.mimetype, 'text/html')
        self.assertEqual(fl.size, 13)
        self.assertEqual(fl.file_name, 'testfile.html')
        self.assertEqual(fl.ext, '.html')
        self.assertEqual(fl.url, '/transient/testfile.html')

    def test_repr(self):
        with open(os.path.join(self.transient_root, 'testfile.html'), 'w') as f:
            f.write('<html></html>')

        fl = TransientFile(self.transient_root, 'testfile.html', self.file_manager)
        represent = repr(fl)
        self.assertIn('TransientFile', represent)
        self.assertIn('testfile.html', represent)

    def test_no_file(self):
        fl = PersistentFile(self.persistent_root, 'testfile2.html', self.file_manager)

        self.assertEqual(fl.mimetype, 'text/html')
        self.assertEqual(fl.size, None)
        self.assertEqual(fl.file_name, 'testfile2.html')
        self.assertEqual(fl.ext, '.html')
        self.assertEqual(fl.url, '/media/testfile2.html')

    def test_delete(self):
        with open(os.path.join(self.transient_root, 'delfile1.html'), 'w') as f:
            f.write('<html></html>')

        fl1 = TransientFile(self.transient_root, 'delfile1.html', self.file_manager)
        fl2 = TransientFile(self.transient_root, 'delfile2.html', self.file_manager)

        self.assertTrue(os.path.isfile(fl1.path))
        self.assertFalse(os.path.isfile(fl2.path))

        log = []
        with patch('logging.Logger.warning',
                   side_effect=lambda m: log.append(m)):
            self.file_manager.delete(fl1)
            self.file_manager.delete(fl2)

        self.assertFalse(os.path.isfile(fl1.path))
        self.assertFalse(os.path.isfile(fl2.path))
        self.assertIn('delfile2.html', log[0])
        self.assertIn('was not found', log[0])

    def test_delete_error(self):
        path = os.path.join(self.transient_root, 'delfile1.html')
        with open(path, 'w') as f:
            f.write('<html></html>')

        fl1 = TransientFile(self.transient_root, 'delfile1.html', self.file_manager)
        self.assertTrue(os.path.isfile(fl1.path))
        log = []

        # mocking permission error
        def unlink_error(path):
            raise OSError("[Errno 13] Permission denied: {}".format(path))

        with patch('logging.Logger.error',
                   side_effect=lambda m: log.append(m)):
            with patch('os.unlink', side_effect=unlink_error):
                with self.assertRaises(OSError) as exc:
                    self.file_manager.delete(fl1)

    def test_readonly_file_manager(self):
        get_persistent = self.ro_file_manager.get_persistent

        fl = get_persistent('name.txt')
        self.assertIsInstance(fl, PersistentFile)
        self.assertEqual(self.ro_file_manager.get_persistent_url(fl), '/media/name.txt')


        self.assertRaises(ValueError, get_persistent, 'something/../name.txt')
        self.assertRaises(ValueError, get_persistent, '/something/name.txt')
        self.assertRaises(ValueError, get_persistent, '~/something/name.txt')


    def test_create_transient(self):
        req_fl = os.path.join(self.transient_root, 'xxxxx.html')
        with open(req_fl, 'w') as f:
            f.write('<html></html>' * 10000)

        with open(req_fl) as f:
            request = Request.blank('/', POST={'file': ('big.html', f)})

            fl = self.file_manager.create_transient(request.POST['file'].file,
                                                    request.POST['file'].name)

        self.assertEqual(fl.size, 130000)

        # XXX this is a test of strange behaviour when browser does not
        #     pass Content-Length header when uploading a file in POST body
        #     See iktomi.cms.ajax_file_upload
        #     There is no obvious way to simulate this behaviour except
        #     hardcoded length variable.
        with open(req_fl, 'w') as f:
            f.write('<html></html>' * 10000)

        with open(req_fl) as f:
            request = Request.blank('/', POST={'file': ('big.html', f)})

            fl = self.file_manager.create_transient(request.POST['file'].file,
                                                    request.POST['file'].name,
                                                    length=130000)

        self.assertEqual(fl.size, 130000)

    def test_create_transient_dir(self):
        req_fl = os.path.join(self.transient_root, 'xxxxx.html')
        with open(req_fl, 'w') as f:
            f.write('<html></html>' * 10000)

        nonexistent_dir = os.path.join(self.transient_root,
                                       "non/existent/dir")

        self.assertFalse(os.path.exists(nonexistent_dir))

        self.file_manager.transient_root = nonexistent_dir

        with open(req_fl) as f:
            request = Request.blank('/', POST={'file': ('big.html', f)})
            fl = self.file_manager.create_transient(request.POST['file'].file,
                                                    request.POST['file'].name)

        self.assertEqual(fl.path, os.path.join(nonexistent_dir, fl.name))
        self.assertEqual(fl.size, 130000)

    def test_create_symlink(self):
        stream1 = BytesIO(b'hello')
        stream2 = BytesIO(b'world')

        source1 = self.file_manager.create_transient(stream1, 'hello.txt')
        source2 = self.file_manager.create_transient(stream2, 'world.txt')

        target_file_dir = os.path.join(self.persistent_root, 'dir/subdir')
        target_file = PersistentFile(target_file_dir, 'target.txt')
        target_file_path = os.path.join(target_file_dir, 'target.txt')
        self.assertFalse(os.path.isfile(target_file_path))

        self.file_manager.create_symlink(source1, target_file)

        self.assertTrue(os.path.isfile(target_file_path))

        with open(target_file_path) as f:
            self.assertEqual('hello', f.read())

        self.file_manager.create_symlink(source2, target_file)

        self.assertTrue(os.path.isfile(target_file_path))

        with open(target_file_path) as f:
            self.assertEqual('world', f.read())
Example #2
0
class SqlaFilesTests(unittest.TestCase):
    def setUp(self):

        self.transient_root = tempfile.mkdtemp()
        self.persistent_root = tempfile.mkdtemp()
        self.transient_url = '/transient/'
        self.persistent_url = '/media/'

        self.file_manager = FileManager(self.transient_root,
                                        self.persistent_root,
                                        self.transient_url,
                                        self.persistent_url)

        self.ro_file_manager = ReadonlyFileManager(self.persistent_root,
                                                   self.persistent_url)

    def tearDown(self):
        shutil.rmtree(self.transient_root)
        shutil.rmtree(self.persistent_root)

    def test_file_attrs(self):
        with open(os.path.join(self.transient_root, 'testfile.html'),
                  'w') as f:
            f.write('<html></html>')

        fl = TransientFile(self.transient_root, 'testfile.html',
                           self.file_manager)

        self.assertEqual(fl.mimetype, 'text/html')
        self.assertEqual(fl.size, 13)
        self.assertEqual(fl.file_name, 'testfile.html')
        self.assertEqual(fl.ext, '.html')
        self.assertEqual(fl.url, '/transient/testfile.html')

    def test_repr(self):
        with open(os.path.join(self.transient_root, 'testfile.html'),
                  'w') as f:
            f.write('<html></html>')

        fl = TransientFile(self.transient_root, 'testfile.html',
                           self.file_manager)
        represent = repr(fl)
        self.assertIn('TransientFile', represent)
        self.assertIn('testfile.html', represent)

    def test_no_file(self):
        fl = PersistentFile(self.persistent_root, 'testfile2.html',
                            self.file_manager)

        self.assertEqual(fl.mimetype, 'text/html')
        self.assertEqual(fl.size, None)
        self.assertEqual(fl.file_name, 'testfile2.html')
        self.assertEqual(fl.ext, '.html')
        self.assertEqual(fl.url, '/media/testfile2.html')

    def test_delete(self):
        with open(os.path.join(self.transient_root, 'delfile1.html'),
                  'w') as f:
            f.write('<html></html>')

        fl1 = TransientFile(self.transient_root, 'delfile1.html',
                            self.file_manager)
        fl2 = TransientFile(self.transient_root, 'delfile2.html',
                            self.file_manager)

        self.assertTrue(os.path.isfile(fl1.path))
        self.assertFalse(os.path.isfile(fl2.path))

        log = []
        with patch('logging.Logger.warning',
                   side_effect=lambda m: log.append(m)):
            self.file_manager.delete(fl1)
            self.file_manager.delete(fl2)

        self.assertFalse(os.path.isfile(fl1.path))
        self.assertFalse(os.path.isfile(fl2.path))
        self.assertIn('delfile2.html', log[0])
        self.assertIn('was not found', log[0])

    def test_delete_error(self):
        path = os.path.join(self.transient_root, 'delfile1.html')
        with open(path, 'w') as f:
            f.write('<html></html>')

        fl1 = TransientFile(self.transient_root, 'delfile1.html',
                            self.file_manager)
        self.assertTrue(os.path.isfile(fl1.path))
        log = []

        # mocking permission error
        def unlink_error(path):
            raise OSError("[Errno 13] Permission denied: {}".format(path))

        with patch('logging.Logger.error',
                   side_effect=lambda m: log.append(m)):
            with patch('os.unlink', side_effect=unlink_error):
                with self.assertRaises(OSError) as exc:
                    self.file_manager.delete(fl1)

    def test_readonly_file_manager(self):
        get_persistent = self.ro_file_manager.get_persistent

        fl = get_persistent('name.txt')
        self.assertIsInstance(fl, PersistentFile)
        self.assertEqual(self.ro_file_manager.get_persistent_url(fl),
                         '/media/name.txt')

        self.assertRaises(ValueError, get_persistent, 'something/../name.txt')
        self.assertRaises(ValueError, get_persistent, '/something/name.txt')
        self.assertRaises(ValueError, get_persistent, '~/something/name.txt')

    def test_create_transient(self):
        req_fl = os.path.join(self.transient_root, 'xxxxx.html')
        with open(req_fl, 'w') as f:
            f.write('<html></html>' * 10000)

        with open(req_fl) as f:
            request = Request.blank('/', POST={'file': ('big.html', f)})

            fl = self.file_manager.create_transient(request.POST['file'].file,
                                                    request.POST['file'].name)

        self.assertEqual(fl.size, 130000)

        # XXX this is a test of strange behaviour when browser does not
        #     pass Content-Length header when uploading a file in POST body
        #     See iktomi.cms.ajax_file_upload
        #     There is no obvious way to simulate this behaviour except
        #     hardcoded length variable.
        with open(req_fl, 'w') as f:
            f.write('<html></html>' * 10000)

        with open(req_fl) as f:
            request = Request.blank('/', POST={'file': ('big.html', f)})

            fl = self.file_manager.create_transient(request.POST['file'].file,
                                                    request.POST['file'].name,
                                                    length=130000)

        self.assertEqual(fl.size, 130000)

    def test_create_transient_dir(self):
        req_fl = os.path.join(self.transient_root, 'xxxxx.html')
        with open(req_fl, 'w') as f:
            f.write('<html></html>' * 10000)

        nonexistent_dir = os.path.join(self.transient_root, "non/existent/dir")

        self.assertFalse(os.path.exists(nonexistent_dir))

        self.file_manager.transient_root = nonexistent_dir

        with open(req_fl) as f:
            request = Request.blank('/', POST={'file': ('big.html', f)})
            fl = self.file_manager.create_transient(request.POST['file'].file,
                                                    request.POST['file'].name)

        self.assertEqual(fl.path, os.path.join(nonexistent_dir, fl.name))
        self.assertEqual(fl.size, 130000)

    def test_create_symlink(self):
        stream1 = BytesIO(b'hello')
        stream2 = BytesIO(b'world')

        source1 = self.file_manager.create_transient(stream1, 'hello.txt')
        source2 = self.file_manager.create_transient(stream2, 'world.txt')

        target_file_dir = os.path.join(self.persistent_root, 'dir/subdir')
        target_file = PersistentFile(target_file_dir, 'target.txt')
        target_file_path = os.path.join(target_file_dir, 'target.txt')
        self.assertFalse(os.path.isfile(target_file_path))

        self.file_manager.create_symlink(source1, target_file)

        self.assertTrue(os.path.isfile(target_file_path))

        with open(target_file_path) as f:
            self.assertEqual('hello', f.read())

        self.file_manager.create_symlink(source2, target_file)

        self.assertTrue(os.path.isfile(target_file_path))

        with open(target_file_path) as f:
            self.assertEqual('world', f.read())