From d5e4a0362a08ca3c0e7a33ea8caafccb22b906b2 Mon Sep 17 00:00:00 2001 From: Adam Cecile Date: Thu, 19 Apr 2018 22:11:55 +0200 Subject: Port to Python 3.x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on PR sent by Adam Cécile (eLvErDe on GitHub): https://github.com/gluster/libgfapi-python/pull/21 Additional changes to original PR: * Make it pep8 compliant * Fix comment in getcwd() * Add functest36 env to tox.ini Change-Id: I45c4056333c12a82814cf8adcfa87e6687365366 Signed-off-by: Prashanth Pai --- gluster/gfapi/__init__.py | 2 +- gluster/gfapi/gfapi.py | 181 +++++++++++++++++--------- setup.py | 5 +- test/__init__.py | 7 +- test/functional/libgfapi-python-tests.py | 105 ++++++++------- test/unit/gluster/test_gfapi.py | 214 ++++++++++++++++--------------- tox.ini | 12 +- 7 files changed, 311 insertions(+), 215 deletions(-) diff --git a/gluster/gfapi/__init__.py b/gluster/gfapi/__init__.py index 785b3e7..e3aa4d3 100644 --- a/gluster/gfapi/__init__.py +++ b/gluster/gfapi/__init__.py @@ -10,5 +10,5 @@ __version__ = '1.1' -from gfapi import File, Dir, DirEntry, Volume +from .gfapi import File, Dir, DirEntry, Volume __all__ = ['File', 'Dir', 'DirEntry', 'Volume'] diff --git a/gluster/gfapi/gfapi.py b/gluster/gfapi/gfapi.py index eedc03b..5078c00 100644 --- a/gluster/gfapi/gfapi.py +++ b/gluster/gfapi/gfapi.py @@ -8,7 +8,10 @@ # later), or the GNU General Public License, version 2 (GPLv2), in all # cases as published by the Free Software Foundation. +from __future__ import unicode_literals + import ctypes +import sys import os import math import time @@ -25,6 +28,13 @@ from gluster.gfapi.utils import validate_mount, validate_glfd python_mode_to_os_flags = {} +PY3 = sys.version_info >= (3, 0) +if PY3: + string_types = (str,) +else: + string_types = (str, unicode) + + def _populate_mode_to_flags_dict(): # http://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html for mode in ['r', 'rb']: @@ -43,6 +53,32 @@ def _populate_mode_to_flags_dict(): _populate_mode_to_flags_dict() +def decode_to_bytes(text): + """ + Decode unicode object to bytes + or return original object if already bytes + """ + if isinstance(text, string_types): + return text.encode('utf-8') + elif isinstance(text, bytes): + return text + else: + raise ValueError('Cannot convert object with type %s' % type(text)) + + +def encode_to_string(text): + """ + Encode bytes objects to unicode str + or return original object if already unicode + """ + if isinstance(text, string_types): + return text + elif isinstance(text, bytes): + return text.decode('utf-8') + else: + raise ValueError('Cannot convert object with type %s' % type(text)) + + class File(object): def __init__(self, fd, path=None, mode=None): @@ -238,17 +274,18 @@ class File(object): :raises: OSError on failure """ if size == 0: - size = api.glfs_fgetxattr(self.fd, key, None, size) + size = api.glfs_fgetxattr(self.fd, decode_to_bytes(key), + None, size) if size < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) buf = ctypes.create_string_buffer(size) - rc = api.glfs_fgetxattr(self.fd, key, buf, size) + rc = api.glfs_fgetxattr(self.fd, decode_to_bytes(key), buf, size) if rc < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) - return buf.value[:rc] + return encode_to_string(buf.value[:rc]) @validate_glfd def flistxattr(self, size=0): @@ -279,17 +316,23 @@ class File(object): # buffer" format. i = 0 while i < rc: - new_xa = buf.raw[i] + if PY3: + new_xa = str(bytes([buf.raw[i]]), 'utf-8') + else: + new_xa = buf.raw[i] i += 1 while i < rc: - next_char = buf.raw[i] + if PY3: + next_char = str(bytes([buf.raw[i]]), 'utf-8') + else: + next_char = buf.raw[i] i += 1 if next_char == '\0': xattrs.append(new_xa) break new_xa += next_char xattrs.sort() - return xattrs + return [encode_to_string(x) for x in xattrs] @validate_glfd def fsetxattr(self, key, value, flags=0): @@ -307,7 +350,9 @@ class File(object): does not already exist. :raises: OSError on failure """ - ret = api.glfs_fsetxattr(self.fd, key, value, len(value), flags) + ret = api.glfs_fsetxattr(self.fd, decode_to_bytes(key), + decode_to_bytes(value), + len(decode_to_bytes(value)), flags) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -320,7 +365,7 @@ class File(object): :param key: The key of extended attribute. :raises: OSError on failure """ - ret = api.glfs_fremovexattr(self.fd, key) + ret = api.glfs_fremovexattr(self.fd, decode_to_bytes(key)) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -488,7 +533,7 @@ class Dir(Iterator): self._api.glfs_closedir(self.fd) self._api = None - def next(self): + def __next__(self): entry = api.Dirent() entry.d_reclen = 256 @@ -514,6 +559,8 @@ class Dir(Iterator): else: return entry + next = __next__ # Python 2 + class DirEntry(object): """ @@ -532,11 +579,11 @@ class DirEntry(object): __slots__ = ('_name', '_vol', '_lstat', '_stat', '_path') def __init__(self, vol, scandir_path, name, lstat): - self._name = name + self._name = encode_to_string(name) self._vol = vol self._lstat = lstat self._stat = None - self._path = os.path.join(scandir_path, name) + self._path = os.path.join(scandir_path, self._name) @property def name(self): @@ -662,7 +709,7 @@ class Volume(object): raise LibgfapiException("Host and Volume name should not be None.") if proto not in ('tcp', 'rdma', 'unix'): raise LibgfapiException("Invalid protocol specified.") - if not isinstance(port, (int, long)): + if not isinstance(port, int): raise LibgfapiException("Invalid port specified.") self.host = host @@ -690,14 +737,16 @@ class Volume(object): # Already mounted return - self.fs = api.glfs_new(self.volname) + self.fs = api.glfs_new(decode_to_bytes(self.volname)) if not self.fs: err = ctypes.get_errno() raise LibgfapiException("glfs_new(%s) failed: %s" % (self.volname, os.strerror(err))) - ret = api.glfs_set_volfile_server(self.fs, self.protocol, - self.host, self.port) + ret = api.glfs_set_volfile_server(self.fs, + decode_to_bytes(self.protocol), + decode_to_bytes(self.host), + self.port) if ret < 0: err = ctypes.get_errno() raise LibgfapiException("glfs_set_volfile_server(%s, %s, %s, " @@ -762,7 +811,8 @@ class Volume(object): Higher the value, more verbose the logging. """ if self.fs: - ret = api.glfs_set_logging(self.fs, log_file, log_level) + ret = api.glfs_set_logging(self.fs, decode_to_bytes(log_file), + log_level) if ret < 0: err = ctypes.get_errno() raise LibgfapiException("glfs_set_logging(%s, %s) failed: %s" % @@ -805,7 +855,7 @@ class Volume(object): and X_OK to test permissions :returns: True if access is allowed, False if not """ - ret = api.glfs_access(self.fs, path, mode) + ret = api.glfs_access(self.fs, decode_to_bytes(path), mode) if ret == 0: return True else: @@ -819,7 +869,7 @@ class Volume(object): :param path: Path to change current working directory to :raises: OSError on failure """ - ret = api.glfs_chdir(self.fs, path) + ret = api.glfs_chdir(self.fs, decode_to_bytes(path)) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -833,7 +883,7 @@ class Volume(object): :param mode: new mode :raises: OSError on failure """ - ret = api.glfs_chmod(self.fs, path, mode) + ret = api.glfs_chmod(self.fs, decode_to_bytes(path), mode) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -848,7 +898,7 @@ class Volume(object): :param gid: new group id for path :raises: OSError on failure """ - ret = api.glfs_chown(self.fs, path, uid, gid) + ret = api.glfs_chown(self.fs, decode_to_bytes(path), uid, gid) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -888,10 +938,9 @@ class Volume(object): PATH_MAX = 4096 buf = ctypes.create_string_buffer(PATH_MAX) ret = api.glfs_getcwd(self.fs, buf, PATH_MAX) - if ret < 0: - err = ctypes.get_errno() - raise OSError(err, os.strerror(err)) - return buf.value + if not ret: + raise OSError(errno.ENOENT, os.strerror(errno.ENOENT)) + return encode_to_string(buf.value) def getmtime(self, path): """ @@ -922,17 +971,19 @@ class Volume(object): :raises: OSError on failure """ if size == 0: - size = api.glfs_getxattr(self.fs, path, key, None, 0) + size = api.glfs_getxattr(self.fs, decode_to_bytes(path), + decode_to_bytes(key), None, 0) if size < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) buf = ctypes.create_string_buffer(size) - rc = api.glfs_getxattr(self.fs, path, key, buf, size) + rc = api.glfs_getxattr(self.fs, decode_to_bytes(path), + decode_to_bytes(key), buf, size) if rc < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) - return buf.value[:rc] + return encode_to_string(buf.value[:rc]) def isdir(self, path): """ @@ -983,7 +1034,7 @@ class Volume(object): for entry in self.opendir(path): if not isinstance(entry, api.Dirent): break - name = entry.d_name[:entry.d_reclen] + name = encode_to_string(entry.d_name[:entry.d_reclen]) if name not in (".", ".."): dir_list.append(name) return dir_list @@ -1007,7 +1058,7 @@ class Volume(object): if not (isinstance(entry, api.Dirent) and isinstance(stat_info, api.Stat)): break - name = entry.d_name[:entry.d_reclen] + name = encode_to_string(entry.d_name[:entry.d_reclen]) if name not in (".", ".."): entries_with_stat.append((name, stat_info)) return entries_with_stat @@ -1034,7 +1085,7 @@ class Volume(object): """ for (entry, lstat) in self.opendir(path, readdirplus=True): name = entry.d_name[:entry.d_reclen] - if name not in (".", ".."): + if name not in (b".", b".."): yield DirEntry(self, path, name, lstat) @validate_mount @@ -1051,13 +1102,13 @@ class Volume(object): :raises: OSError on failure """ if size == 0: - size = api.glfs_listxattr(self.fs, path, None, 0) + size = api.glfs_listxattr(self.fs, decode_to_bytes(path), None, 0) if size < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) buf = ctypes.create_string_buffer(size) - rc = api.glfs_listxattr(self.fs, path, buf, size) + rc = api.glfs_listxattr(self.fs, decode_to_bytes(path), buf, size) if rc < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1067,17 +1118,23 @@ class Volume(object): # buffer" format. i = 0 while i < rc: - new_xa = buf.raw[i] + if PY3: + new_xa = str(bytes([buf.raw[i]]), 'utf-8') + else: + new_xa = buf.raw[i] i += 1 while i < rc: - next_char = buf.raw[i] + if PY3: + next_char = str(bytes([buf.raw[i]]), 'utf-8') + else: + next_char = buf.raw[i] i += 1 if next_char == '\0': xattrs.append(new_xa) break new_xa += next_char xattrs.sort() - return xattrs + return [encode_to_string(x) for x in xattrs] @validate_mount def lstat(self, path): @@ -1089,13 +1146,13 @@ class Volume(object): :raises: OSError on failure """ s = api.Stat() - rc = api.glfs_lstat(self.fs, path, ctypes.byref(s)) + rc = api.glfs_lstat(self.fs, decode_to_bytes(path), ctypes.byref(s)) if rc < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) return s - def makedirs(self, path, mode=0777): + def makedirs(self, path, mode=0o777): """ Recursive directory creation function. Like mkdir(), but makes all intermediate-level directories needed to contain the leaf directory. @@ -1119,14 +1176,14 @@ class Volume(object): self.mkdir(path, mode) @validate_mount - def mkdir(self, path, mode=0777): + def mkdir(self, path, mode=0o777): """ Create a directory named path with numeric mode mode. The default mode is 0777 (octal). :raises: OSError on failure """ - ret = api.glfs_mkdir(self.fs, path, mode) + ret = api.glfs_mkdir(self.fs, decode_to_bytes(path), mode) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1156,7 +1213,7 @@ class Volume(object): :raises: OSError on failure to create/open file. TypeError and ValueError if mode is invalid. """ - if not isinstance(mode, basestring): + if not isinstance(mode, string_types): raise TypeError("Mode must be a string") try: flags = python_mode_to_os_flags[mode] @@ -1164,16 +1221,17 @@ class Volume(object): raise ValueError("Invalid mode") else: if (os.O_CREAT & flags) == os.O_CREAT: - fd = api.glfs_creat(self.fs, path, flags, 0666) + fd = api.glfs_creat(self.fs, decode_to_bytes(path), + flags, 0o666) else: - fd = api.glfs_open(self.fs, path, flags) + fd = api.glfs_open(self.fs, decode_to_bytes(path), flags) if not fd: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) return File(fd, path=path, mode=mode) @validate_mount - def open(self, path, flags, mode=0777): + def open(self, path, flags, mode=0o777): """ Similar to Python's os.open() @@ -1193,9 +1251,9 @@ class Volume(object): raise TypeError("flags must evaluate to an integer") if (os.O_CREAT & flags) == os.O_CREAT: - fd = api.glfs_creat(self.fs, path, flags, mode) + fd = api.glfs_creat(self.fs, decode_to_bytes(path), flags, mode) else: - fd = api.glfs_open(self.fs, path, flags) + fd = api.glfs_open(self.fs, decode_to_bytes(path), flags) if not fd: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1213,7 +1271,7 @@ class Volume(object): :returns: Returns a instance of Dir class :raises: OSError on failure """ - fd = api.glfs_opendir(self.fs, path) + fd = api.glfs_opendir(self.fs, decode_to_bytes(path)) if not fd: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1231,11 +1289,11 @@ class Volume(object): """ PATH_MAX = 4096 buf = ctypes.create_string_buffer(PATH_MAX) - ret = api.glfs_readlink(self.fs, path, buf, PATH_MAX) + ret = api.glfs_readlink(self.fs, decode_to_bytes(path), buf, PATH_MAX) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) - return buf.value[:ret] + return encode_to_string(buf.value[:ret]) def remove(self, path): """ @@ -1255,7 +1313,8 @@ class Volume(object): :param key: The key of extended attribute. :raises: OSError on failure """ - ret = api.glfs_removexattr(self.fs, path, key) + ret = api.glfs_removexattr(self.fs, decode_to_bytes(path), + decode_to_bytes(key)) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1269,7 +1328,8 @@ class Volume(object): :raises: OSError on failure """ - ret = api.glfs_rename(self.fs, src, dst) + ret = api.glfs_rename(self.fs, decode_to_bytes(src), + decode_to_bytes(dst)) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1283,7 +1343,7 @@ class Volume(object): :raises: OSError on failure """ - ret = api.glfs_rmdir(self.fs, path) + ret = api.glfs_rmdir(self.fs, decode_to_bytes(path)) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1377,7 +1437,9 @@ class Volume(object): :raises: OSError on failure """ - ret = api.glfs_setxattr(self.fs, path, key, value, len(value), flags) + ret = api.glfs_setxattr(self.fs, decode_to_bytes(path), + decode_to_bytes(key), decode_to_bytes(value), + len(decode_to_bytes(value)), flags) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1390,7 +1452,7 @@ class Volume(object): :raises: OSError on failure """ s = api.Stat() - rc = api.glfs_stat(self.fs, path, ctypes.byref(s)) + rc = api.glfs_stat(self.fs, decode_to_bytes(path), ctypes.byref(s)) if rc < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1411,7 +1473,7 @@ class Volume(object): :raises: OSError on failure """ s = api.Statvfs() - rc = api.glfs_statvfs(self.fs, path, ctypes.byref(s)) + rc = api.glfs_statvfs(self.fs, decode_to_bytes(path), ctypes.byref(s)) if rc < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1424,7 +1486,8 @@ class Volume(object): :raises: OSError on failure """ - ret = api.glfs_link(self.fs, source, link_name) + ret = api.glfs_link(self.fs, decode_to_bytes(source), + decode_to_bytes(link_name)) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1436,7 +1499,8 @@ class Volume(object): :raises: OSError on failure """ - ret = api.glfs_symlink(self.fs, source, link_name) + ret = api.glfs_symlink(self.fs, decode_to_bytes(source), + decode_to_bytes(link_name)) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1448,7 +1512,7 @@ class Volume(object): :raises: OSError on failure """ - ret = api.glfs_unlink(self.fs, path) + ret = api.glfs_unlink(self.fs, decode_to_bytes(path)) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1486,7 +1550,7 @@ class Volume(object): timespec_array[1].tv_sec = int(whole) timespec_array[1].tv_nsec = int(decimal * 1e9) - ret = api.glfs_utimens(self.fs, path, timespec_array) + ret = api.glfs_utimens(self.fs, decode_to_bytes(path), timespec_array) if ret < 0: err = ctypes.get_errno() raise OSError(err, os.strerror(err)) @@ -1727,6 +1791,7 @@ class Volume(object): self.makedirs(dst) errors = [] for (name, st) in names_with_stat: + name = encode_to_string(name) if name in ignored_names: continue srcpath = os.path.join(src, name) diff --git a/setup.py b/setup.py index b1645ea..853515c 100644 --- a/setup.py +++ b/setup.py @@ -51,8 +51,11 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Topic :: System :: Filesystems', ], ) diff --git a/test/__init__.py b/test/__init__.py index b00eb23..4186ad0 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -9,7 +9,10 @@ # cases as published by the Free Software Foundation. import os -import ConfigParser +try: + from configparser import ConfigParser +except ImportError: + from ConfigParser import ConfigParser def get_test_config(): @@ -22,7 +25,7 @@ def get_test_config(): dirname = os.path.dirname(__file__) conf_file = dirname + "/test.conf" if os.path.exists(conf_file): - config = ConfigParser.ConfigParser() + config = ConfigParser() config.read(conf_file) return config return None diff --git a/test/functional/libgfapi-python-tests.py b/test/functional/libgfapi-python-tests.py index a64dbc2..be2801f 100644 --- a/test/functional/libgfapi-python-tests.py +++ b/test/functional/libgfapi-python-tests.py @@ -8,8 +8,11 @@ # later), or the GNU General Public License, version 2 (GPLv2), in all # cases as published by the Free Software Foundation. +from __future__ import unicode_literals + import unittest import os +import sys import stat import types import errno @@ -18,13 +21,18 @@ import threading import uuid from nose import SkipTest from test import get_test_config -from ConfigParser import NoSectionError, NoOptionError +try: + from configparser import NoSectionError, NoOptionError +except ImportError: + from ConfigParser import NoSectionError, NoOptionError from uuid import uuid4 from gluster.gfapi.api import Stat from gluster.gfapi import File, Volume, DirEntry from gluster.gfapi.exceptions import LibgfapiException, Error +PY3 = sys.version_info >= (3, 0) + config = get_test_config() if config: try: @@ -66,7 +74,7 @@ class BinFileOpsTest(unittest.TestCase): payload = bytearray(data, "ascii") path = self._testMethodName + ".io" with File(self.vol.open(path, - os.O_CREAT | os.O_WRONLY | os.O_EXCL, 0644)) as f: + os.O_CREAT | os.O_WRONLY | os.O_EXCL, 0o644)) as f: f.write(payload) # Read binary data with File(self.vol.open(path, os.O_RDONLY)) as f: @@ -94,10 +102,10 @@ class FileOpsTest(unittest.TestCase): cls.vol = None def setUp(self): - self.data = "gluster is awesome" + self.data = b"gluster is awesome" self.path = self._testMethodName + ".io" with File(self.vol.open(self.path, - os.O_CREAT | os.O_WRONLY | os.O_EXCL, 0644), + os.O_CREAT | os.O_WRONLY | os.O_EXCL, 0o644), path=self.path) as f: rc = f.write(self.data) self.assertEqual(rc, len(self.data)) @@ -112,7 +120,7 @@ class FileOpsTest(unittest.TestCase): with File(self.vol.open(self.path, os.O_RDONLY)) as f: self.assertTrue(isinstance(f, File)) buf = f.read(len(self.data)) - self.assertFalse(isinstance(buf, types.IntType)) + self.assertFalse(isinstance(buf, int)) self.assertEqual(buf, self.data) def test_open_file_not_exist(self): @@ -171,11 +179,11 @@ class FileOpsTest(unittest.TestCase): def test_fopen(self): # Default permission should be 0666 name = uuid4().hex - data = "Gluster is so awesome" + data = b"Gluster is so awesome" with self.vol.fopen(name, 'w') as f: f.write(data) - perms = self.vol.stat(name).st_mode & 0777 - self.assertEqual(perms, int(0666)) + perms = self.vol.stat(name).st_mode & 0o777 + self.assertEqual(perms, int(0o666)) # 'r': Open file for reading. # If not specified, mode should default to 'r' @@ -218,18 +226,18 @@ class FileOpsTest(unittest.TestCase): with self.vol.fopen(name, 'a') as f: self.assertEqual('a', f.mode) # This should be appended at the end - f.write("hello") + f.write(b"hello") with self.vol.fopen(name) as f: - self.assertEqual(f.read(), data + "hello") + self.assertEqual(f.read(), data + b"hello") # 'a+': Open for reading and appending (writing at end of file) with self.vol.fopen(name, 'a+') as f: self.assertEqual('a+', f.mode) # This should be appended at the end - f.write(" world") + f.write(b" world") f.fsync() f.lseek(0, os.SEEK_SET) - self.assertEqual(f.read(), data + "hello world") + self.assertEqual(f.read(), data + b"hello world") def test_fopen_in_thread(self): def gluster_fopen(): @@ -256,7 +264,7 @@ class FileOpsTest(unittest.TestCase): def test_write_file_dup_lseek_read(self): try: f = File(self.vol.open("dune", os.O_CREAT | os.O_EXCL | os.O_RDWR)) - f.write("I must not fear. Fear is the mind-killer.") + f.write(b"I must not fear. Fear is the mind-killer.") fdup = f.dup() self.assertTrue(isinstance(fdup, File)) f.close() @@ -264,13 +272,13 @@ class FileOpsTest(unittest.TestCase): self.assertEqual(ret, 0) buf = fdup.read(15) - self.assertEqual(buf, "I must not fear") + self.assertEqual(buf, b"I must not fear") ret = fdup.lseek(29, os.SEEK_SET) self.assertEqual(ret, 29) buf = fdup.read(11) - self.assertEqual(buf, "mind-killer") + self.assertEqual(buf, b"mind-killer") fdup.close() except OSError as e: @@ -278,12 +286,18 @@ class FileOpsTest(unittest.TestCase): def test_chmod(self): stat = self.vol.stat(self.path) - orig_mode = oct(stat.st_mode & 0777) - self.assertEqual(orig_mode, '0644L') - self.vol.chmod(self.path, 0600) + orig_mode = oct(stat.st_mode & 0o777) + if PY3: + self.assertEqual(orig_mode, '0o644') + else: + self.assertEqual(orig_mode, '0644L') + self.vol.chmod(self.path, 0o600) stat = self.vol.stat(self.path) - new_mode = oct(stat.st_mode & 0777) - self.assertEqual(new_mode, '0600L') + new_mode = oct(stat.st_mode & 0o777) + if PY3: + self.assertEqual(new_mode, '0o600') + else: + self.assertEqual(new_mode, '0600L') def test_exists(self): e = self.vol.exists(self.path) @@ -317,7 +331,7 @@ class FileOpsTest(unittest.TestCase): def test_lstat(self): sb = self.vol.lstat(self.path) - self.assertFalse(isinstance(sb, types.IntType)) + self.assertFalse(isinstance(sb, int)) self.assertEqual(sb.st_size, len(self.data)) def test_rename(self): @@ -333,7 +347,7 @@ class FileOpsTest(unittest.TestCase): def test_stat(self): sb = self.vol.stat(self.path) - self.assertFalse(isinstance(sb, types.IntType)) + self.assertFalse(isinstance(sb, int)) self.assertEqual(sb.st_size, len(self.data)) def test_unlink(self): @@ -461,14 +475,14 @@ class FileOpsTest(unittest.TestCase): def test_ftruncate(self): name = uuid4().hex with File(self.vol.open(name, os.O_WRONLY | os.O_CREAT)) as f: - f.write("123456789") + f.write(b"123456789") f.ftruncate(5) f.fsync() with File(self.vol.open(name, os.O_RDONLY)) as f: # The size should be reduced self.assertEqual(f.fgetsize(), 5) # So should be the content. - self.assertEqual(f.read(), "12345") + self.assertEqual(f.read(), b"12345") def test_fallocate(self): name = uuid4().hex @@ -492,15 +506,15 @@ class FileOpsTest(unittest.TestCase): def test_zerofill(self): name = uuid4().hex with File(self.vol.open(name, os.O_RDWR | os.O_CREAT)) as f: - f.write('0123456789') + f.write(b'0123456789') f.fsync() self.assertEqual(f.fstat().st_size, 10) f.lseek(0, os.SEEK_SET) - self.assertEqual(f.read(), '0123456789') + self.assertEqual(f.read(), b'0123456789') f.zerofill(3, 6) f.lseek(0, os.SEEK_SET) data = f.read() - self.assertEqual(data, '012\x00\x00\x00\x00\x00\x009') + self.assertEqual(data, b'012\x00\x00\x00\x00\x00\x009') self.assertEqual(len(data), 10) def test_utime(self): @@ -589,17 +603,20 @@ class FileOpsTest(unittest.TestCase): def test_readinto(self): file_name = uuid4().hex with File(self.vol.open(file_name, os.O_WRONLY | os.O_CREAT)) as f: - s = ''.join([str(i) for i in xrange(10)]) - f.write(s) + s = ''.join([str(i) for i in range(10)]) + f.write(bytearray(s, "ascii")) f.fsync() buf = bytearray(1) with File(self.vol.open(file_name, os.O_RDONLY)) as f: - for i in xrange(10): + for i in range(10): # Read one character at a time into buf f.readinto(buf) self.assertEqual(len(buf), 1) - self.assertEqual(buf, bytearray(str(i))) + if PY3: + self.assertEqual(buf, bytes(str(i), 'ascii')) + else: + self.assertEqual(buf, bytearray(str(i))) with File(self.vol.open(file_name, os.O_RDONLY)) as f: self.assertRaises(TypeError, f.readinto, str("buf")) @@ -622,7 +639,7 @@ class FileOpsTest(unittest.TestCase): # Create source file. src_file = uuid4().hex with self.vol.fopen(src_file, 'wb') as f: - for i in xrange(2): + for i in range(2): f.write(os.urandom(128 * 1024)) f.write(os.urandom(25 * 1024)) # Change/set atime and mtime @@ -697,11 +714,11 @@ class FileOpsTest(unittest.TestCase): def test_copymode(self): src_file = uuid4().hex self.vol.fopen(src_file, 'w').close() - self.vol.chmod(src_file, 0644) + self.vol.chmod(src_file, 0o644) dest_file = uuid4().hex self.vol.fopen(dest_file, 'w').close() - self.vol.chmod(dest_file, 0640) + self.vol.chmod(dest_file, 0o640) self.vol.copymode(src_file, dest_file) self.assertEqual(self.vol.stat(src_file).st_mode, @@ -711,7 +728,7 @@ class FileOpsTest(unittest.TestCase): # Create source file and set mode, atime, mtime src_file = uuid4().hex self.vol.fopen(src_file, 'w').close() - self.vol.chmod(src_file, 0640) + self.vol.chmod(src_file, 0o640) (atime, mtime) = (692884800, 692884800) self.vol.utime(src_file, (atime, mtime)) @@ -733,7 +750,7 @@ class FileOpsTest(unittest.TestCase): # Create source file. src_file = uuid4().hex with self.vol.fopen(src_file, 'wb') as f: - for i in xrange(2): + for i in range(2): f.write(os.urandom(128 * 1024)) f.write(os.urandom(25 * 1024)) @@ -766,7 +783,7 @@ class FileOpsTest(unittest.TestCase): # Create source file. src_file = uuid4().hex with self.vol.fopen(src_file, 'wb') as f: - for i in xrange(2): + for i in range(2): f.write(os.urandom(128 * 1024)) f.write(os.urandom(25 * 1024)) (atime, mtime) = (692884800, 692884800) @@ -820,7 +837,7 @@ class DirOpsTest(unittest.TestCase): # Create a filesystem tree self.data = "gluster is awesome" self.dir_path = self._testMethodName + "_dir" - self.vol.mkdir(self.dir_path, 0755) + self.vol.mkdir(self.dir_path, 0o755) for x in range(0, 3): d = os.path.join(self.dir_path, 'testdir' + str(x)) self.vol.mkdir(d) @@ -926,23 +943,21 @@ class DirOpsTest(unittest.TestCase): def test_makedirs(self): name = self.dir_path + "/subd1/subd2/subd3" - self.vol.makedirs(name, 0755) + self.vol.makedirs(name, 0o755) self.assertTrue(self.vol.isdir(name)) def test_statvfs(self): sb = self.vol.statvfs("/") - self.assertFalse(isinstance(sb, types.IntType)) - self.assertEqual(sb.f_namemax, 255L) + self.assertFalse(isinstance(sb, int)) + self.assertEqual(sb.f_namemax, 255) # creating a dir, checking Total number of free inodes # is reduced - self.vol.makedirs("statvfs_dir1", 0755) + self.vol.makedirs("statvfs_dir1", 0o755) sb2 = self.vol.statvfs("/") self.assertTrue(sb2.f_ffree < sb.f_ffree) def test_rmtree(self): - """ - by testing rmtree, we are also testing unlink and rmdir - """ + # By testing rmtree, we are also testing unlink and rmdir f = os.path.join(self.dir_path, "testdir0", "nestedfile0") self.vol.exists(f) d = os.path.join(self.dir_path, "testdir0") diff --git a/test/unit/gluster/test_gfapi.py b/test/unit/gluster/test_gfapi.py index 4216f96..d35d7e1 100644 --- a/test/unit/gluster/test_gfapi.py +++ b/test/unit/gluster/test_gfapi.py @@ -8,6 +8,8 @@ # later), or the GNU General Public License, version 2 (GPLv2), in all # cases as published by the Free Software Foundation. +from __future__ import unicode_literals + import unittest import gluster import inspect @@ -22,7 +24,6 @@ from gluster.gfapi import api from gluster.gfapi.exceptions import LibgfapiException from nose import SkipTest from mock import Mock, MagicMock, patch -from contextlib import nested def _mock_glfs_close(fd): @@ -105,14 +106,14 @@ class TestFile(unittest.TestCase): mock_glfs_fchmod.return_value = 0 with patch("gluster.gfapi.api.glfs_fchmod", mock_glfs_fchmod): - self.fd.fchmod(0600) + self.fd.fchmod(0o600) def test_fchmod_fail_exception(self): mock_glfs_fchmod = Mock() mock_glfs_fchmod.return_value = -1 with patch("gluster.gfapi.api.glfs_fchmod", mock_glfs_fchmod): - self.assertRaises(OSError, self.fd.fchmod, 0600) + self.assertRaises(OSError, self.fd.fchmod, 0o600) def test_fchown_success(self): mock_glfs_fchown = Mock() @@ -169,6 +170,7 @@ class TestFile(unittest.TestCase): def test_fsync_success(self): mock_glfs_fsync = Mock() + mock_glfs_fsync.return_value = 0 with patch("gluster.gfapi.api.glfs_fsync", mock_glfs_fsync): self.fd.fsync() @@ -190,12 +192,12 @@ class TestFile(unittest.TestCase): def test_read_success(self): def _mock_glfs_read(fd, rbuf, buflen, flags): - rbuf.value = "hello" + rbuf.value = b"hello" return 5 with patch("gluster.gfapi.api.glfs_read", _mock_glfs_read): b = self.fd.read(5) - self.assertEqual(b, "hello") + self.assertEqual(b, b"hello") def test_read_fail_exception(self): mock_glfs_read = Mock() @@ -311,7 +313,7 @@ class TestDir(unittest.TestCase): with patch("gluster.gfapi.api.glfs_readdir_r", mock_glfs_readdir_r): fd = Dir(2) - ent = fd.next() + ent = next(fd) self.assertTrue(isinstance(ent, api.Dirent)) @@ -387,7 +389,7 @@ class TestVolume(unittest.TestCase): with patch("gluster.gfapi.api.glfs_new", _m_glfs_new): # Mounting for first time v.mount() - _m_glfs_new.assert_called_once_with("vol") + _m_glfs_new.assert_called_once_with(b"vol") _m_glfs_new.reset_mock() for i in range(0, 5): v.mount() @@ -402,7 +404,7 @@ class TestVolume(unittest.TestCase): self.assertRaises(LibgfapiException, v.mount) self.assertFalse(v.fs) self.assertFalse(v.mounted) - _m_glfs_new.assert_called_once_with("vol") + _m_glfs_new.assert_called_once_with(b"vol") # glfs_set_volfile_server() failed _m_set_vol = Mock(return_value=-1) @@ -410,9 +412,9 @@ class TestVolume(unittest.TestCase): with patch("gluster.gfapi.api.glfs_set_volfile_server", _m_set_vol): self.assertRaises(LibgfapiException, v.mount) self.assertFalse(v.mounted) - _m_glfs_new.assert_called_once_with("vol") - _m_set_vol.assert_called_once_with(v.fs, v.protocol, - v.host, v.port) + _m_glfs_new.assert_called_once_with(b"vol") + _m_set_vol.assert_called_once_with(v.fs, v.protocol.encode('utf-8'), + v.host.encode('utf-8'), v.port) # glfs_init() failed _m_glfs_init = Mock(return_value=-1) @@ -433,7 +435,7 @@ class TestVolume(unittest.TestCase): self.assertTrue(v.mounted) def test_set_logging(self): - _m_set_logging = Mock() + _m_set_logging = Mock(return_value=0) # Called after mount() v = Volume("host", "vol") @@ -449,21 +451,21 @@ class TestVolume(unittest.TestCase): _m_set_logging = Mock(return_value=-1) with patch("gluster.gfapi.api.glfs_set_logging", _m_set_logging): self.assertRaises(LibgfapiException, v.set_logging, "/dev/null", 7) - _m_set_logging.assert_called_once_with(v.fs, "/dev/null", 7) + _m_set_logging.assert_called_once_with(v.fs, b"/dev/null", 7) def test_chmod_success(self): mock_glfs_chmod = Mock() mock_glfs_chmod.return_value = 0 with patch("gluster.gfapi.api.glfs_chmod", mock_glfs_chmod): - self.vol.chmod("file.txt", 0600) + self.vol.chmod("file.txt", 0o600) def test_chmod_fail_exception(self): mock_glfs_chmod = Mock() mock_glfs_chmod.return_value = -1 with patch("gluster.gfapi.api.glfs_chmod", mock_glfs_chmod): - self.assertRaises(OSError, self.vol.chmod, "file.txt", 0600) + self.assertRaises(OSError, self.vol.chmod, "file.txt", 0o600) def test_chown_success(self): mock_glfs_chown = Mock() @@ -484,12 +486,12 @@ class TestVolume(unittest.TestCase): mock_glfs_creat.return_value = 2 with patch("gluster.gfapi.api.glfs_creat", mock_glfs_creat): - with File(self.vol.open("file.txt", os.O_CREAT, 0644)) as f: + with File(self.vol.open("file.txt", os.O_CREAT, 0o644)) as f: self.assertTrue(isinstance(f, File)) self.assertEqual(mock_glfs_creat.call_count, 1) mock_glfs_creat.assert_called_once_with(12345, - "file.txt", - os.O_CREAT, 0644) + b"file.txt", + os.O_CREAT, 0o644) def test_exists_true(self): mock_glfs_stat = Mock() @@ -593,12 +595,12 @@ class TestVolume(unittest.TestCase): def test_getxattr_success(self): def mock_glfs_getxattr(fs, path, key, buf, maxlen): - buf.value = "fake_xattr" + buf.value = b"fake_xattr" return 10 with patch("gluster.gfapi.api.glfs_getxattr", mock_glfs_getxattr): buf = self.vol.getxattr("file.txt", "key1", 32) - self.assertEquals("fake_xattr", buf) + self.assertEqual("fake_xattr", buf) def test_getxattr_fail_exception(self): mock_glfs_getxattr = Mock() @@ -613,23 +615,23 @@ class TestVolume(unittest.TestCase): mock_glfs_opendir.return_value = 2 dirent1 = api.Dirent() - dirent1.d_name = "mockfile" + dirent1.d_name = b"mockfile" dirent1.d_reclen = 8 dirent2 = api.Dirent() - dirent2.d_name = "mockdir" + dirent2.d_name = b"mockdir" dirent2.d_reclen = 7 dirent3 = api.Dirent() - dirent3.d_name = "." + dirent3.d_name = b"." dirent3.d_reclen = 1 mock_Dir_next = Mock() mock_Dir_next.side_effect = [dirent1, dirent2, dirent3, StopIteration] - with nested(patch("gluster.gfapi.api.glfs_opendir", - mock_glfs_opendir), - patch("gluster.gfapi.Dir.next", mock_Dir_next)): - d = self.vol.listdir("testdir") - self.assertEqual(len(d), 2) - self.assertEqual(d[0], 'mockfile') + with patch("gluster.gfapi.api.glfs_opendir", mock_glfs_opendir): + with patch("gluster.gfapi.Dir.__next__", mock_Dir_next): + with patch("gluster.gfapi.Dir.next", mock_Dir_next): + d = self.vol.listdir("testdir") + self.assertEqual(len(d), 2) + self.assertEqual(d[0], 'mockfile') def test_listdir_fail_exception(self): mock_glfs_opendir = Mock() @@ -643,17 +645,17 @@ class TestVolume(unittest.TestCase): mock_glfs_opendir.return_value = 2 dirent1 = api.Dirent() - dirent1.d_name = "mockfile" + dirent1.d_name = b"mockfile" dirent1.d_reclen = 8 stat1 = api.Stat() stat1.st_nlink = 1 dirent2 = api.Dirent() - dirent2.d_name = "mockdir" + dirent2.d_name = b"mockdir" dirent2.d_reclen = 7 stat2 = api.Stat() stat2.st_nlink = 2 dirent3 = api.Dirent() - dirent3.d_name = "." + dirent3.d_name = b"." dirent3.d_reclen = 1 stat3 = api.Stat() stat3.n_link = 2 @@ -663,15 +665,15 @@ class TestVolume(unittest.TestCase): (dirent3, stat3), StopIteration] - with nested(patch("gluster.gfapi.api.glfs_opendir", - mock_glfs_opendir), - patch("gluster.gfapi.Dir.next", mock_Dir_next)): - d = self.vol.listdir_with_stat("testdir") - self.assertEqual(len(d), 2) - self.assertEqual(d[0][0], 'mockfile') - self.assertEqual(d[0][1].st_nlink, 1) - self.assertEqual(d[1][0], 'mockdir') - self.assertEqual(d[1][1].st_nlink, 2) + with patch("gluster.gfapi.api.glfs_opendir", mock_glfs_opendir): + with patch("gluster.gfapi.Dir.__next__", mock_Dir_next): + with patch("gluster.gfapi.Dir.next", mock_Dir_next): + d = self.vol.listdir_with_stat("testdir") + self.assertEqual(len(d), 2) + self.assertEqual(d[0][0], 'mockfile') + self.assertEqual(d[0][1].st_nlink, 1) + self.assertEqual(d[1][0], 'mockdir') + self.assertEqual(d[1][1].st_nlink, 2) def test_listdir_with_stat_fail_exception(self): mock_glfs_opendir = Mock() @@ -684,19 +686,19 @@ class TestVolume(unittest.TestCase): mock_glfs_opendir.return_value = 2 dirent1 = api.Dirent() - dirent1.d_name = "mockfile" + dirent1.d_name = b"mockfile" dirent1.d_reclen = 8 stat1 = api.Stat() stat1.st_nlink = 1 stat1.st_mode = 33188 dirent2 = api.Dirent() - dirent2.d_name = "mockdir" + dirent2.d_name = b"mockdir" dirent2.d_reclen = 7 stat2 = api.Stat() stat2.st_nlink = 2 stat2.st_mode = 16877 dirent3 = api.Dirent() - dirent3.d_name = "." + dirent3.d_name = b"." dirent3.d_reclen = 1 stat3 = api.Stat() stat3.n_link = 2 @@ -707,31 +709,31 @@ class TestVolume(unittest.TestCase): (dirent3, stat3), StopIteration] - with nested(patch("gluster.gfapi.api.glfs_opendir", - mock_glfs_opendir), - patch("gluster.gfapi.Dir.next", mock_Dir_next)): - i = 0 - for entry in self.vol.scandir("testdir"): - self.assertTrue(isinstance(entry, DirEntry)) - if entry.name == 'mockfile': - self.assertEqual(entry.path, 'testdir/mockfile') - self.assertTrue(entry.is_file()) - self.assertFalse(entry.is_dir()) - self.assertEqual(entry.stat().st_nlink, 1) - elif entry.name == 'mockdir': - self.assertEqual(entry.path, 'testdir/mockdir') - self.assertTrue(entry.is_dir()) - self.assertFalse(entry.is_file()) - self.assertEqual(entry.stat().st_nlink, 2) - else: - self.fail("Unexpected entry") - i = i + 1 - self.assertEqual(i, 2) + with patch("gluster.gfapi.api.glfs_opendir", mock_glfs_opendir): + with patch("gluster.gfapi.Dir.__next__", mock_Dir_next): + with patch("gluster.gfapi.Dir.next", mock_Dir_next): + i = 0 + for entry in self.vol.scandir("testdir"): + self.assertTrue(isinstance(entry, DirEntry)) + if entry.name == 'mockfile': + self.assertEqual(entry.path, 'testdir/mockfile') + self.assertTrue(entry.is_file()) + self.assertFalse(entry.is_dir()) + self.assertEqual(entry.stat().st_nlink, 1) + elif entry.name == 'mockdir': + self.assertEqual(entry.path, 'testdir/mockdir') + self.assertTrue(entry.is_dir()) + self.assertFalse(entry.is_file()) + self.assertEqual(entry.stat().st_nlink, 2) + else: + self.fail("Unexpected entry") + i = i + 1 + self.assertEqual(i, 2) def test_listxattr_success(self): def mock_glfs_listxattr(fs, path, buf, buflen): if buf: - buf.raw = "key1\0key2\0" + buf.raw = b"key1\0key2\0" return 10 with patch("gluster.gfapi.api.glfs_listxattr", mock_glfs_listxattr): @@ -798,11 +800,11 @@ class TestVolume(unittest.TestCase): mock_exists = Mock() mock_exists.side_effect = (False, True, False) - with nested(patch("gluster.gfapi.api.glfs_mkdir", mock_glfs_mkdir), - patch("gluster.gfapi.Volume.exists", mock_exists)): - self.vol.makedirs("dir1/", 0775) - self.assertEqual(mock_glfs_mkdir.call_count, 1) - mock_glfs_mkdir.assert_any_call(self.vol.fs, "dir1/", 0775) + with patch("gluster.gfapi.api.glfs_mkdir", mock_glfs_mkdir): + with patch("gluster.gfapi.Volume.exists", mock_exists): + self.vol.makedirs("dir1/", 0o775) + self.assertEqual(mock_glfs_mkdir.call_count, 1) + mock_glfs_mkdir.assert_any_call(self.vol.fs, b"dir1/", 0o775) def test_makedirs_success_EEXIST(self): err = errno.EEXIST @@ -812,13 +814,13 @@ class TestVolume(unittest.TestCase): mock_exists = Mock() mock_exists.side_effect = [False, True, False] - with nested(patch("gluster.gfapi.api.glfs_mkdir", mock_glfs_mkdir), - patch("gluster.gfapi.Volume.exists", mock_exists)): - self.vol.makedirs("./dir1/dir2", 0775) - self.assertEqual(mock_glfs_mkdir.call_count, 2) - mock_glfs_mkdir.assert_any_call(self.vol.fs, "./dir1", 0775) - mock_glfs_mkdir.assert_called_with(self.vol.fs, "./dir1/dir2", - 0775) + with patch("gluster.gfapi.api.glfs_mkdir", mock_glfs_mkdir): + with patch("gluster.gfapi.Volume.exists", mock_exists): + self.vol.makedirs("./dir1/dir2", 0o775) + self.assertEqual(mock_glfs_mkdir.call_count, 2) + mock_glfs_mkdir.assert_any_call(self.vol.fs, b"./dir1", 0o775) + mock_glfs_mkdir.assert_called_with(self.vol.fs, b"./dir1/dir2", + 0o775) def test_makedirs_fail_exception(self): mock_glfs_mkdir = Mock() @@ -827,23 +829,23 @@ class TestVolume(unittest.TestCase): mock_exists = Mock() mock_exists.return_value = False - with nested(patch("gluster.gfapi.api.glfs_mkdir", mock_glfs_mkdir), - patch("gluster.gfapi.Volume.exists", mock_exists)): - self.assertRaises(OSError, self.vol.makedirs, "dir1/dir2", 0775) + with patch("gluster.gfapi.api.glfs_mkdir", mock_glfs_mkdir): + with patch("gluster.gfapi.Volume.exists", mock_exists): + self.assertRaises(OSError, self.vol.makedirs, "dir1/dir2", 0o775) def test_mkdir_success(self): mock_glfs_mkdir = Mock() mock_glfs_mkdir.return_value = 0 with patch("gluster.gfapi.api.glfs_mkdir", mock_glfs_mkdir): - self.vol.mkdir("testdir", 0775) + self.vol.mkdir("testdir", 0o775) def test_mkdir_fail_exception(self): mock_glfs_mkdir = Mock() mock_glfs_mkdir.return_value = -1 with patch("gluster.gfapi.api.glfs_mkdir", mock_glfs_mkdir): - self.assertRaises(OSError, self.vol.mkdir, "testdir", 0775) + self.assertRaises(OSError, self.vol.mkdir, "testdir", 0o775) def test_open_with_statement_success(self): mock_glfs_open = Mock() @@ -854,7 +856,7 @@ class TestVolume(unittest.TestCase): self.assertTrue(isinstance(f, File)) self.assertEqual(mock_glfs_open.call_count, 1) mock_glfs_open.assert_called_once_with(12345, - "file.txt", os.O_WRONLY) + b"file.txt", os.O_WRONLY) def test_open_with_statement_fail_exception(self): mock_glfs_open = Mock() @@ -875,7 +877,7 @@ class TestVolume(unittest.TestCase): f = File(self.vol.open("file.txt", os.O_WRONLY)) self.assertTrue(isinstance(f, File)) self.assertEqual(mock_glfs_open.call_count, 1) - mock_glfs_open.assert_called_once_with(12345, "file.txt", + mock_glfs_open.assert_called_once_with(12345, b"file.txt", os.O_WRONLY) def test_open_direct_fail_exception(self): @@ -971,11 +973,11 @@ class TestVolume(unittest.TestCase): mock_rmdir = Mock() mock_islink = Mock(return_value=False) - with nested(patch("gluster.gfapi.Volume.scandir", mock_scandir), - patch("gluster.gfapi.Volume.islink", mock_islink), - patch("gluster.gfapi.Volume.unlink", mock_unlink), - patch("gluster.gfapi.Volume.rmdir", mock_rmdir)): - self.vol.rmtree("dirpath") + with patch("gluster.gfapi.Volume.scandir", mock_scandir): + with patch("gluster.gfapi.Volume.islink", mock_islink): + with patch("gluster.gfapi.Volume.unlink", mock_unlink): + with patch("gluster.gfapi.Volume.rmdir", mock_rmdir): + self.vol.rmtree("dirpath") mock_islink.assert_called_once_with("dirpath") mock_unlink.assert_called_once_with("dirpath/file1") @@ -988,9 +990,9 @@ class TestVolume(unittest.TestCase): mock_islink = Mock() mock_islink.return_value = False - with nested(patch("gluster.gfapi.Volume.scandir", mock_scandir), - patch("gluster.gfapi.Volume.islink", mock_islink)): - self.assertRaises(OSError, self.vol.rmtree, "dir1") + with patch("gluster.gfapi.Volume.scandir", mock_scandir): + with patch("gluster.gfapi.Volume.islink", mock_islink): + self.assertRaises(OSError, self.vol.rmtree, "dir1") def test_rmtree_islink_exception(self): mock_islink = Mock() @@ -1010,11 +1012,11 @@ class TestVolume(unittest.TestCase): mock_rmdir = Mock(side_effect=OSError) mock_islink = Mock(return_value=False) - with nested(patch("gluster.gfapi.Volume.scandir", mock_scandir), - patch("gluster.gfapi.Volume.islink", mock_islink), - patch("gluster.gfapi.Volume.unlink", mock_unlink), - patch("gluster.gfapi.Volume.rmdir", mock_rmdir)): - self.vol.rmtree("dirpath", True) + with patch("gluster.gfapi.Volume.scandir", mock_scandir): + with patch("gluster.gfapi.Volume.islink", mock_islink): + with patch("gluster.gfapi.Volume.unlink", mock_unlink): + with patch("gluster.gfapi.Volume.rmdir", mock_rmdir): + self.vol.rmtree("dirpath", True) mock_islink.assert_called_once_with("dirpath") mock_unlink.assert_called_once_with("dirpath/file1") @@ -1131,14 +1133,14 @@ class TestVolume(unittest.TestCase): m_utime = Mock() m_chmod = Mock() m_copystat = Mock() - with nested(patch("gluster.gfapi.Volume.listdir_with_stat", m_list_s), - patch("gluster.gfapi.Volume.makedirs", m_makedirs), - patch("gluster.gfapi.Volume.fopen", m_fopen), - patch("gluster.gfapi.Volume.copyfileobj", m_copyfileobj), - patch("gluster.gfapi.Volume.utime", m_utime), - patch("gluster.gfapi.Volume.chmod", m_chmod), - patch("gluster.gfapi.Volume.copystat", m_copystat)): - self.vol.copytree('/source', '/destination') + with patch("gluster.gfapi.Volume.listdir_with_stat", m_list_s): + with patch("gluster.gfapi.Volume.makedirs", m_makedirs): + with patch("gluster.gfapi.Volume.fopen", m_fopen): + with patch("gluster.gfapi.Volume.copyfileobj", m_copyfileobj): + with patch("gluster.gfapi.Volume.utime", m_utime): + with patch("gluster.gfapi.Volume.chmod", m_chmod): + with patch("gluster.gfapi.Volume.copystat", m_copystat): + self.vol.copytree('/source', '/destination') # Assert that listdir_with_stat() was called on all directories self.assertEqual(m_list_s.call_count, 3 + 1) @@ -1176,7 +1178,7 @@ class TestVolume(unittest.TestCase): with patch("gluster.gfapi.api.glfs_utimens", mock_glfs_utimens): self.vol.utime('/path', (atime, mtime)) self.assertTrue(mock_glfs_utimens.called) - self.assertEqual(mock_glfs_utimens.call_args[0][1], '/path') + self.assertEqual(mock_glfs_utimens.call_args[0][1], b'/path') # verify atime and mtime self.assertEqual(mock_glfs_utimens.call_args[0][2][0].tv_sec, int(atime)) diff --git a/tox.ini b/tox.ini index b9213ba..b702b3a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py26,py27,pep8 +envlist = py26,py27,py36,pep8 minversion = 1.6 [testenv] @@ -14,7 +14,15 @@ deps = commands = nosetests -v {posargs:test/unit} [testenv:functest] -commands = ./.functests {posargs} +commands = nosetests -s -v {posargs:test/functional} + +[testenv:functest27] +basepython = python2.7 +commands = nosetests -s -v {posargs:test/functional} + +[testenv:functest36] +basepython = python3.6 +commands = nosetests -s -v {posargs:test/functional} [testenv:pep8] commands = -- cgit