From bbe395767ae844dc9ffb500f0689aca0e2aa1813 Mon Sep 17 00:00:00 2001 From: Zhou Cheng Date: Thu, 7 Mar 2024 12:34:09 +0800 Subject: [PATCH] CI: revert multi client test from posix random test. (#4457) --- .github/scripts/hypo/common.py | 6 +- .github/scripts/hypo/fs_op.py | 141 +++++---- .github/scripts/hypo/fsrand2.py | 452 +++++++++++---------------- .github/scripts/hypo/fsrand2_test.py | 112 ++++++- .github/scripts/hypo/strategy.py | 2 +- .github/workflows/fsrand2.yml | 7 +- 6 files changed, 379 insertions(+), 341 deletions(-) diff --git a/.github/scripts/hypo/common.py b/.github/scripts/hypo/common.py index 1436e56c3432..0c77db184d8f 100644 --- a/.github/scripts/hypo/common.py +++ b/.github/scripts/hypo/common.py @@ -104,19 +104,17 @@ def support_acl(path): with open(file, 'r') as f: config = json.load(f) if config['Meta'].get('Args', '').find('--enable-acl') != -1: - # print(f"{path} has enabled ACL.") + return True + elif config['Format'].get('EnableACL', False): return True else: - # print(f"{path} does not have enabled ACL.") return False else: mount_point = subprocess.check_output(["df", root]).decode("utf-8").splitlines()[-1].split()[0] mount_options = subprocess.check_output(["sudo", "tune2fs", "-l", mount_point]).decode("utf-8") if "acl" not in mount_options: - # print(f"{path} does not have enabled ACL.") return False else: - # print(f"{path} has enabled ACL.") return True def get_stat(path): diff --git a/.github/scripts/hypo/fs_op.py b/.github/scripts/hypo/fs_op.py index b3566ecefe03..bb42cd51ab15 100644 --- a/.github/scripts/hypo/fs_op.py +++ b/.github/scripts/hypo/fs_op.py @@ -41,11 +41,11 @@ def get(self): class FsOperation: JFS_CONTROL_FILES=['.accesslog', '.config', '.stats'] stats = Statistics() - def __init__(self, logger: logging.Logger): - self.logger = logger + def __init__(self, loggers: Dict[str, logging.Logger]): + self.loggers = loggers def run_cmd(self, command:str, root_dir:str) -> str: - self.logger.info(f'run_cmd: {command}') + self.loggers[root_dir].info(f'run_cmd: {command}') if '|' in command or '>' in command or '&' in command: ret=os.system(command) if ret == 0: @@ -73,11 +73,11 @@ def handleException(self, e, root_dir, action, path, **kwargs): if err.find('setfacl') != -1 and err.find('\n') != -1: err = '\n'.join(sorted(err.split('\n'))) self.stats.failure(action) - self.logger.info(f'{action} {path} {kwargs} failed: {err}') + self.loggers[root_dir].info(f'{action} {path} {kwargs} failed: {err}') return Exception(err) def do_open(self, root_dir, file, flags, mask, mode, user): - self.logger.debug(f'do_open {root_dir} {file} {flags} {mode} {user}') + self.loggers[root_dir].debug(f'do_open {root_dir} {file} {flags} {mode} {user}') abspath = os.path.join(root_dir, file) flag = 0 fd = -1 @@ -96,11 +96,11 @@ def do_open(self, root_dir, file, flags, mask, mode, user): if fd > 0: os.close(fd) self.stats.success('do_open') - self.logger.info(f'do_open {abspath} {flags} {mode} succeed') + self.loggers[root_dir].info(f'do_open {abspath} {flags} {mode} succeed') return get_stat(abspath) def do_write(self, root_dir, file, offset, content, flags, whence, user): - self.logger.debug(f'do_write {root_dir} {file} {offset}') + self.loggers[root_dir].debug(f'do_write {root_dir} {file} {offset}') abspath = os.path.join(root_dir, file) fd = -1 flag = 0 @@ -124,12 +124,12 @@ def do_write(self, root_dir, file, offset, content, flags, whence, user): os.seteuid(0) os.setegid(0) self.stats.success('do_write') - self.logger.info(f'do_write {abspath} {offset} succeed') + self.loggers[root_dir].info(f'do_write {abspath} {offset} succeed') return get_stat(abspath) def do_fallocate(self, root_dir, file, offset, length, mode, user): - self.logger.debug(f'do_fallocate {root_dir} {file} {offset} {length} {mode}') + self.loggers[root_dir].debug(f'do_fallocate {root_dir} {file} {offset} {length} {mode}') abspath = os.path.join(root_dir, file) fd = -1 try: @@ -149,12 +149,12 @@ def do_fallocate(self, root_dir, file, offset, length, mode, user): os.seteuid(0) os.setegid(0) self.stats.success('do_fallocate') - self.logger.info(f'do_fallocate {abspath} {offset} {length} {mode} succeed') + self.loggers[root_dir].info(f'do_fallocate {abspath} {offset} {length} {mode} succeed') return get_stat(abspath) def do_read(self, root_dir, file, offset, length, user): - self.logger.debug(f'do_read {root_dir} {file} {offset} {length}') + self.loggers[root_dir].debug(f'do_read {root_dir} {file} {offset} {length}') abspath = os.path.join(root_dir, file) fd = -1 try: @@ -176,11 +176,11 @@ def do_read(self, root_dir, file, offset, length, user): os.seteuid(0) os.setegid(0) self.stats.success('do_read') - self.logger.info(f'do_read {abspath} {offset} {length} succeed') + self.loggers[root_dir].info(f'do_read {abspath} {offset} {length} succeed') return (md5sum, ) def do_truncate(self, root_dir, file, size, user): - self.logger.debug(f'do_truncate {root_dir} {file} {size}') + self.loggers[root_dir].debug(f'do_truncate {root_dir} {file} {size}') abspath = os.path.join(root_dir, file) fd = -1 try: @@ -195,7 +195,7 @@ def do_truncate(self, root_dir, file, size, user): os.seteuid(0) os.setegid(0) self.stats.success('do_truncate') - self.logger.info(f'do_truncate {abspath} {size} succeed') + self.loggers[root_dir].info(f'do_truncate {abspath} {size} succeed') return get_stat(abspath) def do_create_file(self, root_dir, parent, file_name, mode, content, user, umask): @@ -214,7 +214,7 @@ def do_create_file(self, root_dir, parent, file_name, mode, content, user, umask os.umask(old_umask) assert os.path.isfile(abspath), f'do_create_file: {abspath} with mode {mode} should be file' self.stats.success('do_create_file') - self.logger.info(f'do_create_file {abspath} with mode {mode} succeed') + self.loggers[root_dir].info(f'do_create_file {abspath} with mode {mode} succeed') return get_stat(abspath) def do_mkfifo(self, root_dir, parent, file_name, mode, user, umask): @@ -232,7 +232,7 @@ def do_mkfifo(self, root_dir, parent, file_name, mode, user, umask): assert os.path.exists(abspath), f'do_mkfifo: {abspath} should exist' assert stat.S_ISFIFO(os.stat(abspath).st_mode), f'do_mkfifo: {abspath} should be fifo' self.stats.success('do_mkfifo') - self.logger.info(f'do_mkfifo {abspath} succeed') + self.loggers[root_dir].info(f'do_mkfifo {abspath} succeed') return get_stat(abspath) def do_listdir(self, root_dir, dir, user): @@ -247,7 +247,7 @@ def do_listdir(self, root_dir, dir, user): os.seteuid(0) os.setegid(0) self.stats.success('do_listdir') - self.logger.info(f'do_listdir {abspath} succeed') + self.loggers[root_dir].info(f'do_listdir {abspath} succeed') return tuple(li) def do_unlink(self, root_dir, file, user): @@ -262,7 +262,7 @@ def do_unlink(self, root_dir, file, user): os.setegid(0) assert not os.path.exists(abspath), f'do_unlink: {abspath} should not exist' self.stats.success('do_unlink') - self.logger.info(f'do_unlink {abspath} succeed') + self.loggers[root_dir].info(f'do_unlink {abspath} succeed') return () def do_rename(self, root_dir, entry, parent, new_entry_name, user, umask): @@ -283,7 +283,7 @@ def do_rename(self, root_dir, entry, parent, new_entry_name, user, umask): # assert not os.path.exists(abspath), f'do_rename: {abspath} should not exist' assert os.path.lexists(new_abspath), f'do_rename: {new_abspath} should exist' self.stats.success('do_rename') - self.logger.info(f'do_rename {abspath} {new_abspath} succeed') + self.loggers[root_dir].info(f'do_rename {abspath} {new_abspath} succeed') return get_stat(new_abspath) def do_copy_file(self, root_dir, entry, parent, new_entry_name, follow_symlinks, user, umask): @@ -302,7 +302,7 @@ def do_copy_file(self, root_dir, entry, parent, new_entry_name, follow_symlinks, os.umask(old_umask) assert os.path.lexists(new_abspath), f'do_copy_file: {new_abspath} should exist' self.stats.success('do_copy_file') - self.logger.info(f'do_copy_file {abspath} {new_abspath} succeed') + self.loggers[root_dir].info(f'do_copy_file {abspath} {new_abspath} succeed') return get_stat(new_abspath) def do_clone_entry(self, root_dir:str, entry, parent, new_entry_name, preserve, user='root', umask=0o022, mount='cmd/mount/mount'): @@ -327,7 +327,7 @@ def do_clone_entry(self, root_dir:str, entry, parent, new_entry_name, preserve, os.umask(old_umask) assert os.path.lexists(new_abspath), f'do_clone_entry: {new_abspath} should exist' self.stats.success('do_clone_entry') - self.logger.info(f'do_clone_entry {abspath} {new_abspath} succeed') + self.loggers[root_dir].info(f'do_clone_entry {abspath} {new_abspath} succeed') return get_stat(new_abspath) def do_copy_tree(self, root_dir, entry, parent, new_entry_name, symlinks, ignore_dangling_symlinks, dir_exist_ok, user, umask): @@ -349,7 +349,7 @@ def do_copy_tree(self, root_dir, entry, parent, new_entry_name, symlinks, ignore os.umask(old_mask) assert os.path.lexists(new_abspath), f'do_copy_tree: {new_abspath} should exist' self.stats.success('do_copy_tree') - self.logger.info(f'do_copy_tree {abspath} {new_abspath} succeed') + self.loggers[root_dir].info(f'do_copy_tree {abspath} {new_abspath} succeed') return get_stat(new_abspath) def do_mkdir(self, root_dir, parent, subdir, mode, user, umask): @@ -367,7 +367,7 @@ def do_mkdir(self, root_dir, parent, subdir, mode, user, umask): os.umask(old_mask) assert os.path.isdir(abspath), f'do_mkdir: {abspath} should be dir' self.stats.success('do_mkdir') - self.logger.info(f'do_mkdir {abspath} with mode {oct(mode)} succeed') + self.loggers[root_dir].info(f'do_mkdir {abspath} with mode {oct(mode)} succeed') return get_stat(abspath) def do_rmdir(self, root_dir, dir, user ): @@ -382,7 +382,7 @@ def do_rmdir(self, root_dir, dir, user ): os.setegid(0) assert not os.path.exists(abspath), f'do_rmdir: {abspath} should not exist' self.stats.success('do_rmdir') - self.logger.info(f'do_rmdir {abspath} succeed') + self.loggers[root_dir].info(f'do_rmdir {abspath} succeed') return () def do_hardlink(self, root_dir, dest_file, parent, link_file_name, user, umask): @@ -403,7 +403,7 @@ def do_hardlink(self, root_dir, dest_file, parent, link_file_name, user, umask): # time.sleep(0.005) assert os.path.lexists(link_abs_path), f'do_hardlink: {link_abs_path} should exist' self.stats.success('do_hardlink') - self.logger.info(f'do_hardlink {dest_abs_path} {link_abs_path} succeed') + self.loggers[root_dir].info(f'do_hardlink {dest_abs_path} {link_abs_path} succeed') return get_stat(link_abs_path) def do_symlink(self, root_dir, dest_file, parent, link_file_name, user, umask): @@ -423,7 +423,7 @@ def do_symlink(self, root_dir, dest_file, parent, link_file_name, user, umask): os.umask(old_mask) assert os.path.islink(link_abs_path), f'do_symlink: {link_abs_path} should be link' self.stats.success('do_symlink') - self.logger.info(f'do_symlink {dest_abs_path} {link_abs_path} succeed') + self.loggers[root_dir].info(f'do_symlink {dest_abs_path} {link_abs_path} succeed') return get_stat(link_abs_path) def do_set_xattr(self, root_dir, file, name, value, flag, user): @@ -438,10 +438,30 @@ def do_set_xattr(self, root_dir, file, name, value, flag, user): os.seteuid(0) os.setegid(0) self.stats.success('do_set_xattr') - self.logger.info(f"do_set_xattr {abspath} user.{name} {value} {flag} succeed") + self.loggers[root_dir].info(f"do_set_xattr {abspath} user.{name} {value} {flag} succeed") v = xattr.getxattr(abspath, 'user.'+name) return (v,) - + + def do_list_xattr(self, root_dir, file, user): + abspath = os.path.join(root_dir, file) + xattr_list = [] + try: + self.seteuid(user) + xattrs = xattr.listxattr(abspath) + xattr_list = [] + for attr in xattrs: + value = xattr.getxattr(abspath, attr) + xattr_list.append((attr, value)) + xattr_list.sort() # Sort the list based on xattr names + except Exception as e: + return self.handleException(e, root_dir, 'do_list_xattr', abspath, user=user) + finally: + os.seteuid(0) + os.setegid(0) + self.stats.success('do_list_xattr') + self.loggers[f'{root_dir}'].info(f"do_list_xattr {abspath} succeed") + return xattr_list + def do_remove_xattr(self, root_dir, file, user): abspath = os.path.join(root_dir, file) try: @@ -459,19 +479,19 @@ def do_remove_xattr(self, root_dir, file, user): os.seteuid(0) os.setegid(0) self.stats.success('do_remove_xattr') - self.logger.info(f"do_remove_xattr {abspath} {name} succeed") + self.loggers[f'{root_dir}'].info(f"do_remove_xattr {abspath} {name} succeed") assert name not in xattr.listxattr(abspath), f'do_remove_xattr: {name} should not in xattr list' return tuple(sorted(xattr.listxattr(abspath))) - def do_change_groups(self, user, group, groups): + def do_change_groups(self, root_dir, user, group, groups): try: subprocess.run(['usermod', '-g', group, '-G', ",".join(groups), user], check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: self.stats.failure('do_change_groups') - self.logger.info(f"do_change_groups {user} {group} {groups} failed: {e.output.decode()}") + self.loggers[root_dir].info(f"do_change_groups {user} {group} {groups} failed: {e.output.decode()}") return self.stats.success('do_change_groups') - self.logger.info(f"do_change_groups {user} {group} {groups} succeed") + self.loggers[root_dir].info(f"do_change_groups {user} {group} {groups} succeed") def do_chmod(self, root_dir, entry, mode, user): abspath = os.path.join(root_dir, entry) @@ -485,19 +505,17 @@ def do_chmod(self, root_dir, entry, mode, user): os.seteuid(0) os.setegid(0) self.stats.success('do_chmod') - self.logger.info(f"do_chmod {abspath} {oct(mode)} {user} succeed") + self.loggers[root_dir].info(f"do_chmod {abspath} {oct(mode)} {user} succeed") return get_stat(abspath) def do_get_acl(self, root_dir: str, entry: str): abspath = os.path.join(root_dir, entry) - print(f'ls {abspath}') - os.system(f'ls {abspath}') try: acl = get_acl(abspath) except Exception as e: return self.handleException(e, root_dir, 'do_get_acl', abspath) self.stats.success('do_get_acl') - self.logger.info(f"do_get_acl {abspath} succeed") + self.loggers[f'{root_dir}'].info(f"do_get_acl {abspath} succeed") return acl def do_remove_acl(self, root_dir: str, entry: str, option: str, user: str): @@ -507,7 +525,7 @@ def do_remove_acl(self, root_dir: str, entry: str, option: str, user: str): except subprocess.CalledProcessError as e: return self.handleException(e, root_dir, 'do_remove_acl', abspath, option=option,user=user) self.stats.success('do_remove_acl') - self.logger.info(f"do_remove_acl {abspath} with {option} succeed") + self.loggers[root_dir].info(f"do_remove_acl {abspath} with {option} succeed") return get_acl(abspath) def do_set_acl(self, root_dir, sudo_user, entry, user, user_perm, group, group_perm, other_perm, set_mask, mask, default, recursive, recalc_mask, not_recalc_mask, logical, physical): @@ -531,7 +549,7 @@ def do_set_acl(self, root_dir, sudo_user, entry, user, user_perm, group, group_p except subprocess.CalledProcessError as e: return self.handleException(e, root_dir, 'do_set_acl', abspath, user_perm=user_perm, group_perm=group_perm, other_perm=other_perm) self.stats.success('do_set_acl') - self.logger.info(f"do_set_acl {abspath} with {text} succeed") + self.loggers[f'{root_dir}'].info(f"do_set_acl {abspath} with {text} succeed") return (acl,) def do_utime(self, root_dir, entry, access_time, modify_time, follow_symlinks, user): @@ -547,7 +565,7 @@ def do_utime(self, root_dir, entry, access_time, modify_time, follow_symlinks, u os.seteuid(0) os.setegid(0) self.stats.success('do_utime') - self.logger.info(f"do_utime {abspath} {access_time} {modify_time} succeed") + self.loggers[root_dir].info(f"do_utime {abspath} {access_time} {modify_time} succeed") return get_stat(abspath) def do_chown(self, root_dir, entry, owner, user): @@ -565,7 +583,7 @@ def do_chown(self, root_dir, entry, owner, user): os.seteuid(0) os.setegid(0) self.stats.success('do_chown') - self.logger.info(f"do_chown {abspath} {owner} succeed") + self.loggers[root_dir].info(f"do_chown {abspath} {owner} succeed") return get_stat(abspath) def do_split_dir(self, root_dir, dir, vdirs): @@ -577,10 +595,10 @@ def do_split_dir(self, root_dir, dir, vdirs): subprocess.check_call(['touch', abspath]) except Exception as e: self.stats.failure('do_split_dir') - self.logger.info(f"do_split_dir {abspath} {vdirs} failed: {str(e)}") + self.loggers[root_dir].info(f"do_split_dir {abspath} {vdirs} failed: {str(e)}") return self.stats.success('do_split_dir') - self.logger.info(f"do_split_dir {abspath} {vdirs} succeed") + self.loggers[root_dir].info(f"do_split_dir {abspath} {vdirs} succeed") def do_merge_dir(self, root_dir, dir): relpath = os.path.join(dir, f'.jfs_split#1') @@ -591,15 +609,12 @@ def do_merge_dir(self, root_dir, dir): subprocess.check_call(['touch', abspath]) except Exception as e: self.stats.failure('do_merge_dir') - self.logger.info(f"do_merge_dir {abspath} failed: {str(e)}") + self.loggers[f'{root_dir}'].info(f"do_merge_dir {abspath} failed: {str(e)}") return self.stats.success('do_merge_dir') - self.logger.info(f"do_merge_dir {abspath} succeed") + self.loggers[f'{root_dir}'].info(f"do_merge_dir {abspath} succeed") def do_rebalance(self, root_dir, entry, zone, is_vdir): - if not is_jfs(root_dir): - print(f'{root_dir} is not in jfs, skip rebalance') - return if zone == '': print(f'{root_dir} is not multizoned, skip rebalance') return @@ -614,10 +629,10 @@ def do_rebalance(self, root_dir, entry, zone, is_vdir): os.rename(abspath, dest) except Exception as e: self.stats.failure('do_rebalance') - self.logger.info(f"do_rebalance {abspath} {dest} failed: {str(e)}") + self.loggers[root_dir].info(f"do_rebalance {abspath} {dest} failed: {str(e)}") return self.stats.success('do_rebalance') - self.logger.info(f"do_rebalance {abspath} {dest} succeed") + self.loggers[root_dir].info(f"do_rebalance {abspath} {dest} succeed") def do_mount(self, context:Context, mount, allow_other=True, enable_xattr=True, enable_acl=True, read_only=False, user='root'): command = f'sudo -u {user} {mount} mount {context.volume} {context.mp} --conf-dir={context.conf_dir} --no-update' @@ -695,7 +710,7 @@ def do_info(self, context:Context, mount, entry, user='root', **kwargs): return self.handleException(e, context.root_dir, 'do_info', abs_path) result = self.parse_info(result) self.stats.success('do_info') - self.logger.info(f'do_info {abs_path} succeed') + self.loggers[context.root_dir].info(f'do_info {abs_path} succeed') return result def do_rmr(self, context:Context, entry, mount, user='root'): @@ -708,7 +723,7 @@ def do_rmr(self, context:Context, entry, mount, user='root'): return self.handleException(e, context.root_dir, 'do_rmr', abspath) assert not os.path.exists(abspath), f'do_rmr: {abspath} should not exist' self.stats.success('do_rmr') - self.logger.info(f'do_rmr {abspath} succeed') + self.loggers[context.root_dir].info(f'do_rmr {abspath} succeed') return True def do_status(self, context:Context, mount, user='root'): @@ -721,7 +736,7 @@ def do_status(self, context:Context, mount, user='root'): except subprocess.CalledProcessError as e: return self.handleException(e, context.root_dir, 'do_status', '') self.stats.success('do_status') - self.logger.info(f'do_status succeed') + self.loggers[context.root_dir].info(f'do_status succeed') return result['rootname'], result['password'], result['uuid'], result['storage'], \ result['token'], result['accesskey'], result['secretkey'], \ result['blockSize'], result['partitions'], result['compress'] @@ -733,7 +748,7 @@ def do_dump(self, context:Context, entry, mount, user='root'): except subprocess.CalledProcessError as e: return self.handleException(e, context.root_dir, 'do_dump', abspath) self.stats.success('do_dump') - self.logger.info(f'do_dump {abspath} succeed') + self.loggers[context.root_dir].info(f'do_dump {abspath} succeed') return result def do_warmup(self, context:Context, entry, mount, user='root'): @@ -743,7 +758,7 @@ def do_warmup(self, context:Context, entry, mount, user='root'): except subprocess.CalledProcessError as e: return self.handleException(e, context.root_dir, 'do_warmup', abspath) self.stats.success('do_warmup') - self.logger.info(f'do_warmup {abspath} succeed') + self.loggers[context.root_dir].info(f'do_warmup {abspath} succeed') return True def do_import(self, context:Context, mount, src_uri, dest_path, mode, user='root'): @@ -753,7 +768,7 @@ def do_import(self, context:Context, mount, src_uri, dest_path, mode, user='root except subprocess.CalledProcessError as e: return self.handleException(e, context.root_dir, 'do_import', abspath, src_uri=src_uri) self.stats.success('do_import') - self.logger.info(f'do_import {src_uri} succeed') + self.loggers[context.root_dir].info(f'do_import {src_uri} succeed') # src_uri is stared with /, so we need to remove the first / return self.do_info(context=context, mount=mount, entry=os.path.join(dest_path, src_uri[1:])) @@ -766,7 +781,7 @@ def do_gc(self, context:Context, mount:str, delete:bool, user:str='root'): except subprocess.CalledProcessError as e: return self.handleException(e, context.root_dir, 'do_gc', '') self.stats.success('do_gc') - self.logger.info(f'do_gc succeed') + self.loggers[context.root_dir].info(f'do_gc succeed') return True def do_fsck(self, context:Context, mount, repair, user='root'): @@ -778,7 +793,7 @@ def do_fsck(self, context:Context, mount, repair, user='root'): except subprocess.CalledProcessError as e: return self.handleException(e, context.root_dir, 'do_fsck', '') self.stats.success('do_fsck') - self.logger.info(f'do_fsck succeed') + self.loggers[context.root_dir].info(f'do_fsck succeed') return True def do_quota_set(self, context:Context, mount, path, capacity, inodes, user='root'): @@ -795,7 +810,7 @@ def do_quota_set(self, context:Context, mount, path, capacity, inodes, user='roo except subprocess.CalledProcessError as e: return self.handleException(e, context.root_dir, 'do_quota_set', abspath) self.stats.success('do_quota_set') - self.logger.info(f'do_quota_set {abspath} succeed') + self.loggers[context.root_dir].info(f'do_quota_set {abspath} succeed') return self.do_quota_get(context=context, mount=mount, path=path, user=user) def do_quota_delete(self, context:Context, mount, path, user='root'): @@ -807,7 +822,7 @@ def do_quota_delete(self, context:Context, mount, path, user='root'): except subprocess.CalledProcessError as e: return self.handleException(e, context.root_dir, 'do_quota_delete', abspath) self.stats.success('do_quota_delete') - self.logger.info(f'do_quota_delete {abspath} succeed') + self.loggers[context.root_dir].info(f'do_quota_delete {abspath} succeed') return True def do_quota_get(self, context:Context, mount, path, user='root'): @@ -819,7 +834,7 @@ def do_quota_get(self, context:Context, mount, path, user='root'): except subprocess.CalledProcessError as e: return self.handleException(e, context.root_dir, 'do_quota_get', abspath) self.stats.success('do_quota_get') - self.logger.info(f'do_quota_get {abspath} succeed') + self.loggers[context.root_dir].info(f'do_quota_get {abspath} succeed') return result def do_quota_list(self, context:Context, mount, user='root'): @@ -829,7 +844,7 @@ def do_quota_list(self, context:Context, mount, user='root'): except subprocess.CalledProcessError as e: return self.handleException(e, context.root_dir, 'do_quota_list', '') self.stats.success('do_quota_list') - self.logger.info(f'do_quota_list succeed') + self.loggers[context.root_dir].info(f'do_quota_list succeed') return result def do_trash_list(self, context:Context, user='root'): @@ -844,7 +859,7 @@ def do_trash_list(self, context:Context, user='root'): os.seteuid(0) os.setegid(0) self.stats.success('do_trash_list') - self.logger.info(f'do_trash_list succeed') + self.loggers[context.root_dir].info(f'do_trash_list succeed') return tuple(li) def do_trash_restore(self, context:Context, index, user='root'): @@ -861,6 +876,6 @@ def do_trash_restore(self, context:Context, index, user='root'): restored_path = os.path.join(context.mp, '/'.join(trash_file.split('|')[1:])) restored_path = os.path.relpath(restored_path, context.root_dir) self.stats.success('do_trash_restore') - self.logger.info(f'do_trash_restore succeed') + self.loggers[context.root_dir].info(f'do_trash_restore succeed') return restored_path \ No newline at end of file diff --git a/.github/scripts/hypo/fsrand2.py b/.github/scripts/hypo/fsrand2.py index faf44b0338b4..273b509b10af 100644 --- a/.github/scripts/hypo/fsrand2.py +++ b/.github/scripts/hypo/fsrand2.py @@ -12,7 +12,7 @@ __import__("hypothesis") except ImportError: subprocess.check_call(["pip", "install", "hypothesis"]) -from hypothesis import HealthCheck, assume, strategies as st, settings, Verbosity +from hypothesis import HealthCheck, assume, reproduce_failure, strategies as st, settings, Verbosity from hypothesis.stateful import rule, precondition, RuleBasedStateMachine, Bundle, initialize, multiple, consumes from hypothesis import Phase, seed from strategy import * @@ -30,33 +30,29 @@ class JuicefsMachine(RuleBasedStateMachine): EntryWithACL = Bundle('entry_with_acl') FilesWithXattr = Bundle('files_with_xattr') start = time.time() - DEFALUT_ROOT_DIR1 = '/tmp/fsrand' - DEFALUT_ROOT_DIR2 = '/tmp/jfs/fsrand' - ROOT_DIR1=os.environ.get('ROOT_DIR1', DEFALUT_ROOT_DIR1).split(',') - ROOT_DIR1 = [x.rstrip('/') for x in ROOT_DIR1] - ROOT_DIR2=os.environ.get('ROOT_DIR2', DEFALUT_ROOT_DIR2).split(',') - ROOT_DIR2 = [x.rstrip('/') for x in ROOT_DIR2] + ROOT_DIR1=os.environ.get('ROOT_DIR1', '/tmp/fsrand').rstrip('/') + ROOT_DIR2=os.environ.get('ROOT_DIR2', '/tmp/jfs/fsrand').rstrip('/') log_level = os.environ.get('LOG_LEVEL', 'INFO') - logger = common.setup_logger(f'./fsrand.log', 'fsrand_logger', log_level) - fsop = FsOperation(logger) - ZONES1 = common.get_zones(ROOT_DIR1[0]) - ZONES2 = common.get_zones(ROOT_DIR2[0]) + loggers = {f'{ROOT_DIR1}': common.setup_logger(f'./log1', 'logger1', log_level), \ + f'{ROOT_DIR2}': common.setup_logger(f'./log2', 'logger2', log_level)} + fsop = FsOperation(loggers) + ZONES = {ROOT_DIR1:common.get_zones(ROOT_DIR1), ROOT_DIR2:common.get_zones(ROOT_DIR2)} SUDO_USERS = ['root', 'user1'] USERS=['root', 'user1', 'user2','user3'] GROUPS = USERS+['group1', 'group2', 'group3', 'group4'] group_created = False INCLUDE_RULES = [] - EXCLUDE_RULES = ['rebalance_dir', 'rebalance_file', 'merge_dir', 'split_dir', \ - 'clone_cp_file', 'clone_cp_dir', 'set_acl'] + EXCLUDE_RULES = ['rebalance_dir', 'rebalance_file', \ + 'clone_cp_file', 'clone_cp_dir'] @initialize(target=Folders) def init_folders(self): - if not os.path.exists(self.ROOT_DIR1[0]): - os.makedirs(self.ROOT_DIR1[0]) - if not os.path.exists(self.ROOT_DIR2[0]): - os.makedirs(self.ROOT_DIR2[0]) + if not os.path.exists(self.ROOT_DIR1): + os.makedirs(self.ROOT_DIR1) + if not os.path.exists(self.ROOT_DIR2): + os.makedirs(self.ROOT_DIR2) if os.environ.get('PROFILE', 'dev') != 'generate': - common.clean_dir(self.ROOT_DIR1[0]) - common.clean_dir(self.ROOT_DIR2[0]) + common.clean_dir(self.ROOT_DIR1) + common.clean_dir(self.ROOT_DIR2) return '' def create_users(self, users): @@ -80,20 +76,20 @@ def __init__(self): if duration > MAX_RUNTIME: raise Exception(f'run out of time: {duration}') - def equal(self, result1, result2, rootdir1, rootdir2): + def equal(self, result1, result2): if os.getenv('PROFILE', 'dev') == 'generate': return True if type(result1) != type(result2): return False if isinstance(result1, Exception): - r1 = str(result1).replace(rootdir1, '') - r2 = str(result2).replace(rootdir2, '') + r1 = str(result1).replace(self.ROOT_DIR1, '') + r2 = str(result2).replace(self.ROOT_DIR2, '') return r1 == r2 elif isinstance(result1, tuple): return result1 == result2 elif isinstance(result1, str): - r1 = str(result1).replace(rootdir1, '') - r2 = str(result2).replace(rootdir2, '') + r1 = str(result1).replace(self.ROOT_DIR1, '') + r2 = str(result2).replace(self.ROOT_DIR2, '') return r1 == r2 else: return result1 == result2 @@ -106,15 +102,12 @@ def seteuid(self, user): flags = st_open_flags, umask = st_umask, mode = st_entry_mode, - user = st.sampled_from(SUDO_USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(SUDO_USERS)) @precondition(lambda self: 'open' not in self.EXCLUDE_RULES) - def open(self, file, flags, mode, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root', umask=0o022): - result1 = self.fsop.do_open(rootdir1, file, flags, umask, mode, user) - result2 = self.fsop.do_open(rootdir2, file, flags, umask, mode, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mopen:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def open(self, file, flags, mode, user='root', umask=0o022): + result1 = self.fsop.do_open(self.ROOT_DIR1, file, flags, umask, mode, user) + result2 = self.fsop.do_open(self.ROOT_DIR2, file, flags, umask, mode, user) + assert self.equal(result1, result2), f'\033[31mopen:\nresult1 is {result1}\nresult2 is {result2}\033[0m' @rule(file = Files.filter(lambda x: x != multiple()), @@ -122,57 +115,46 @@ def open(self, file, flags, mode, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_R content = st_content, flags = st_open_flags, whence = st.sampled_from([os.SEEK_SET, os.SEEK_CUR, os.SEEK_END]), - user = st.sampled_from(SUDO_USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) + user = st.sampled_from(SUDO_USERS) ) @precondition(lambda self: 'write' not in self.EXCLUDE_RULES) - def write(self, file, offset, content, flags, whence, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - result1 = self.fsop.do_write(rootdir1, file, offset, content, flags, whence, user) - result2 = self.fsop.do_write(rootdir2, file, offset, content, flags, whence, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mwrite:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def write(self, file, offset, content, flags, whence, user='root'): + result1 = self.fsop.do_write(self.ROOT_DIR1, file, offset, content, flags, whence, user) + result2 = self.fsop.do_write(self.ROOT_DIR2, file, offset, content, flags, whence, user) + assert self.equal(result1, result2), f'\033[31mwrite:\nresult1 is {result1}\nresult2 is {result2}\033[0m' @rule(file = Files.filter(lambda x: x != multiple()), offset = st.integers(min_value=0, max_value=MAX_FILE_SIZE), length = st.integers(min_value=0, max_value=MAX_FALLOCATE_LENGTH), mode = st.just(0), - user = st.sampled_from(SUDO_USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(SUDO_USERS)) @precondition(lambda self: 'fallocate' not in self.EXCLUDE_RULES) - def fallocate(self, file, offset, length, mode, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - result1 = self.fsop.do_fallocate(rootdir1, file, offset, length, mode, user) - result2 = self.fsop.do_fallocate(rootdir2, file, offset, length, mode, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mfallocate:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def fallocate(self, file, offset, length, mode, user='root'): + result1 = self.fsop.do_fallocate(self.ROOT_DIR1, file, offset, length, mode, user) + result2 = self.fsop.do_fallocate(self.ROOT_DIR2, file, offset, length, mode, user) + assert self.equal(result1, result2), f'\033[31mfallocate:\nresult1 is {result1}\nresult2 is {result2}\033[0m' @rule( file = Files.filter(lambda x: x != multiple()), offset = st_offset, length = st.integers(min_value=0, max_value=MAX_FILE_SIZE), - user = st.sampled_from(SUDO_USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(SUDO_USERS)) @precondition(lambda self: 'read' not in self.EXCLUDE_RULES) - def read(self, file, offset, length, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - result1 = self.fsop.do_read(rootdir1, file, offset, length, user) - result2 = self.fsop.do_read(rootdir2, file, offset, length, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mread:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def read(self, file, offset, length, user='root'): + result1 = self.fsop.do_read(self.ROOT_DIR1, file, offset, length, user) + result2 = self.fsop.do_read(self.ROOT_DIR2, file, offset, length, user) + assert self.equal(result1, result2), f'\033[31mread:\nresult1 is {result1}\nresult2 is {result2}\033[0m' @rule(file=Files.filter(lambda x: x != multiple()), size=st.integers(min_value=0, max_value=MAX_TRUNCATE_LENGTH), - user=st.sampled_from(SUDO_USERS), - rootdir1=st.sampled_from(ROOT_DIR1), - rootdir2=st.sampled_from(ROOT_DIR2) - ) + user=st.sampled_from(SUDO_USERS)) @precondition(lambda self: 'truncate' not in self.EXCLUDE_RULES) - def truncate(self, file, size, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - result1 = self.fsop.do_truncate(rootdir1, file, size, user) - result2 = self.fsop.do_truncate(rootdir2, file, size, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mtruncate:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def truncate(self, file, size, user='root'): + result1 = self.fsop.do_truncate(self.ROOT_DIR1, file, size, user) + result2 = self.fsop.do_truncate(self.ROOT_DIR2, file, size, user) + assert self.equal(result1, result2), f'\033[31mtruncate:\nresult1 is {result1}\nresult2 is {result2}\033[0m' @rule(target=Files, parent = Folders.filter(lambda x: x != multiple()), @@ -180,44 +162,35 @@ def truncate(self, file, size, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT mode = st_open_mode, content = st_content, user = st.sampled_from(SUDO_USERS), - umask = st_umask, - rootdir1=st.sampled_from(ROOT_DIR1), - rootdir2=st.sampled_from(ROOT_DIR2) - ) + umask = st_umask) @precondition(lambda self: 'create_file' not in self.EXCLUDE_RULES) - def create_file(self, parent, file_name, content, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, mode='x', user='root', umask=0o022): - result1 = self.fsop.do_create_file(rootdir1, parent, file_name, mode, content, user, umask) - result2 = self.fsop.do_create_file(rootdir2, parent, file_name, mode, content, user, umask) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mcreate_file:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def create_file(self, parent, file_name, content, mode='x', user='root', umask=0o022): + result1 = self.fsop.do_create_file(self.ROOT_DIR1, parent, file_name, mode, content, user, umask) + result2 = self.fsop.do_create_file(self.ROOT_DIR2, parent, file_name, mode, content, user, umask) + assert self.equal(result1, result2), f'\033[31mcreate_file:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return multiple() else: return os.path.join(parent, file_name) @rule(dir = Folders.filter(lambda x: x != multiple()), - user = st.sampled_from(SUDO_USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(SUDO_USERS)) @precondition(lambda self: 'listdir' not in self.EXCLUDE_RULES) - def listdir(self, dir, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - result1 = self.fsop.do_listdir(rootdir1, dir, user) - result2 = self.fsop.do_listdir(rootdir2, dir, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mlistdir:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def listdir(self, dir, user='root'): + result1 = self.fsop.do_listdir(self.ROOT_DIR1, dir, user) + result2 = self.fsop.do_listdir(self.ROOT_DIR2, dir, user) + assert self.equal(result1, result2), f'\033[31mlistdir:\nresult1 is {result1}\nresult2 is {result2}\033[0m' @rule( target = Files, file = consumes(Files).filter(lambda x: x != multiple()), - user = st.sampled_from(SUDO_USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(SUDO_USERS)) @precondition(lambda self: 'unlink' not in self.EXCLUDE_RULES) - def unlink(self, file, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): + def unlink(self, file, user='root'): print(file) - result1 = self.fsop.do_unlink(rootdir1, file, user) - result2 = self.fsop.do_unlink(rootdir2, file, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31munlink:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + result1 = self.fsop.do_unlink(self.ROOT_DIR1, file, user) + result2 = self.fsop.do_unlink(self.ROOT_DIR2, file, user) + assert self.equal(result1, result2), f'\033[31munlink:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return file else: @@ -228,15 +201,12 @@ def unlink(self, file, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, u parent = Folders, new_entry_name = st_entry_name, user = st.sampled_from(SUDO_USERS), - umask = st_umask, - rootdir1=st.sampled_from(ROOT_DIR1), - rootdir2=st.sampled_from(ROOT_DIR2) - ) + umask = st_umask) @precondition(lambda self: 'rename_file' not in self.EXCLUDE_RULES) - def rename_file(self, entry, parent, new_entry_name, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root', umask=0o022): - result1 = self.fsop.do_rename(rootdir1, entry, parent, new_entry_name, user, umask) - result2 = self.fsop.do_rename(rootdir2, entry, parent, new_entry_name, user, umask) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mrename_file:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def rename_file(self, entry, parent, new_entry_name, user='root', umask=0o022): + result1 = self.fsop.do_rename(self.ROOT_DIR1, entry, parent, new_entry_name, user, umask) + result2 = self.fsop.do_rename(self.ROOT_DIR2, entry, parent, new_entry_name, user, umask) + assert self.equal(result1, result2), f'\033[31mrename_file:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return entry else: @@ -247,15 +217,12 @@ def rename_file(self, entry, parent, new_entry_name, rootdir1=DEFALUT_ROOT_DIR1, parent = Folders, new_entry_name = st_entry_name, user = st.sampled_from(SUDO_USERS), - umask = st_umask, - rootdir1=st.sampled_from(ROOT_DIR1), - rootdir2=st.sampled_from(ROOT_DIR2) - ) + umask = st_umask) @precondition(lambda self: 'rename_dir' not in self.EXCLUDE_RULES) - def rename_dir(self, entry, parent, new_entry_name, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root', umask=0o022): - result1 = self.fsop.do_rename(rootdir1, entry, parent, new_entry_name, user, umask) - result2 = self.fsop.do_rename(rootdir2, entry, parent, new_entry_name, user, umask) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mrename_dir:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def rename_dir(self, entry, parent, new_entry_name, user='root', umask=0o022): + result1 = self.fsop.do_rename(self.ROOT_DIR1, entry, parent, new_entry_name, user, umask) + result2 = self.fsop.do_rename(self.ROOT_DIR2, entry, parent, new_entry_name, user, umask) + assert self.equal(result1, result2), f'\033[31mrename_dir:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return entry else: @@ -267,15 +234,12 @@ def rename_dir(self, entry, parent, new_entry_name, rootdir1=DEFALUT_ROOT_DIR1, new_entry_name = st_entry_name, follow_symlinks = st.booleans(), user = st.sampled_from(SUDO_USERS), - umask = st_umask, - rootdir1=st.sampled_from(ROOT_DIR1), - rootdir2=st.sampled_from(ROOT_DIR2) - ) + umask = st_umask ) @precondition(lambda self: 'copy_file' not in self.EXCLUDE_RULES) - def copy_file(self, entry, parent, new_entry_name, follow_symlinks, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root', umask=0o022): - result1 = self.fsop.do_copy_file(rootdir1, entry, parent, new_entry_name, follow_symlinks, user, umask) - result2 = self.fsop.do_copy_file(rootdir2, entry, parent, new_entry_name, follow_symlinks, user, umask) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mcopy_file:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def copy_file(self, entry, parent, new_entry_name, follow_symlinks, user='root', umask=0o022): + result1 = self.fsop.do_copy_file(self.ROOT_DIR1, entry, parent, new_entry_name, follow_symlinks, user, umask) + result2 = self.fsop.do_copy_file(self.ROOT_DIR2, entry, parent, new_entry_name, follow_symlinks, user, umask) + assert self.equal(result1, result2), f'\033[31mcopy_file:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return multiple() else: @@ -286,14 +250,11 @@ def copy_file(self, entry, parent, new_entry_name, follow_symlinks, rootdir1=DEF new_entry_name = st_entry_name, preserve = st.booleans(), user = st.sampled_from(SUDO_USERS), - umask = st_umask, - rootdir1=st.sampled_from(ROOT_DIR1), - rootdir2=st.sampled_from(ROOT_DIR2) - ) + umask = st_umask ) @precondition(lambda self: 'clone_cp_file' not in self.EXCLUDE_RULES) - def clone_cp_file(self, entry, parent, new_entry_name, preserve, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root', umask=0o022): - result1 = self.fsop.do_clone_entry(rootdir1, entry, parent, new_entry_name, preserve, user, umask) - result2 = self.fsop.do_clone_entry(rootdir2, entry, parent, new_entry_name, preserve, user, umask) + def clone_cp_file(self, entry, parent, new_entry_name, preserve, user='root', umask=0o022): + result1 = self.fsop.do_clone_entry(self.ROOT_DIR1, entry, parent, new_entry_name, preserve, user, umask) + result2 = self.fsop.do_clone_entry(self.ROOT_DIR2, entry, parent, new_entry_name, preserve, user, umask) # assert self.equal(result1, result2), f'clone_file:\nresult1 is {result1}\nresult2 is {result2}' assert type(result1) == type(result2), f'\033[31mclone_cp_file:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): @@ -309,14 +270,12 @@ def clone_cp_file(self, entry, parent, new_entry_name, preserve, rootdir1=DEFALU preserve = st.booleans(), user = st.sampled_from(SUDO_USERS), umask = st_umask, - rootdir1=st.sampled_from(ROOT_DIR1), - rootdir2=st.sampled_from(ROOT_DIR2) ) @precondition(lambda self: 'clone_cp_dir' not in self.EXCLUDE_RULES ) - def clone_cp_dir(self, entry, parent, new_entry_name, preserve, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root', umask=0o022): - result1 = self.fsop.do_clone_entry(rootdir1, entry, parent, new_entry_name, preserve, user, umask) - result2 = self.fsop.do_clone_entry(rootdir2, entry, parent, new_entry_name, preserve, user, umask) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mclone_cp_dir:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def clone_cp_dir(self, entry, parent, new_entry_name, preserve, user, umask): + result1 = self.fsop.do_clone_entry(self.ROOT_DIR1, entry, parent, new_entry_name, preserve, user, umask) + result2 = self.fsop.do_clone_entry(self.ROOT_DIR2, entry, parent, new_entry_name, preserve, user, umask) + assert self.equal(result1, result2), f'\033[31mclone_cp_dir:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return multiple() else: @@ -328,15 +287,12 @@ def clone_cp_dir(self, entry, parent, new_entry_name, preserve, rootdir1=DEFALUT subdir = st_entry_name, mode = st_entry_mode, user = st.sampled_from(SUDO_USERS), - umask = st_umask, - rootdir1=st.sampled_from(ROOT_DIR1), - rootdir2=st.sampled_from(ROOT_DIR2) - ) + umask = st_umask ) @precondition(lambda self: 'mkdir' not in self.EXCLUDE_RULES) - def mkdir(self, parent, subdir, mode, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root', umask=0o022): - result1 = self.fsop.do_mkdir(rootdir1, parent, subdir, mode, user, umask) - result2 = self.fsop.do_mkdir(rootdir2, parent, subdir, mode, user, umask) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mmkdir:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def mkdir(self, parent, subdir, mode, user='root', umask=0o022): + result1 = self.fsop.do_mkdir(self.ROOT_DIR1, parent, subdir, mode, user, umask) + result2 = self.fsop.do_mkdir(self.ROOT_DIR2, parent, subdir, mode, user, umask) + assert self.equal(result1, result2), f'\033[31mmkdir:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return multiple() else: @@ -344,16 +300,13 @@ def mkdir(self, parent, subdir, mode, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFAL @rule( target = Folders, dir = consumes(Folders).filter(lambda x: x != multiple()), - user = st.sampled_from(SUDO_USERS), - rootdir1=st.sampled_from(ROOT_DIR1), - rootdir2=st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(SUDO_USERS)) @precondition(lambda self: 'rmdir' not in self.EXCLUDE_RULES) - def rmdir(self, dir, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): + def rmdir(self, dir, user='root'): assume(dir != '') - result1 = self.fsop.do_rmdir(rootdir1, dir, user) - result2 = self.fsop.do_rmdir(rootdir2, dir, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mrmdir:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + result1 = self.fsop.do_rmdir(self.ROOT_DIR1, dir, user) + result2 = self.fsop.do_rmdir(self.ROOT_DIR2, dir, user) + assert self.equal(result1, result2), f'\033[31mrmdir:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return dir else: @@ -364,15 +317,12 @@ def rmdir(self, dir, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, use parent = Folders.filter(lambda x: x != multiple()), link_file_name = st_entry_name, user = st.sampled_from(SUDO_USERS), - umask = st_umask, - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + umask = st_umask) @precondition(lambda self: 'hardlink' not in self.EXCLUDE_RULES) - def hardlink(self, dest_file, parent, link_file_name, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root', umask=0o022): - result1 = self.fsop.do_hardlink(rootdir1, dest_file, parent, link_file_name, user, umask) - result2 = self.fsop.do_hardlink(rootdir2, dest_file, parent, link_file_name, user, umask) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mhardlink:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def hardlink(self, dest_file, parent, link_file_name, user='root', umask=0o022): + result1 = self.fsop.do_hardlink(self.ROOT_DIR1, dest_file, parent, link_file_name, user, umask) + result2 = self.fsop.do_hardlink(self.ROOT_DIR2, dest_file, parent, link_file_name, user, umask) + assert self.equal(result1, result2), f'\033[31mhardlink:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return multiple() else: @@ -383,15 +333,12 @@ def hardlink(self, dest_file, parent, link_file_name, rootdir1=DEFALUT_ROOT_DIR1 parent = Folders.filter(lambda x: x != multiple()), link_file_name = st_entry_name, user = st.sampled_from(SUDO_USERS), - umask = st_umask, - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + umask = st_umask ) @precondition(lambda self: 'symlink' not in self.EXCLUDE_RULES) - def symlink(self, dest_file, parent, link_file_name,rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root', umask=0o022): - result1 = self.fsop.do_symlink(rootdir1, dest_file, parent, link_file_name, user, umask) - result2 = self.fsop.do_symlink(rootdir2, dest_file, parent, link_file_name, user, umask) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31msymlink:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def symlink(self, dest_file, parent, link_file_name, user='root', umask=0o022): + result1 = self.fsop.do_symlink(self.ROOT_DIR1, dest_file, parent, link_file_name, user, umask) + result2 = self.fsop.do_symlink(self.ROOT_DIR2, dest_file, parent, link_file_name, user, umask) + assert self.equal(result1, result2), f'\033[31msymlink:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return multiple() else: @@ -402,102 +349,94 @@ def symlink(self, dest_file, parent, link_file_name,rootdir1=DEFALUT_ROOT_DIR1, name = st_xattr_name, value = st_xattr_value, flag = st.sampled_from([xattr.XATTR_CREATE, xattr.XATTR_REPLACE]), - user = st.sampled_from(SUDO_USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(SUDO_USERS) + ) @precondition(lambda self: 'set_xattr' not in self.EXCLUDE_RULES) - def set_xattr(self, file, name, value, flag, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - result1 = self.fsop.do_set_xattr(rootdir1, file, name, value, flag, user) - result2 = self.fsop.do_set_xattr(rootdir2, file, name, value, flag, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mset_xattr:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def set_xattr(self, file, name, value, flag, user='root'): + # assert '\x00' not in name, f'xattr name should not include \x00' + result1 = self.fsop.do_set_xattr(self.ROOT_DIR1, file, name, value, flag, user) + result2 = self.fsop.do_set_xattr(self.ROOT_DIR2, file, name, value, flag, user) + assert self.equal(result1, result2), f'\033[31mset_xattr:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return multiple() else: return file @rule(file = FilesWithXattr.filter(lambda x: x != multiple()), - user = st.sampled_from(SUDO_USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(SUDO_USERS)) + @precondition(lambda self: 'list_xattr' not in self.EXCLUDE_RULES) + def list_xattr(self, file, user='root'): + result1 = self.fsop.do_list_xattr(self.ROOT_DIR1, file, user) + result2 = self.fsop.do_list_xattr(self.ROOT_DIR2, file, user) + assert self.equal(result1, result2), f'\033[31mlist_xattr:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + + + @rule(file = FilesWithXattr.filter(lambda x: x != multiple()), + user = st.sampled_from(SUDO_USERS)) @precondition(lambda self: 'get_xattr' not in self.EXCLUDE_RULES) - def remove_xattr(self, file, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - result1 = self.fsop.do_remove_xattr(rootdir1, file, user) - result2 = self.fsop.do_remove_xattr(rootdir2, file, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mremove_xattr:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def remove_xattr(self, file, user='root'): + result1 = self.fsop.do_remove_xattr(self.ROOT_DIR1, file, user) + result2 = self.fsop.do_remove_xattr(self.ROOT_DIR2, file, user) + assert self.equal(result1, result2), f'\033[31mremove_xattr:\nresult1 is {result1}\nresult2 is {result2}\033[0m' @rule(user = st.sampled_from(USERS).filter(lambda x: x != 'root'), group = st.sampled_from(GROUPS), - groups = st.lists(st.sampled_from(GROUPS), unique=True), - ) + groups = st.lists(st.sampled_from(GROUPS), unique=True)) @precondition(lambda self: 'change_groups' not in self.EXCLUDE_RULES) def change_groups(self, user, group, groups): - self.fsop.do_change_groups(user, group, groups) + self.fsop.do_change_groups(self.ROOT_DIR1, user, group, groups) + self.fsop.do_change_groups(self.ROOT_DIR2, user, group, groups) @rule(entry = Entries.filter(lambda x: x != multiple()), mode = st_entry_mode, - user = st.sampled_from(SUDO_USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(SUDO_USERS)) @precondition(lambda self: 'chmod' not in self.EXCLUDE_RULES) - def chmod(self, entry, mode, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - result1 = self.fsop.do_chmod(rootdir1, entry, mode, user) - result2 = self.fsop.do_chmod(rootdir2, entry, mode, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mchmod:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def chmod(self, entry, mode, user='root'): + result1 = self.fsop.do_chmod(self.ROOT_DIR1, entry, mode, user) + result2 = self.fsop.do_chmod(self.ROOT_DIR2, entry, mode, user) + assert self.equal(result1, result2), f'\033[31mchmod:\nresult1 is {result1}\nresult2 is {result2}\033[0m' - @rule(entry = Entries.filter(lambda x: x != multiple()), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) - @precondition(lambda self: 'get_acl' not in self.EXCLUDE_RULES) - def get_acl(self, entry, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2): - assume(common.support_acl(rootdir1) and common.support_acl(rootdir2)) - result1 = self.fsop.do_get_acl(rootdir1, entry) - result2 = self.fsop.do_get_acl(rootdir2, entry) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mget_acl:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + @rule(entry = Entries.filter(lambda x: x != multiple())) + @precondition(lambda self: 'get_acl' not in self.EXCLUDE_RULES and common.support_acl(self.ROOT_DIR1) and common.support_acl(self.ROOT_DIR2) ) + def get_acl(self, entry): + result1 = self.fsop.do_get_acl(self.ROOT_DIR1, entry) + result2 = self.fsop.do_get_acl(self.ROOT_DIR2, entry) + assert self.equal(result1, result2), f'\033[31mget_acl:\nresult1 is {result1}\nresult2 is {result2}\033[0m' @rule(entry = EntryWithACL.filter(lambda x: x != multiple()), option = st.sampled_from(['--remove-all', '--remove-default']), - user = st.sampled_from(SUDO_USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) + user = st.sampled_from(SUDO_USERS) ) - @precondition(lambda self: 'remove_acl' not in self.EXCLUDE_RULES ) - def remove_acl(self, entry, option, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - assume(common.support_acl(rootdir1) and common.support_acl(rootdir2)) - result1 = self.fsop.do_remove_acl(rootdir1, entry, option, user) - result2 = self.fsop.do_remove_acl(rootdir2, entry, option, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mremove_acl:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + @precondition(lambda self: 'remove_acl' not in self.EXCLUDE_RULES and common.support_acl(self.ROOT_DIR1) and common.support_acl(self.ROOT_DIR2) ) + def remove_acl(self, entry: str, option: str, user='root'): + result1 = self.fsop.do_remove_acl(self.ROOT_DIR1, entry, option, user) + result2 = self.fsop.do_remove_acl(self.ROOT_DIR2, entry, option, user) + assert self.equal(result1, result2), f'\033[31mremove_acl:\nresult1 is {result1}\nresult2 is {result2}\033[0m' @rule( target=EntryWithACL, sudo_user = st.sampled_from(SUDO_USERS), entry = Entries.filter(lambda x: x != multiple()), user=st.sampled_from(USERS+['']), - user_perm = st.sets(st.sampled_from(['r', 'w', 'x', ''])), + user_perm = st.sets(st.sampled_from(['r', 'w', 'x'])), group=st.sampled_from(GROUPS+['']), - group_perm = st.sets(st.sampled_from(['r', 'w', 'x'])), - other_perm = st.sets(st.sampled_from(['r', 'w', 'x', ''])), + group_perm = st.sets(st.sampled_from(['r', 'w', 'x'])).filter(lambda x: len(x) > 0), + other_perm = st.sets(st.sampled_from(['r', 'w', 'x'])), set_mask = st.booleans(), - mask = st.sets(st.sampled_from(['r', 'w', 'x', ''])), + mask = st.sets(st.sampled_from(['r', 'w', 'x'])).filter(lambda x: len(x) > 0), default = st.booleans(), recursive = st.booleans(), recalc_mask = st.booleans(), not_recalc_mask = st.booleans(), logical = st.booleans(), physical = st.booleans(), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) ) - @precondition(lambda self: 'set_acl' not in self.EXCLUDE_RULES) - def set_acl(self, sudo_user, entry, user, user_perm, group, group_perm, other_perm, set_mask, mask, default, recursive, recalc_mask, not_recalc_mask, logical, physical, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2): - assume(common.support_acl(rootdir1) and common.support_acl(rootdir2)) - result1 = self.fsop.do_set_acl(rootdir1, sudo_user, entry, user, user_perm, group, group_perm, other_perm, set_mask, mask, default, recursive, recalc_mask, not_recalc_mask, logical, physical) - result2 = self.fsop.do_set_acl(rootdir2, sudo_user, entry, user, user_perm, group, group_perm, other_perm, set_mask, mask, default, recursive, recalc_mask, not_recalc_mask, logical, physical) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mset_acl:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + @precondition(lambda self: 'set_acl' not in self.EXCLUDE_RULES and common.support_acl(self.ROOT_DIR1) and common.support_acl(self.ROOT_DIR2) ) + def set_acl(self, sudo_user, entry, user, user_perm, group, group_perm, other_perm, set_mask, mask, default, recursive, recalc_mask, not_recalc_mask, logical, physical): + result1 = self.fsop.do_set_acl(self.ROOT_DIR1, sudo_user, entry, user, user_perm, group, group_perm, other_perm, set_mask, mask, default, recursive, recalc_mask, not_recalc_mask, logical, physical) + result2 = self.fsop.do_set_acl(self.ROOT_DIR2, sudo_user, entry, user, user_perm, group, group_perm, other_perm, set_mask, mask, default, recursive, recalc_mask, not_recalc_mask, logical, physical) + assert self.equal(result1, result2), f'\033[31mset_acl:\nresult1 is {result1}\nresult2 is {result2}\033[0m' if isinstance(result1, Exception): return multiple() else: @@ -507,70 +446,53 @@ def set_acl(self, sudo_user, entry, user, user_perm, group, group_perm, other_pe access_time=st_time, modify_time=st_time, follow_symlinks=st.booleans(), - user = st.sampled_from(USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(USERS)) @precondition(lambda self: 'utime' not in self.EXCLUDE_RULES) - def utime(self, entry, access_time, modify_time, follow_symlinks, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - result1 = self.fsop.do_utime(rootdir1, entry, access_time, modify_time, follow_symlinks, user) - result2 = self.fsop.do_utime(rootdir2, entry, access_time, modify_time, follow_symlinks, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mutime:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def utime(self, entry, access_time, modify_time, follow_symlinks, user='root'): + result1 = self.fsop.do_utime(self.ROOT_DIR1, entry, access_time, modify_time, follow_symlinks, user) + result2 = self.fsop.do_utime(self.ROOT_DIR2, entry, access_time, modify_time, follow_symlinks, user) + assert self.equal(result1, result2), f'\033[31mutime:\nresult1 is {result1}\nresult2 is {result2}\033[0m' @rule(entry = Entries.filter(lambda x: x != multiple()), owner= st.sampled_from(USERS), - user = st.sampled_from(USERS), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) + user = st.sampled_from(USERS)) @precondition(lambda self: 'chown' not in self.EXCLUDE_RULES) - def chown(self, entry, owner, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2, user='root'): - result1 = self.fsop.do_chown(rootdir1, entry, owner, user) - result2 = self.fsop.do_chown(rootdir2, entry, owner, user) - assert self.equal(result1, result2, rootdir1, rootdir2), f'\033[31mchown:\nresult1 is {result1}\nresult2 is {result2}\033[0m' + def chown(self, entry, owner, user='root'): + result1 = self.fsop.do_chown(self.ROOT_DIR1, entry, owner, user) + result2 = self.fsop.do_chown(self.ROOT_DIR2, entry, owner, user) + assert self.equal(result1, result2), f'\033[31mchown:\nresult1 is {result1}\nresult2 is {result2}\033[0m' - @rule( dir =Folders, - vdirs = st.integers(min_value=2, max_value=31), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) - @precondition(lambda self: 'split_dir' not in self.EXCLUDE_RULES) - def split_dir(self, dir, vdirs, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2): - self.fsop.do_split_dir(rootdir1, dir, vdirs) - self.fsop.do_split_dir(rootdir2, dir, vdirs) + @rule( dir =Folders, vdirs = st.integers(min_value=2, max_value=31) ) + @precondition(lambda self: 'split_dir' not in self.EXCLUDE_RULES and (common.is_jfs(self.ROOT_DIR1) or common.is_jfs(self.ROOT_DIR2))) + def split_dir(self, dir, vdirs): + self.fsop.do_split_dir(self.ROOT_DIR1, dir, vdirs) + self.fsop.do_split_dir(self.ROOT_DIR2, dir, vdirs) - @rule(dir = Folders, - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) - @precondition(lambda self: 'merge_dir' not in self.EXCLUDE_RULES) - def merge_dir(self, dir, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2): - self.fsop.do_merge_dir(rootdir1, dir) - self.fsop.do_merge_dir(rootdir2, dir) + + @rule(dir = Folders) + @precondition(lambda self: 'merge_dir' not in self.EXCLUDE_RULES and (common.is_jfs(self.ROOT_DIR1) or common.is_jfs(self.ROOT_DIR2))) + def merge_dir(self, dir): + self.fsop.do_merge_dir(self.ROOT_DIR1, dir) + self.fsop.do_merge_dir(self.ROOT_DIR2, dir) @rule(dir = Folders, - zone1=st.sampled_from(ZONES1), - zone2=st.sampled_from(ZONES2), - is_vdir=st.booleans(), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) - ) - @precondition(lambda self: 'rebalance_dir' not in self.EXCLUDE_RULES) - def rebalance_dir(self, dir, zone1, zone2, is_vdir, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2): - self.fsop.do_rebalance(rootdir1, dir, zone1, is_vdir) - self.fsop.do_rebalance(rootdir2, dir, zone2, is_vdir) + zone1=st.sampled_from(ZONES[ROOT_DIR1]), + zone2=st.sampled_from(ZONES[ROOT_DIR2]), + is_vdir=st.booleans()) + @precondition(lambda self: 'rebalance_dir' not in self.EXCLUDE_RULES and (common.is_jfs(self.ROOT_DIR1) or common.is_jfs(self.ROOT_DIR2))) + def rebalance_dir(self, dir, zone1, zone2, is_vdir): + self.fsop.do_rebalance(self.ROOT_DIR1, dir, zone1, is_vdir) + self.fsop.do_rebalance(self.ROOT_DIR2, dir, zone2, is_vdir) @rule(file = Files, - zone1=st.sampled_from(ZONES1), - zone2=st.sampled_from(ZONES2), - rootdir1 = st.sampled_from(ROOT_DIR1), - rootdir2 = st.sampled_from(ROOT_DIR2) + zone1=st.sampled_from(ZONES[ROOT_DIR1]), + zone2=st.sampled_from(ZONES[ROOT_DIR2]), ) - @precondition(lambda self: 'rebalance_file' not in self.EXCLUDE_RULES ) - def rebalance_file(self, file, zone1, zone2, rootdir1=DEFALUT_ROOT_DIR1, rootdir2=DEFALUT_ROOT_DIR2): - self.fsop.do_rebalance(rootdir1, file, zone1, False) - self.fsop.do_rebalance(rootdir2, file, zone2, False) + @precondition(lambda self: 'rebalance_file' not in self.EXCLUDE_RULES and (common.is_jfs(self.ROOT_DIR1) or common.is_jfs(self.ROOT_DIR2))) + def rebalance_file(self, file, zone1, zone2): + self.fsop.do_rebalance(self.ROOT_DIR1, file, zone1, False) + self.fsop.do_rebalance(self.ROOT_DIR2, file, zone2, False) def teardown(self): pass diff --git a/.github/scripts/hypo/fsrand2_test.py b/.github/scripts/hypo/fsrand2_test.py index 58dcd1c7e5d5..9cc7107292c3 100644 --- a/.github/scripts/hypo/fsrand2_test.py +++ b/.github/scripts/hypo/fsrand2_test.py @@ -2,12 +2,116 @@ from fsrand2 import JuicefsMachine class TestFsrand2(unittest.TestCase): - def test_create_hardlink(self): + def test_hardlink_795(self): + # reproduce https://github.com/juicedata/jfs/issues/795 + for i in range(10): + state = JuicefsMachine() + v1 = state.init_folders() + v2 = state.create_file(content=b'', file_name='aaac', parent=v1, user='root') + state.rebalance_dir(dir=v1, is_vdir=False, zone1=v1, zone2='.jfszone0') + state.hardlink(dest_file=v2, link_file_name='aaaa', parent=v1, user='root') + state.teardown() + + def test_hardlink_769(self): + # reproduce nlink issue: https://github.com/juicedata/jfs/issues/769 + for i in range(10): + state = JuicefsMachine() + v1 = state.init_folders() + state.split_dir(dir=v1, vdirs=2) + v2 = state.create_file(content='a', file_name='aaab', parent=v1, user='root') + state.rebalance_file(file=v2, zone1=v1, zone2='.jfszone0') + state.hardlink(dest_file=v2, link_file_name='aaaa', parent=v1, user='root') + state.teardown() + + def test_listdir_910(self): + # See: https://github.com/juicedata/jfs/issues/910 + state = JuicefsMachine() + v1 = state.init_folders() + v2 = state.create_file(content=b'', file_name='aaaa', mode='w', parent=v1, user='root') + state.chmod(entry=v1, mode=32, user='root') + state.listdir(dir=v1, user='root') + state.change_groups(group='root', groups=['root'], user='user1') + state.listdir(dir=v1, user='user1') + state.teardown() + + def test_acl_913(self): + # See: https://github.com/juicedata/jfs/issues/913 + state = JuicefsMachine() + v1 = state.init_folders() + v2 = state.create_file(content=b'', file_name='aaaa', mode='w', parent=v1, user='root') + v3 = state.set_acl(default=False, entry=v1, group='root', group_perm=set(), logical=False, mask=set(), not_recalc_mask=False, other_perm=set(), physical=False, recalc_mask=False, recursive=False, set_mask=False, sudo_user='root', user='user1', user_perm=set()) + state.chmod(entry=v1, mode=4, user='root') + state.set_acl(default=False, entry=v1, group='root', group_perm=set(), logical=False, mask=set(), not_recalc_mask=False, other_perm=set(), physical=False, recalc_mask=False, recursive=True, set_mask=False, sudo_user='user1', user='root', user_perm=set()) + state.teardown() + + def test_fallocate_914(self): + # See: https://github.com/juicedata/jfs/issues/914 + state = JuicefsMachine() + v1 = state.init_folders() + v2 = state.create_file(content=b'yl\xff{', file_name='tadj', mode='x', parent=v1, user='root') + state.fallocate(file=v2, length=22911, mode=0, offset=7849, user='root') + state.copy_file(entry=v2, follow_symlinks=True, new_entry_name='npyn', parent=v1, user='root') + state.teardown() + + def test_clone_918(self): + # See: https://github.com/juicedata/jfs/issues/918 + state = JuicefsMachine() + v1 = state.init_folders() + v2 = state.create_file(content=b'', file_name='lcka', mode='w', parent=v1, user='root') + v3 = state.clone_cp_file(entry=v2, new_entry_name='bbbb', parent=v1, preserve=True, user='root') + state.chmod(entry=v3, mode=258, user='root') + v5 = state.clone_cp_file(entry=v3, new_entry_name='mbbb', parent=v1, preserve=True, user='root') + state.teardown() + + def test_acl_1004(self): + # SEE https://github.com/juicedata/jfs/issues/1004 + state = JuicefsMachine() + v1 = state.init_folders() + state.listdir(dir=v1, user='root') + state.change_groups(group='root', groups=[], user='user1') + v2 = state.set_acl(default=False, entry=v1, group='root', group_perm={'r'}, logical=False, mask=set(), not_recalc_mask=False, other_perm=set(), physical=False, recalc_mask=False, recursive=False, set_mask=False, sudo_user='root', user='root', user_perm=set()) + state.listdir(dir=v1, user='user1') + state.teardown() + + def test_acl_1006(self): + # SEE https://github.com/juicedata/jfs/issues/1006 + state = JuicefsMachine() + v1 = state.init_folders() + state.create_file(content=b'', file_name='aaaa', mode='w', parent=v1, umask=0, user='root') + state.set_acl(default=False, entry=v1, group='root', group_perm={'r'}, logical=False, mask=set(), not_recalc_mask=False, other_perm=set(), physical=False, recalc_mask=False, recursive=True, set_mask=False, sudo_user='root', user='root', user_perm=set()) + state.set_acl(default=False, entry=v1, group='user1', group_perm={'r'}, logical=False, mask=set(), not_recalc_mask=False, other_perm=set(), physical=False, recalc_mask=False, recursive=False, set_mask=False, sudo_user='root', user='root', user_perm=set()) + state.set_acl(default=False, entry=v1, group='root', group_perm={'r'}, logical=False, mask=set(), not_recalc_mask=False, other_perm=set(), physical=False, recalc_mask=False, recursive=True, set_mask=False, sudo_user='user1', user='root', user_perm=set()) + state.teardown() + + def test_acl_1011(self): + # SEE https://github.com/juicedata/jfs/issues/1011 + state = JuicefsMachine() + v1 = state.init_folders() + state.chmod(entry=v1, mode=0, user='root') + state.split_dir(dir=v1, vdirs=2) + state.change_groups(group='root', groups=[], user='user1') + v2 = state.set_acl(default=False, entry=v1, group='root', group_perm={'r'}, logical=False, mask=set(), not_recalc_mask=False, other_perm=set(), physical=False, recalc_mask=False, recursive=False, set_mask=False, sudo_user='root', user='root', user_perm=set()) + v3 = state.create_file(content=b'', file_name='aaaa', mode='w', parent=v1, umask=0, user='root') + state.listdir(dir=v1, user='user1') + state.teardown() + + def test_acl_1044(self): + # SEE: https://github.com/juicedata/jfs/issues/1044 + state = JuicefsMachine() + v1 = state.init_folders() + v3 = state.create_file(content=b'', file_name='aaca', mode='w', parent=v1, umask=0, user='root') + v4 = state.set_xattr(file=v3, flag=2, name='0', user='root', value=b"abc") + v5 = state.set_acl(default=False, entry=v3, group='root', group_perm={'r'}, logical=False, mask={'r'}, not_recalc_mask=False, other_perm=set(), physical=False, recalc_mask=False, recursive=False, set_mask=False, sudo_user='root', user='root', user_perm={'r'}) + state.remove_acl(entry=v3, option='--remove-all', user='root') + state.list_xattr(file=v3, user='root') + state.teardown() + + def skip_test_acl_4458(self): + # SEE: https://github.com/juicedata/juicefs/issues/4458 state = JuicefsMachine() v1 = state.init_folders() - v2 = state.create_file(content=b'', file_name='aaab', parent=v1) - v3 = state.hardlink(dest_file=v2, link_file_name='aaaa', parent=v1) - state.rename_file(entry=v3, new_entry_name='aaab', parent=v1) + v3 = state.set_acl(default=True, entry=v1, group='root', group_perm=set(), logical=False, mask=set(), not_recalc_mask=False, other_perm=set(), physical=False, recalc_mask=True, recursive=True, set_mask=True, sudo_user='root', user='user1', user_perm={v1, 'r', 'w', 'x'}) + state.create_file(content=b'', file_name='afds', mode='w', parent=v1, umask=295, user='root') state.teardown() if __name__ == '__main__': diff --git a/.github/scripts/hypo/strategy.py b/.github/scripts/hypo/strategy.py index a3d41f699b8d..6873d7665835 100644 --- a/.github/scripts/hypo/strategy.py +++ b/.github/scripts/hypo/strategy.py @@ -22,7 +22,7 @@ st_xattr_name = st.text(st.characters(), min_size=1, max_size=MAX_XATTR_NAME).filter(lambda x: '\x00' not in x) st_xattr_value = st.binary(min_size=1, max_size=MAX_XATTR_VALUE) st_umask = st.integers(min_value=0o000, max_value=0o777) -st_entry_mode = st.integers(min_value=0o000, max_value=0o7777) +st_entry_mode = st.integers(min_value=0o000, max_value=0o7777).filter(lambda x: x & 0o070 != 0) st_open_mode = st.sampled_from(['w', 'x', 'a']) st_open_flags = st.lists(st.sampled_from([os.O_RDONLY, os.O_WRONLY, os.O_RDWR, os.O_APPEND, os.O_CREAT, os.O_EXCL, os.O_TRUNC, os.O_SYNC, os.O_DSYNC, os.O_RSYNC]), unique=True, min_size=1) st_time=st.integers(min_value=0, max_value=int(time.time())) diff --git a/.github/workflows/fsrand2.yml b/.github/workflows/fsrand2.yml index bc4c16fed52a..e0413eb2b1b6 100644 --- a/.github/workflows/fsrand2.yml +++ b/.github/workflows/fsrand2.yml @@ -99,17 +99,16 @@ jobs: else PROFILE='pull_request' fi - sudo -E PROFILE=${PROFILE} python3 .github/scripts/hypo/fsrand2.py + sudo -E PROFILE=${PROFILE} python3 .github/scripts/hypo/fsrand2.py 2>&1 | tee fsrand.log + exit ${PIPESTATUS[0]} - name: check fsrand.log if: always() - shell: bash run: | tail -500 fsrand.log - + - name: check juicefs.log if: always() - shell: bash run: | if [ -f ~/.juicefs/juicefs.log ]; then tail -300 ~/.juicefs/juicefs.log