diff options
-rw-r--r-- | glusterfs/gfapi.py | 42 | ||||
-rw-r--r-- | test/functional/libgfapi-python-tests.py | 30 | ||||
-rw-r--r-- | test/unit/gluster/test_gfapi.py | 39 | ||||
-rw-r--r-- | tox.ini | 2 |
4 files changed, 68 insertions, 45 deletions
diff --git a/glusterfs/gfapi.py b/glusterfs/gfapi.py index 8eeb3d6..6ca2ad7 100644 --- a/glusterfs/gfapi.py +++ b/glusterfs/gfapi.py @@ -19,8 +19,6 @@ import os import stat import errno -from contextlib import contextmanager - # Disclaimer: many of the helper functions (e.g., exists, isdir) where copied # from the python source code @@ -92,6 +90,17 @@ class File(object): def __init__(self, fd): self.fd = fd + def __enter__(self): + if self.fd is None: + # __enter__ should only be called within the context + # of a 'with' statement when opening a file through + # Volume.open() + raise ValueError("I/O operation on closed file") + return self + + def __exit__(self, type, value, tb): + self.close() + def close(self): ret = api.glfs_close(self.fd) if ret < 0: @@ -243,20 +252,6 @@ class Volume(object): raise OSError(err, os.strerror(err)) return ret - @contextmanager - def creat(self, path, flags, mode): - fd = api.glfs_creat(self.fs, path, flags, mode) - if not fd: - err = ctypes.get_errno() - raise OSError(err, os.strerror(err)) - - fileobj = None - try: - fileobj = File(fd) - yield fileobj - finally: - fileobj.close() - def exists(self, path): """ Test whether a path exists. @@ -384,19 +379,16 @@ class Volume(object): raise OSError(err, os.strerror(err)) return ret - @contextmanager - def open(self, path, flags): - fd = api.glfs_open(self.fs, path, flags) + def open(self, path, flags, mode=0777): + if (os.O_CREAT & flags) == os.O_CREAT: + fd = api.glfs_creat(self.fs, path, flags, mode) + else: + fd = api.glfs_open(self.fs, path, flags) if not fd: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) - fileobj = None - try: - fileobj = File(fd) - yield fileobj - finally: - fileobj.close() + return File(fd) def opendir(self, path): fd = api.glfs_opendir(self.fs, path) diff --git a/test/functional/libgfapi-python-tests.py b/test/functional/libgfapi-python-tests.py index cdb556c..ac5c38f 100644 --- a/test/functional/libgfapi-python-tests.py +++ b/test/functional/libgfapi-python-tests.py @@ -17,6 +17,7 @@ import unittest import os import types import loremipsum +import errno from glusterfs import gfapi @@ -40,7 +41,8 @@ class BinFileOpsTest(unittest.TestCase): def setUp(self): self.data = bytearray([(k % 128) for k in range(0, 1024)]) self.path = self._testMethodName + ".io" - with self.vol.creat(self.path, os.O_WRONLY | os.O_EXCL, 0644) as fd: + with self.vol.open(self.path, os.O_CREAT | os.O_WRONLY | os.O_EXCL, + 0644) as fd: fd.write(self.data) def test_bin_open_and_read(self): @@ -70,7 +72,8 @@ class FileOpsTest(unittest.TestCase): def setUp(self): self.data = loremipsum.get_sentence() self.path = self._testMethodName + ".io" - with self.vol.creat(self.path, os.O_WRONLY | os.O_EXCL, 0644) as fd: + with self.vol.open(self.path, os.O_CREAT | os.O_WRONLY | os.O_EXCL, + 0644) as fd: rc = fd.write(self.data) self.assertEqual(rc, len(self.data)) ret = fd.fsync() @@ -87,6 +90,26 @@ class FileOpsTest(unittest.TestCase): self.assertFalse(isinstance(buf, types.IntType)) self.assertEqual(buf.value, self.data) + def test_open_file_not_exist(self): + try: + f = self.vol.open("filenotexist", os.O_WRONLY) + except OSError as e: + self.assertEqual(e.errno, errno.ENOENT) + else: + f.close() + self.fail("Expected a OSError with errno.ENOENT") + + def test_create_file_already_exists(self): + try: + f = self.vol.open("newfile", os.O_CREAT) + f.close() + g = self.vol.open("newfile", os.O_CREAT | os.O_EXCL) + except OSError as e: + self.assertEqual(e.errno, errno.EEXIST) + else: + g.close() + self.fail("Expected a OSError with errno.EEXIST") + def test_exists(self): e = self.vol.exists(self.path) self.assertTrue(e) @@ -186,7 +209,8 @@ class DirOpsTest(unittest.TestCase): self.vol.mkdir(self.dir_path, 0755) for x in range(0, 3): f = os.path.join(self.dir_path, self.testfile + str(x)) - with self.vol.creat(f, os.O_WRONLY | os.O_EXCL, 0644) as fd: + with self.vol.open(f, os.O_CREAT | os.O_WRONLY | os.O_EXCL, + 0644) as fd: rc = fd.write(self.data) self.assertEqual(rc, len(self.data)) ret = fd.fdatasync() diff --git a/test/unit/gluster/test_gfapi.py b/test/unit/gluster/test_gfapi.py index 8fcf938..ed7ed45 100644 --- a/test/unit/gluster/test_gfapi.py +++ b/test/unit/gluster/test_gfapi.py @@ -279,23 +279,12 @@ class TestVolume(unittest.TestCase): mock_glfs_creat.return_value = 2 with patch("glusterfs.gfapi.api.glfs_creat", mock_glfs_creat): - with self.vol.creat("file.txt", os.O_WRONLY, 0644) as fd: + with self.vol.open("file.txt", os.O_CREAT, 0644) as fd: self.assertTrue(isinstance(fd, gfapi.File)) self.assertEqual(mock_glfs_creat.call_count, 1) mock_glfs_creat.assert_called_once_with(2, "file.txt", - os.O_WRONLY, 0644) - - def test_creat_fail_exception(self): - mock_glfs_creat = Mock() - mock_glfs_creat.return_value = None - - def assert_creat(): - with self.vol.creat("file.txt", os.O_WRONLY, 0644) as fd: - self.assertEqual(fd, None) - - with patch("glusterfs.gfapi.api.glfs_creat", mock_glfs_creat): - self.assertRaises(OSError, assert_creat) + os.O_CREAT, 0644) def test_exists_true(self): mock_glfs_stat = Mock() @@ -430,7 +419,8 @@ class TestVolume(unittest.TestCase): mock_Dir_next = Mock() mock_Dir_next.side_effect = [dirent1, dirent2, dirent3, None] - with nested(patch("glusterfs.gfapi.api.glfs_opendir", mock_glfs_opendir), + with nested(patch("glusterfs.gfapi.api.glfs_opendir", + mock_glfs_opendir), patch("glusterfs.gfapi.Dir.next", mock_Dir_next)): d = self.vol.listdir("testdir") self.assertEqual(len(d), 2) @@ -545,7 +535,7 @@ class TestVolume(unittest.TestCase): with patch("glusterfs.gfapi.api.glfs_mkdir", mock_glfs_mkdir): self.assertRaises(OSError, self.vol.mkdir, "testdir", 0775) - def test_open_success(self): + def test_open_with_statement_success(self): mock_glfs_open = Mock() mock_glfs_open.return_value = 2 @@ -556,7 +546,7 @@ class TestVolume(unittest.TestCase): mock_glfs_open.assert_called_once_with(2, "file.txt", os.O_WRONLY) - def test_open_fail_exception(self): + def test_open_with_statement_fail_exception(self): mock_glfs_open = Mock() mock_glfs_open.return_value = None @@ -567,6 +557,23 @@ class TestVolume(unittest.TestCase): with patch("glusterfs.gfapi.api.glfs_open", mock_glfs_open): self.assertRaises(OSError, assert_open) + def test_open_direct_success(self): + mock_glfs_open = Mock() + mock_glfs_open.return_value = 2 + + with patch("glusterfs.gfapi.api.glfs_open", mock_glfs_open): + fd = self.vol.open("file.txt", os.O_WRONLY) + self.assertTrue(isinstance(fd, gfapi.File)) + self.assertEqual(mock_glfs_open.call_count, 1) + mock_glfs_open.assert_called_once_with(2, "file.txt", os.O_WRONLY) + + def test_open_direct_fail_exception(self): + mock_glfs_open = Mock() + mock_glfs_open.return_value = None + + with patch("glusterfs.gfapi.api.glfs_open", mock_glfs_open): + self.assertRaises(OSError, self.vol.open, "file.txt", os.O_RDONLY) + def test_opendir_success(self): mock_glfs_opendir = Mock() mock_glfs_opendir.return_value = 2 @@ -14,7 +14,7 @@ deps = --download-cache={homedir}/.pipcache -r{toxinidir}/tools/test-requires changedir = {toxinidir}/test/unit -commands = nosetests -v --exe --with-xunit --with-coverage --cover-package gluster --cover-erase --cover-xml --cover-html --cover-branches --with-html-output {posargs} +commands = nosetests -v --exe --with-xunit --with-coverage --cover-package glusterfs --cover-erase --cover-xml --cover-html --cover-branches --with-html-output {posargs} [tox:jenkins] downloadcache = ~/cache/pip |