diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 29f27fa4..36dc8956 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -1,13 +1,20 @@ name: Pylint -on: [push] +on: + push: + branches: [master ] + + pull_request: + branches: [ master ] + types: [ opened, synchronize, reopened ] + jobs: build: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.7","3.8", "3.9", "3.10"] + python-version: ["3.9", "3.10", "3.11", "3.13"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} diff --git a/Gentest.py b/Gentest.py index a6ce7abd..bfb31955 100755 --- a/Gentest.py +++ b/Gentest.py @@ -27,26 +27,27 @@ import argparse patch_file = sys.argv[1] -final_py_file = 'test_'+sys.argv[1]+'.py' -data_file= 'sudocode.txt' +final_py_file = 'test_' + sys.argv[1] + '.py' +data_file = 'sudocode.txt' WCA_CLI_PATH = 'wca-api/WCA_CLI' -WCA_CLI_REPO_URL="https://github.ibm.com/code-assistant/wca-api.git" +WCA_CLI_REPO_URL = "https://github.ibm.com/code-assistant/wca-api.git" + def run_wca_cli_commands(patch_file, data_file): - #Check APIKEY exist in enviroment + # Check APIKEY exist in enviroment if not os.getenv("IAM_APIKEY"): print("Error: IAM_APIKEY is not set. Please export it by -> export IAM_APIKEY=your_api_key_here and make sure having python3.13+ Environment") sys.exit(1) - - #Ensure WCA_CLI repo exists locally. If not, automatically clone it. + + # Ensure WCA_CLI repo exists locally. If not, automatically clone it. if not os.path.isdir(WCA_CLI_PATH): print("The '{WCA_CLI_PATH}' directory does not exist.") print("Cloning repository from {WCA_CLI_REPO_URL}...") subprocess.run(["git", "clone", WCA_CLI_REPO_URL]) print("Repository cloned successfully!") - #Run WCA_CLI commands to gather explanations and generate test code. + # Run WCA_CLI commands to gather explanations and generate test code. history = [ "What specific issues does this patch address", "Are there any prerequisites or dependencies for applying this patch" @@ -55,26 +56,25 @@ def run_wca_cli_commands(patch_file, data_file): history1 = [ "generate a python py unitest for the patch using the avocado-misc-tests style", ] - - for i,prompt in enumerate(history,start=1): - command = [ - "python", "wca-api/WCA_CLI/wca_cli.py", "prompt", prompt, - "--source-file", patch_file - ] - print(f"Executing {i}: {prompt}") - subprocess.run(command) - print("\n") - - for i, prompt1 in enumerate(history1, start=1): - with open(data_file, "w") as outfile: - command = [ - "python", "wca-api/WCA_CLI/wca_cli.py", "unit-test", "--using", "avacado framework", - patch_file - ] - print(f"Executing {i}: {prompt1}") - subprocess.run(command, stdout=outfile) - print("\n") + for i, prompt in enumerate(history, start=1): + command = [ + "python", "wca-api/WCA_CLI/wca_cli.py", "prompt", prompt, + "--source-file", patch_file + ] + print(f"Executing {i}: {prompt}") + subprocess.run(command) + print("\n") + + for i, prompt1 in enumerate(history1, start=1): + with open(data_file, "w") as outfile: + command = [ + "python", "wca-api/WCA_CLI/wca_cli.py", "unit-test", "--using", "avacado framework", + patch_file + ] + print(f"Executing {i}: {prompt1}") + subprocess.run(command, stdout=outfile) + print("\n") def extract_python_code(input_file, output_file): @@ -115,6 +115,7 @@ def extract_python_code(input_file, output_file): # Outside block in_code_block = False + def main(): parser = argparse.ArgumentParser( @@ -135,10 +136,10 @@ def main(): ) args = parser.parse_args() - print("Running WCA_CLI commands for patch:",patch_file) + print("Running WCA_CLI commands for patch:", patch_file) run_wca_cli_commands(patch_file, data_file) - print("Extracting Python code from "+data_file+" to "+ final_py_file) + print("Extracting Python code from " + data_file + " to " + final_py_file) extract_python_code(data_file, final_py_file) diff --git a/avocado-setup.py b/avocado-setup.py index f1304308..6475da2b 100644 --- a/avocado-setup.py +++ b/avocado-setup.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# pylint: disable=E0602 # Copyright (C) IBM Corp. 2016. # # This program is free software: you can redistribute it and/or modify @@ -50,7 +51,8 @@ class Result(Enum): Failures = "failures" Skip = "skip" Warn = "warn" - Interrupt ="interrupt" + Interrupt = "interrupt" + class Testsuite_status(Enum): Total = "Total" @@ -58,8 +60,10 @@ class Testsuite_status(Enum): Not_Run = "Not_Run" Cant_Run = "Cant_Run" -count_result = { _.value : 0 for _ in Result} -count_testsuites_status = { _.value : 0 for _ in Testsuite_status} + +count_result = {_.value: 0 for _ in Result} +count_testsuites_status = {_.value: 0 for _ in Testsuite_status} + class TestSuite(): """ @@ -146,9 +150,9 @@ def env_check(enable_kvm): if packages != '': env_deps = packages.split(',') for dep in env_deps: - if(dep[-1] == "$"): - #Substrings - formatted_dep=dep[:-1] + if dep[-1] == "$": + # Substrings + formatted_dep = dep[:-1] original_dep = formatted_dep else: #Absoulute strings @@ -439,6 +443,7 @@ def run_test(testsuite, avocado_bin, runner, linux_src_path): test_bucket = "_".join([out[1], out[2]]) logger.info("Capturing the Gcov data.....") if test_bucket.startswith("io_"): + driver_name = None with open(input_file, 'r') as file: for line in file: if line.startswith("module"): @@ -712,11 +717,11 @@ def parse_test_config(test_config_file, avocado_bin, enable_kvm, runner): default=None, help="To run the host tests provided in the option and publish result [Note: test names(full path) and separated by comma]") parser.add_argument('--config-env', dest='CONFIG_PATH', - action='store', default=CONFIG_PATH, - help='Specify env config path') + action='store', default=CONFIG_PATH, + help='Specify env config path') parser.add_argument('--config-norun', dest='NORUNTEST_PATH', - action='store', default=NORUNTEST_PATH, - help='Specify no run tests config path') + action='store', default=NORUNTEST_PATH, + help='Specify no run tests config path') args = parser.parse_args() @@ -742,19 +747,19 @@ def parse_test_config(test_config_file, avocado_bin, enable_kvm, runner): logger.error(f"No Run Config Path: {args.NORUNTEST_PATH} not defined") sys.exit(1) - globals() ['TEST_CONF_PATH'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'test_cfg_dir'))) - globals() ['LOG_DIR'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'results_dir'))) - globals() ['TEST_DIR'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'test_dir'))) - globals() ['DATA_DIR'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'data_dir'))) - globals() ['prescript'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'pre_script_dir'))) - globals() ['postscript'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'post_script_dir'))) - globals() ['BASE_FRAMEWORK'] = eval(CONFIGFILE.get('framework', 'base')) - globals() ['KVM_FRAMEWORK'] = eval(CONFIGFILE.get('framework', 'kvm')) - globals() ['OPTIONAL_FRAMEWORK'] = eval(CONFIGFILE.get('framework', 'optional')) - globals() ['TEST_REPOS'] = eval(CONFIGFILE.get('tests', 'name')) - globals() ['prescript_dir'] = CONFIGFILE.get('script-dir', 'prescriptdir') - globals() ['postscript_dir'] = CONFIGFILE.get('script-dir', 'postscriptdir') - globals() ['PIP_PACKAGES'] = eval(CONFIGFILE.get('pip-package', 'package')) + globals()['TEST_CONF_PATH'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'test_cfg_dir'))) + globals()['LOG_DIR'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'results_dir'))) + globals()['TEST_DIR'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'test_dir'))) + globals()['DATA_DIR'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'data_dir'))) + globals()['prescript'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'pre_script_dir'))) + globals()['postscript'] = os.path.join(BASE_PATH, eval(CONFIGFILE.get('paths', 'post_script_dir'))) + globals()['BASE_FRAMEWORK'] = eval(CONFIGFILE.get('framework', 'base')) + globals()['KVM_FRAMEWORK'] = eval(CONFIGFILE.get('framework', 'kvm')) + globals()['OPTIONAL_FRAMEWORK'] = eval(CONFIGFILE.get('framework', 'optional')) + globals()['TEST_REPOS'] = eval(CONFIGFILE.get('tests', 'name')) + globals()['prescript_dir'] = CONFIGFILE.get('script-dir', 'prescriptdir') + globals()['postscript_dir'] = CONFIGFILE.get('script-dir', 'postscriptdir') + globals()['PIP_PACKAGES'] = eval(CONFIGFILE.get('pip-package', 'package')) if helper.get_machine_type() == 'pHyp': args.enable_kvm = False diff --git a/lib/helper.py b/lib/helper.py index 132786d9..f850f4ba 100644 --- a/lib/helper.py +++ b/lib/helper.py @@ -211,7 +211,7 @@ def remove_file(src, dest): class PipMagager: - def __init__(self, base_fw=[], opt_fw=[], kvm_fw=[],pip_packages=[], enable_kvm=False): + def __init__(self, base_fw=[], opt_fw=[], kvm_fw=[], pip_packages=[], enable_kvm=False): """ helper class to parse, install, uninstall pip package from user config """ @@ -254,7 +254,7 @@ def install(self): for package in self.install_packages: cmd = '%s %s' % (pip_installcmd, package) if (self.pip_vmajor > 23) or (self.pip_vmajor == 23 and self.pip_vminor >= 1): - cmd = cmd + ' --break-system-packages' # --break-system-packages introduced in pip 23.1 + cmd = cmd + ' --break-system-packages' # --break-system-packages introduced in pip 23.1 runcmd(cmd, err_str='Package installation via pip failed: package %s' % package, debug_str='Installing python package %s using pip' % package) @@ -263,13 +263,12 @@ def uninstall(self): for package in self.uninstall_packages: cmd = '%s uninstall %s -y --disable-pip-version-check' % (self.pip_cmd, package) if (self.pip_vmajor > 23) or (self.pip_vmajor == 23 and self.pip_vminor >= 1): - cmd = cmd + ' --break-system-packages' # --break-system-packages introduced in pip 23.1 + cmd = cmd + ' --break-system-packages' # --break-system-packages introduced in pip 23.1 runcmd(cmd, ignore_status=True, err_str="Error in removing package: %s" % package, debug_str="Uninstalling %s" % package) - class RemoteRunner: """ SSH-based remote command runner using ``sshpass`` + the system ``ssh`` diff --git a/lib/hmc.py b/lib/hmc.py index 3c288e00..0e1b1c36 100644 --- a/lib/hmc.py +++ b/lib/hmc.py @@ -392,7 +392,7 @@ def get_vios_info(self, managed_system): continue # Format: "ltcden7-vios1,vioserver" parts = line.split(',') - name = parts[0].strip() + name = parts[0].strip() lpar_env = parts[1].strip() if len(parts) > 1 else '' # Match on lpar_env containing "vio" OR partition name containing "vios" if ('vio' in lpar_env.lower() or 'vios' in name.lower()) and name: @@ -419,7 +419,7 @@ def get_vios_info(self, managed_system): if len(names) == 1: names = names * 2 vios_names = ' '.join(names) - vios_ip = ' '.join(v['ip'] for v in vios_list if v['ip']) + vios_ip = ' '.join(v['ip'] for v in vios_list if v['ip']) logger.info("VIOS on '%s': names=%s ips=%s", managed_system, vios_names, vios_ip) return {'vios_names': vios_names, 'vios_ip': vios_ip, 'vios_list': vios_list} diff --git a/lib/pci.py b/lib/pci.py index 74737a4b..f6bbb9b3 100644 --- a/lib/pci.py +++ b/lib/pci.py @@ -23,6 +23,12 @@ import platform from .helper import runcmd, is_rhel8 from lib.logger import logger_init + + +class NWException(Exception): + """Exception for network/PCI related errors.""" + + BASE_PATH = os.path.dirname(os.path.abspath(__file__)) logger = logger_init(filepath=BASE_PATH).getlogger() @@ -307,8 +313,8 @@ def get_interfaces_in_pci_address(pci_address, pci_class): if not pci_class or not os.path.isdir(pci_class_path): return "" return [interface for interface in os.listdir(pci_class_path) - if os.path.islink(os.path.join(pci_class_path, interface)) and pci_address \ - in os.readlink(os.path.join(pci_class_path, interface))] + if os.path.islink(os.path.join(pci_class_path, interface)) and pci_address + in os.readlink(os.path.join(pci_class_path, interface))] def get_pci_class_name(pci_address): @@ -633,6 +639,7 @@ def get_secondary_ioa(primary_ioa): return ioa_detail['ioa'] return '' + def is_sriov(pci_address): """ Check if interface is a SRIOV virtual interface. diff --git a/lib/virtual.py b/lib/virtual.py index 132af1e9..54f223d6 100644 --- a/lib/virtual.py +++ b/lib/virtual.py @@ -34,7 +34,6 @@ import re import os -import platform from .helper import runcmd from lib.logger import logger_init @@ -211,4 +210,4 @@ def virtual_info(interface, runner=None): virtual_dict['adapter_type'] = 'hnv' virtual_list.append(virtual_dict) - return virtual_list \ No newline at end of file + return virtual_list diff --git a/pci_info.py b/pci_info.py index eeced534..c0928fff 100644 --- a/pci_info.py +++ b/pci_info.py @@ -43,6 +43,7 @@ logger = logger_init(filepath=BASE_PATH).getlogger() + def create_config_inputs(orig_cfg, new_cfg, inputfile, interface, config_type): """ 1. Creates modified configuration file name according to type of interface from original configuration file @@ -174,11 +175,12 @@ def create_config_file(interface_details, config_type): continue return create_config_inputs(orig_cfg, new_cfg, inputfile, virtual, config_type=config_type) - + # If we reach here, interface_details was empty or all items were skipped logger.warning("No valid virtual interface config found in create_config_file") return None + def create_config(interface_details, config_type): """ Creates avocado test suite / config file, and input file needed for yaml files in that config files. @@ -186,7 +188,7 @@ def create_config(interface_details, config_type): test_suites = [] input_file_string = "" input_params = [] - + if config_type == 'pci': for pci in interface_details: if pci['is_root_disk']: @@ -201,8 +203,8 @@ def create_config(interface_details, config_type): new_cfg = "io_%s_rhel8_%s_fvt" % (pci['adapter_type'], cfg_name) inputfile = "%s/io_%s_rhel8_input.txt" % ( BASE_INPUTFILE_PATH, pci['adapter_type']) - elif pci['adapter_type'] == 'network' and is_sriov(pci[ -'pci_root']): + elif pci['adapter_type'] == 'network' and is_sriov( + pci['pci_root']): orig_cfg = "io_nic_sriov_fvt" new_cfg = "io_nic_sriov_%s_fvt" % cfg_name inputfile = "%s/io_nic_sriov_input.txt" % BASE_INPUTFILE_PATH @@ -213,9 +215,9 @@ def create_config(interface_details, config_type): BASE_INPUTFILE_PATH, pci['adapter_type']) if not os.path.exists("config/tests/host/%s.cfg" % orig_cfg): logger.debug("ignoring pci address %s as there is no cfg for %s", - pci['pci_root'], pci['adapter_type']) + pci['pci_root'], pci['adapter_type']) continue - + result = create_config_inputs(orig_cfg, new_cfg, inputfile, pci, config_type='pci') if result is None: logger.warning("No input params found for %s; skipping input file generation", orig_cfg) @@ -243,6 +245,7 @@ def create_config(interface_details, config_type): return cmd return "" + if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--pci-address', dest='pci_addr', @@ -494,7 +497,7 @@ def create_config(interface_details, config_type): password=args.hmc_password) as hmc: _vios_info = hmc.get_vios_info(_manage_system) _vios_names = _vios_info.get('vios_names', '') - _vios_ip = _vios_info.get('vios_ip', '') + _vios_ip = _vios_info.get('vios_ip', '') logger.info("VIOS names: %s VIOS IPs: %s", _vios_names, _vios_ip) except Exception as _vios_err: logger.warning("Could not retrieve VIOS info: %s", _vios_err) @@ -506,8 +509,8 @@ def create_config(interface_details, config_type): ]: for _d in _details: _d['manageSystem'] = _manage_system - _d['vios_names'] = _vios_names - _d['vios_ip'] = _vios_ip + _d['vios_names'] = _vios_names + _d['vios_ip'] = _vios_ip # ------------------------------------------------------------------ # # host_ip: derive 192.168.10. from the local public IP. @@ -523,7 +526,7 @@ def create_config(interface_details, config_type): if pub_ip: last_octet = pub_ip.split('.')[-1] _d['host_ip'] = '192.168.10.%s' % last_octet - + # Assign host_ips based on number of interfaces num_interfaces = len(_d.get('interfaces', [])) if num_interfaces > 1: @@ -532,7 +535,7 @@ def create_config(interface_details, config_type): else: _d['host_ips'] = '192.168.10.%s' % last_octet _d['netmasks'] = '255.255.255.0' - + logger.info( "Derived host_ip=%s host_ips=%s from public_interface_ip=%s (interfaces: %d)", _d['host_ip'], _d['host_ips'], pub_ip, num_interfaces,