diff --git a/oec-hardware-1.1.5-1-add-virtual-branch-fix-bug.patch b/oec-hardware-1.1.5-1-add-virtual-branch-fix-bug.patch new file mode 100644 index 0000000000000000000000000000000000000000..e2b5a7ec76fe23335d7790ef9e53e59f89a72884 --- /dev/null +++ b/oec-hardware-1.1.5-1-add-virtual-branch-fix-bug.patch @@ -0,0 +1,29904 @@ +diff -Naur rpm/config/test_config.yaml oech/config/test_config.yaml +--- rpm/config/test_config.yaml 2023-10-24 22:25:50.000000000 +0800 ++++ oech/config/test_config.yaml 2023-12-07 15:01:42.217942181 +0800 +@@ -1,75 +1,75 @@ +-# Copyright (c) 2023 Huawei Technologies Co., Ltd. +-# # oec-hardware is licensed under the Mulan PSL v2.gica's +-# # You can use this software according to the terms and conditions of the Mulan PSL v2. +-# # You may obtain a copy of Mulan PSL v2 at: +-# # http://license.coscl.org.cn/MulanPSL2 +-# # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +-# # IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +-# # PURPOSE. +-# # See the Mulan PSL v2 for more details. +-# # Author: +-# # # Create: 2023-09-11 +-# #device: fc\raid\ethernet\infiniband testcase need configuration, It is obtained from the OECH command line interface and +-# needs to be enclosed in single quotation marks +-#disk: fc\raid\disk testcase need configuration, The disk to be tested, such as sda; Or all, test all qualified disks. +-#if_rdma: ethernet testcase need configuration, N means to test according to ordinary network card, y means to test according to RDMA card +-#server_ip: ethernet\infiniband testcase need configuration. If the server port is modified, need to add the port number after the IP address. eg: 2.2.2.4:8090. +-# User need to delete the ip manually which are configured by tool after testing. +-#clent_ip: ethernet\infiniband testcase need configuration. IP to be configured for the client port +-fc: +- fc1: +- device: '0000:03:00.0' +- disk: all +- fc2: +- device: '0000:03:00.1' +- disk: sda +-raid: +- raid1: +- device: '0000:02:00.0' +- disk: all +- raid2: +- device: '0000:0a:00.1' +- disk: sdb +-disk: all +-ethernet: +- # IP has been manually configured, get server IP. +- eth1: +- device: enp125s0f0 +- if_rdma: N +- client_ip: +- server_ip: 2.2.2.4 +- # Configure the IP obtained here. +- eth2: +- device: enp125s0f1 +- if_rdma: N +- client_ip: 2.2.2.3 +- server_ip: 2.2.2.4 +- # The program automatically generates an IP address for IP configuration +- eth3: +- device: enp125s0f2 +- if_rdma: y +- client_ip: +- server_ip: +-infiniband: +- # IP has been manually configured, get server IP. +- ib1: +- device: ibp1s0 +- client_ip: +- server_ip: 2.2.2.4 +- # Configure the IP obtained here. +- ib2: +- device: ibp1s0 +- client_ip: 2.2.2.3 +- server_ip: 2.2.2.4:8090 +- # The program automatically generates an IP address for IP configuration +- ib3: +- device: ibp1s0 +- client_ip: +- server_ip: +-kabiwhitelist: +- ko1: +- ko_name: '' +- ko2: +- ko_name: '' +- rpm: +- rpm_name: '' ++# Copyright (c) 2023 Huawei Technologies Co., Ltd. ++# # oec-hardware is licensed under the Mulan PSL v2.gica's ++# # You can use this software according to the terms and conditions of the Mulan PSL v2. ++# # You may obtain a copy of Mulan PSL v2 at: ++# # http://license.coscl.org.cn/MulanPSL2 ++# # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# # IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# # PURPOSE. ++# # See the Mulan PSL v2 for more details. ++# # Author: ++# # # Create: 2023-09-11 ++# #device: fc\raid\ethernet\infiniband testcase need configuration, It is obtained from the OECH command line interface and ++# needs to be enclosed in single quotation marks ++#disk: fc\raid\disk testcase need configuration, The disk to be tested, such as sda; Or all, test all qualified disks. ++#if_rdma: ethernet testcase need configuration, N means to test according to ordinary network card, y means to test according to RDMA card ++#server_ip: ethernet\infiniband testcase need configuration. If the server port is modified, need to add the port number after the IP address. eg: 2.2.2.4:8090. ++# User need to delete the ip manually which are configured by virtualization after testing. ++#clent_ip: ethernet\infiniband testcase need configuration. IP to be configured for the client port ++fc: ++ fc1: ++ device: '0000:03:00.0' ++ disk: all ++ fc2: ++ device: '0000:03:00.1' ++ disk: sda ++raid: ++ raid1: ++ device: '0000:02:00.0' ++ disk: all ++ raid2: ++ device: '0000:0a:00.1' ++ disk: sdb ++disk: all ++ethernet: ++ # IP has been manually configured, get server IP. ++ eth1: ++ device: enp125s0f0 ++ if_rdma: N ++ client_ip: ++ server_ip: 2.2.2.4 ++ # Configure the IP obtained here. ++ eth2: ++ device: enp125s0f1 ++ if_rdma: N ++ client_ip: 2.2.2.3 ++ server_ip: 2.2.2.4 ++ # The program automatically generates an IP address for IP configuration ++ eth3: ++ device: enp125s0f2 ++ if_rdma: y ++ client_ip: ++ server_ip: ++infiniband: ++ # IP has been manually configured, get server IP. ++ ib1: ++ device: ibp1s0 ++ client_ip: ++ server_ip: 2.2.2.4 ++ # Configure the IP obtained here. ++ ib2: ++ device: ibp1s0 ++ client_ip: 2.2.2.3 ++ server_ip: 2.2.2.4:8090 ++ # The program automatically generates an IP address for IP configuration ++ ib3: ++ device: ibp1s0 ++ client_ip: ++ server_ip: ++kabiwhitelist: ++ ko1: ++ ko_name: '' ++ ko2: ++ ko_name: '' ++ rpm: ++ rpm_name: '' +diff -Naur rpm/hwcompatible/cert_info.py oech/hwcompatible/cert_info.py +--- rpm/hwcompatible/cert_info.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/hwcompatible/cert_info.py 2023-12-07 15:01:42.221942234 +0800 +@@ -28,16 +28,17 @@ + self.logger = logger + self.command = command + +- def create_json(self, device): ++ def create_json(self, device_name, device): + """ + Create hardware information json + Args: ++ device_name: device name + device: hardware device + Returns: True/False + """ + if not device or not device.quad: + self.logger.warning( +- "The %s doesn't have quadruple information, couldn't get hardware." % device.name) ++ "The %s doesn't have quadruple information, couldn't get hardware." % device_name) + return False + + if device.quad in self.cert_quads: +@@ -49,7 +50,7 @@ + + self.logger.info( + "Please input sha256, driverSize, downloadLink for %s manually " +- "if you use outbox driver." % device.name) ++ "if you use outbox driver." % device_name) + + oec_json["vendorID"] = device.quad[0] + oec_json["deviceID"] = device.quad[1] +@@ -62,7 +63,7 @@ + oec_json["chipVendor"] = chip_vendor[0].strip("\n") + oec_json["boardModel"] = device.board + oec_json["chipModel"] = device.chip +- oec_json["type"] = device.name.upper() ++ oec_json["type"] = device_name.upper() + arch = self.command.run_cmd("uname -m", log_print=False) + oec_json["architecture"] = arch[0].strip("\n") + os_cmd = self.command.run_cmd( +diff -Naur rpm/hwcompatible/common.py oech/hwcompatible/common.py +--- rpm/hwcompatible/common.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/hwcompatible/common.py 2023-12-07 15:01:42.221942234 +0800 +@@ -25,12 +25,13 @@ + from .command import Command + + +-def create_test_suite(test_factory, logger, subtests_filter=None): ++def create_test_suite(test_factory, logger, category="compatible", subtests_filter=None): + """ + Create test suites for job testing + Args: + test_factory (list): total test factory + logger (Logger): logger object to record ++ category (str): test category + subtests_filter (list, optional): filter object. Defaults to None. + + Returns: +@@ -47,7 +48,7 @@ + test_suite.append(testcase) + test_name.append(test["name"]) + +- if test["name"] not in NODEVICE: ++ if category == "compatible" and test["name"] not in NODEVICE: + kabi_select = 1 + if "kabi" in test_name: + kabi_select = 0 +diff -Naur rpm/hwcompatible/compatibility.py oech/hwcompatible/compatibility.py +--- rpm/hwcompatible/compatibility.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/hwcompatible/compatibility.py 2023-12-07 15:01:42.221942234 +0800 +@@ -30,7 +30,7 @@ + from .client import Client + from .common import create_test_suite, copy_pci, search_factory + from .constants import NODEVICE, GPU_DRIVER, IB, CDTYPES, KEYCARD_VENDORS, \ +- BOARD, VERSION, DRIVER, CHIP, DEVICE_INFO ++ BOARD, VERSION, DRIVER, CHIP, DEVICE_INFO, TEST_CATEGORY + + + class EulerCertification(): +@@ -47,17 +47,24 @@ + self.dir_name = None + self.logger = logger + self.command = Command(logger) ++ self.category = '' + + def run(self): + """ + Openeuler compatibility verification + :return: + """ +- self.logger.info( +- "The openEuler Hardware Compatibility Test Suite", log_print=False) +- copy_pci() ++ self._select_category() ++ if self.category == "virtualization": ++ self.logger.info( ++ "The openEuler Virtualization Test Suite") ++ elif self.category == "compatible": ++ self.logger.info( ++ "The openEuler Hardware Compatibility Test Suite") ++ copy_pci() ++ certdevice = CertDevice(self.logger) ++ + self.load() +- certdevice = CertDevice(self.logger) + + while True: + self.submit() +@@ -66,15 +73,17 @@ + self.logger.info("All cases are passed, test end.") + return True + +- oec_devices = certdevice.get_devices() +- self.devices = DeviceDocument(CertEnv.devicefile, self.logger, oec_devices) +- self.devices.save() ++ oec_devices = list() ++ if self.category == "compatible": ++ oec_devices = certdevice.get_devices() ++ self.devices = DeviceDocument(CertEnv.devicefile, self.logger, oec_devices) ++ self.devices.save() + test_factory = self.get_tests(oec_devices) + self.update_factory(test_factory) + if not self.choose_tests(): + return True + +- test_suite = create_test_suite(self.test_factory, self.logger) ++ test_suite = create_test_suite(self.test_factory, self.logger, self.category) + args = argparse.Namespace( + test_factory=self.test_factory, test_suite=test_suite) + job = Job(args) +@@ -116,6 +125,8 @@ + os.remove(CertEnv.certificationfile) + if os.path.exists(CertEnv.factoryfile): + os.remove(CertEnv.factoryfile) ++ if os.path.exists(CertEnv.virtfactoryfile): ++ os.remove(CertEnv.virtfactoryfile) + if os.path.exists(CertEnv.devicefile): + os.remove(CertEnv.devicefile) + self.logger.info("Clean compatibility test data succeed.") +@@ -134,7 +145,10 @@ + self.certification.new() + self.certification.save() + if not self.test_factory: +- factory_doc = FactoryDocument(CertEnv.factoryfile, self.logger) ++ if self.category == "virtualization": ++ factory_doc = FactoryDocument(CertEnv.virtfactoryfile, self.logger) ++ elif self.category == "compatible": ++ factory_doc = FactoryDocument(CertEnv.factoryfile, self.logger) + self.test_factory = factory_doc.get_factory() + + oec_id = self.certification.get_certify() +@@ -145,12 +159,12 @@ + self.certification.save() + + display_message = " %s: ".ljust(20) % name + version + "\n" \ +- " Compatibility Test ID: ".ljust(30) + oec_id + "\n" \ +- " Hardware Info: ".ljust(30) + hardware_info + "\n" \ +- " Product URL: ".ljust(30) + self.certification.get_url() + "\n" \ +- " OS Info: ".ljust(30) + self.certification.get_os() + "\n" \ +- " Kernel Info: ".ljust(30) + self.certification.get_kernel() + "\n" \ +- " Test Server: ".ljust(30) + self.certification.get_server() ++ " Compatibility Test ID: ".ljust(30) + oec_id + "\n" \ ++ " Hardware Info: ".ljust(30) + hardware_info + "\n" \ ++ " Product URL: ".ljust(30) + self.certification.get_url() + "\n" \ ++ " OS Info: ".ljust(30) + self.certification.get_os() + "\n" \ ++ " Kernel Info: ".ljust(30) + self.certification.get_kernel() + "\n" \ ++ " Test Server: ".ljust(30) + self.certification.get_server() + self.logger.info(display_message, log_print=False) + + def save(self, job): +@@ -162,10 +176,14 @@ + doc_dir = os.path.join(CertEnv.logdirectoy, job.job_id) + if not os.path.exists(doc_dir): + return +- FactoryDocument(CertEnv.factoryfile, self.logger, self.test_factory).save() ++ if self.category == "virtualization": ++ FactoryDocument(CertEnv.virtfactoryfile, self.logger, self.test_factory).save() ++ shutil.copy(CertEnv.virtfactoryfile, doc_dir) ++ else: ++ FactoryDocument(CertEnv.factoryfile, self.logger, self.test_factory).save() ++ shutil.copy(CertEnv.factoryfile, doc_dir) ++ shutil.copy(CertEnv.devicefile, doc_dir) + shutil.copy(CertEnv.certificationfile, doc_dir) +- shutil.copy(CertEnv.devicefile, doc_dir) +- shutil.copy(CertEnv.factoryfile, doc_dir) + + cwd = os.getcwd() + os.chdir(os.path.dirname(doc_dir)) +@@ -173,13 +191,13 @@ + + "-" + job.job_id + pack_name = self.dir_name + ".tar" + os.rename(job.job_id, self.dir_name) +- ++ + cmd_result = self.command.run_cmd( + "tar -cf %s --exclude '*.lock' %s" % (pack_name, self.dir_name), log_print=False) + if cmd_result[2] != 0: + self.logger.error("Collect job log failed.") + return +- ++ + self.logger.info("Log saved to file: %s succeed." % + os.path.join(os.getcwd(), pack_name)) + shutil.copy(pack_name, CertEnv.datadirectory) +@@ -234,45 +252,58 @@ + self.client = Client(hardware_info, oec_id, self.logger) + return self.client.upload(path, server) + +- def get_tests(self, devices): ++ def get_tests(self, devices=None): + """ + get test items + :param devices: + :return: + """ ++ if devices is None: ++ devices = list() + sort_devices = self.sort_tests(devices) + empty_device = Device(logger=self.logger) + test_factory = list() + casenames = [] +- for (_, dirs, filenames) in os.walk(CertEnv.testdirectoy): ++ test_path = os.path.join(CertEnv.testdirectoy, self.category) ++ for (_, dirs, filenames) in os.walk(test_path): + dirs.sort() + for filename in filenames: + if filename.endswith(".py") and \ + not filename.startswith("__init__"): + casenames.append(filename.split(".")[0]) + +- with open(CertEnv.pcifile) as file: ++ if self.category == "virtualization": + for testname in casenames: +- if sort_devices.get(testname): +- for device in sort_devices[testname]: ++ test = dict() ++ test["name"] = testname ++ test["device"] = empty_device ++ test["run"] = True ++ test["status"] = "NotRun" ++ test["reboot"] = False ++ test_factory.append(test) ++ else: ++ with open(CertEnv.pcifile) as file: ++ for testname in casenames: ++ if sort_devices.get(testname): ++ for device in sort_devices[testname]: ++ test = dict() ++ test["name"] = testname ++ test["device"] = device ++ test["run"] = True ++ test["status"] = "NotRun" ++ test["reboot"] = False ++ test["driverName"] = test.get("device", "").get_driver() ++ test["driverVersion"] = test.get("device", "").get_driver_version() ++ test["boardModel"], test["chipModel"] = test.get("device", "").get_model(testname, file) ++ test_factory.append(test) ++ elif testname in NODEVICE: + test = dict() + test["name"] = testname +- test["device"] = device ++ test["device"] = empty_device + test["run"] = True + test["status"] = "NotRun" + test["reboot"] = False +- test["driverName"] = test.get("device", "").get_driver() +- test["driverVersion"] = test.get("device", "").get_driver_version() +- test["boardModel"], test["chipModel"] = test.get("device", "").get_model(testname, file) + test_factory.append(test) +- elif testname in NODEVICE: +- test = dict() +- test["name"] = testname +- test["device"] = empty_device +- test["run"] = True +- test["status"] = "NotRun" +- test["reboot"] = False +- test_factory.append(test) + return test_factory + + def sort_tests(self, devices): +@@ -370,7 +401,7 @@ + if any([k in id_vendor for k in KEYCARD_VENDORS]): + sort_devices["keycard"] = [device] + continue +- ++ + cmd_result = self.command.run_cmd("dmidecode | grep 'IPMI Device Information'") + if cmd_result[2] == 0: + sort_devices["ipmi"] = [empty_device] +@@ -391,7 +422,10 @@ + + self.logger.info('\033c', log_print=False) + self.logger.info("Select tests to run:", log_print=False) +- self.show_tests() ++ if self.category == "virtualization": ++ self.show_virt_tests() ++ else: ++ self.show_tests() + reply = self.ui.prompt("Selection (|all|none|quit|run): ") + reply = reply.lower() + if reply in ["r", "run"]: +@@ -461,6 +495,33 @@ + device, driver, version, chip, board) + self._print_tests(device) + ++ def show_virt_tests(self): ++ """ ++ show virtualization test items ++ :return: ++ """ ++ self.logger.info("\033[1;35m" + "No.".ljust(4) + "Run-Now?".ljust(10) ++ + "status".ljust(10) + "%s\033[0m" % "Class".ljust(14), log_print=False) ++ num = 0 ++ for test in self.test_factory: ++ name = test["name"] ++ status = test["status"] ++ run = "no" ++ if test["run"] is True: ++ run = "yes" ++ num = num + 1 ++ if status == "PASS": ++ color = "2" ++ elif status == "FAIL": ++ color = "1" ++ elif status == "Force": ++ color = "3" ++ else: ++ color = "4" ++ self.logger.info("%-6d" % num + run.ljust(8) ++ + "\033[0;3%sm%s \033[0m" % (color, status.ljust(8)) ++ + name.ljust(14), log_print=False) ++ + def choose_tests(self): + """ + choose test behavior +@@ -473,8 +534,11 @@ + test["run"] = True + self.logger.info('\033c', log_print=False) + self.logger.info("These tests are recommended to " +- "complete the compatibility test: ", log_print=False) +- self.show_tests() ++ "complete the %s test: " % self.category, log_print=False) ++ if self.category == "virtualization": ++ self.show_virt_tests() ++ else: ++ self.show_tests() + action = self.ui.prompt("Ready to begin testing?", + ["run", "edit", "quit"]) + action = action.lower() +@@ -508,29 +572,33 @@ + if not self.test_factory: + self.test_factory = test_factory + else: +- for test in self.test_factory: +- if not search_factory(test, test_factory): +- self.test_factory.remove(test) +- self.logger.info("delete %s test %s" % (test["name"], +- test["device"].get_name())) +- for test in test_factory: +- if not search_factory(test, self.test_factory): +- self.test_factory.append(test) +- self.logger.info("add %s test %s" % (test["name"], +- test["device"].get_name())) +- for index, test in enumerate(self.test_factory): +- for test_new in test_factory: +- if test["name"] != test_new["name"]: +- continue +- self_test_path = test["device"].path +- new_test_path = test_new["device"].path +- if not self_test_path and not new_test_path: +- continue +- if self_test_path == new_test_path: +- self.test_factory[index]['device'] = test_new['device'] +- ++ if self.category == 'compatible': ++ for test in self.test_factory: ++ if not search_factory(test, test_factory): ++ self.test_factory.remove(test) ++ self.logger.info("delete %s test %s" % (test["name"], ++ test["device"].get_name())) ++ for test in test_factory: ++ if not search_factory(test, self.test_factory): ++ self.test_factory.append(test) ++ self.logger.info("add %s test %s" % (test["name"], ++ test["device"].get_name())) ++ for index, test in enumerate(self.test_factory): ++ for test_new in test_factory: ++ if test["name"] != test_new["name"]: ++ continue ++ self_test_path = test["device"].path ++ new_test_path = test_new["device"].path ++ if not self_test_path and not new_test_path: ++ continue ++ if self_test_path == new_test_path: ++ self.test_factory[index]['device'] = test_new['device'] ++ if self.category == "virtualization": ++ factoryfile_path = CertEnv.virtfactoryfile ++ else: ++ factoryfile_path = CertEnv.factoryfile + self.test_factory.sort(key=lambda k: k["name"]) +- FactoryDocument(CertEnv.factoryfile, self.logger, self.test_factory).save() ++ FactoryDocument(factoryfile_path, self.logger, self.test_factory).save() + + def _print_tests(self, device): + """ +@@ -540,3 +608,17 @@ + + "\033[0;3%sm%s \033[0m" % (device.color, device.status.ljust(8)) + + device.name.ljust(14) + device.device.ljust(15) + device.driver.ljust(15) + + device.version.ljust(18) + device.chip.ljust(20) + device.board, log_print=False) ++ ++ def _select_category(self): ++ self.logger.info("Please select test category.", log_print=False) ++ self.logger.info("\033[1;35m" + "No.".ljust(6) + "category".ljust(35) + "\033[0m", log_print=False) ++ categories = dict(enumerate(TEST_CATEGORY)) ++ for num, category in categories.items(): ++ self.logger.info("%-6d" % (num + 1) + category.ljust(4)) ++ no = self.ui.prompt("Please select test category No:") ++ if no.isdigit(): ++ no = int(no) ++ if 1 <= no <= len(categories): ++ self.category = categories[no - 1] ++ return ++ self._select_category() +diff -Naur rpm/hwcompatible/constants.py oech/hwcompatible/constants.py +--- rpm/hwcompatible/constants.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/hwcompatible/constants.py 2023-12-07 15:01:42.221942234 +0800 +@@ -25,7 +25,7 @@ + DRIVER = "driverName" + VERSION = "driverVersion" + NODEVICE = ("cpufreq", "memory", "clock", "profiler", "system", +- "stress", "kdump", "perf", "acpi", "watchdog", "kabi", "kabiwhitelist") ++ "stress", "kdump", "perf", "acpi", "watchdog", "kabi", "kabiwhitelist", "longtermstability") + TEST_KABI_ARCH = ("aarch64", "x86_64") + CDTYPES = ("DVD_RW", "DVD_PLUS_RW", "DVD_R", "DVD_PLUS_R", "DVD", + "BD_RE", "BD_R", "BD", "CD_RW", "CD_R", "CD") +@@ -35,6 +35,7 @@ + DEVICE_INFO = ('color', 'status', 'num', 'run', 'name', + 'device', 'driver', 'version', 'chip', 'board') + NO_CONFIG_DEVICES = ("gpu", "vgpu", "nvme", "dpdk", "cdrom", "keycard", "spdk") ++TEST_CATEGORY = ("compatible", "virtualization") + + # File access control + FILE_FLAGS = os.O_WRONLY | os.O_CREAT | os.O_TRUNC +diff -Naur rpm/hwcompatible/env.py oech/hwcompatible/env.py +--- rpm/hwcompatible/env.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/hwcompatible/env.py 2023-12-07 15:01:42.221942234 +0800 +@@ -26,6 +26,7 @@ + certificationfile = os.path.join(datadirectory, "compatibility.json") + devicefile = os.path.join(datadirectory, "device.json") + factoryfile = os.path.join(datadirectory, "factory.json") ++ virtfactoryfile = os.path.join(datadirectory, "virtfactory.json") + rebootfile = os.path.join(datadirectory, "reboot.json") + testdirectoy = "/usr/share/oech/lib/tests" + logdirectoy = "/usr/share/oech/logs" +diff -Naur rpm/hwcompatible/job.py oech/hwcompatible/job.py +--- rpm/hwcompatible/job.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/hwcompatible/job.py 2023-12-07 15:01:42.221942234 +0800 +@@ -101,7 +101,7 @@ + testcase["name"], terminal_print=False) + + if testcase["name"] not in NODEVICE: +- cert_infos.create_json(testcase["device"]) ++ cert_infos.create_json(testcase["name"], testcase["device"]) + else: + testcase["status"] = "FAIL" + self.logger.error("Test %s failed." % +diff -Naur rpm/hwcompatible/sysinfo.py oech/hwcompatible/sysinfo.py +--- rpm/hwcompatible/sysinfo.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/hwcompatible/sysinfo.py 2023-12-07 15:01:42.221942234 +0800 +@@ -12,7 +12,6 @@ + # See the Mulan PSL v2 for more details. + # Create: 2020-04-01 + +-import os + import re + from subprocess import getoutput + +diff -Naur rpm/oec-hardware.spec oech/oec-hardware.spec +--- rpm/oec-hardware.spec 2023-10-24 22:25:50.000000000 +0800 ++++ oech/oec-hardware.spec 2023-12-07 15:01:42.221942234 +0800 +@@ -25,7 +25,7 @@ + Summary: openEuler Hardware Compatibility Test Server + Group: Development/Tools + Requires: python3, python3-devel, python3-flask, python3-uWSGI, python3-werkzeug +-Requires: nginx, tar, qperf, psmisc, dpdk, dpdk-tools, dpdk-devel, net-tools ++Requires: nginx, tar, qperf, psmisc, dpdk, dpdk-tools, dpdk-devel, net-tools, perftest + + %description + openEuler Hardware Compatibility Test Suite +@@ -38,7 +38,7 @@ + + %build + %ifarch x86_64 aarch64 +-strip tests/keycard/libswsds_%{_arch}.so ++strip tests/compatible/keycard/libswsds_%{_arch}.so + %endif + [ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT; + DESTDIR=$RPM_BUILD_ROOT VERSION_RELEASE=%{version} make +diff -Naur rpm/server/server.py oech/server/server.py +--- rpm/server/server.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/server/server.py 2023-12-07 15:01:42.225942288 +0800 +@@ -97,7 +97,10 @@ + job = secure_filename(job) + dir_job = os.path.join(dir_results, host, oec_id, job) + json_info = os.path.join(dir_job, 'compatibility.json') +- json_results = os.path.join(dir_job, 'factory.json') ++ files = os.listdir(dir_job) ++ for file in files: ++ if "factory.json" in file: ++ json_results = os.path.join(dir_job, file) + if not os.path.exists(json_info) or not os.path.exists(json_results): + abort(404) + +@@ -110,7 +113,8 @@ + sys.stderr.write("The file %s is not json file.\n") + return False + +- return render_template('job.html', host=host, id=oec_id, job=job, info=info, results=results) ++ return render_template('job.html', host=host, id=oec_id, job=job, info=info, results=results, ++ json_results=json_results) + + + @app.route('/results////devices/') +@@ -127,7 +131,10 @@ + oec_id = secure_filename(oec_id) + job = secure_filename(job) + dir_job = os.path.join(dir_results, host, oec_id, job) +- json_results = os.path.join(dir_job, 'factory.json') ++ files = os.listdir(dir_job) ++ for file in files: ++ if "factory.json" in file: ++ json_results = os.path.join(dir_job, file) + if not os.path.exists(json_results): + abort(404) + +@@ -159,7 +166,10 @@ + oec_id = secure_filename(oec_id) + job = secure_filename(job) + dir_job = os.path.join(dir_results, host, oec_id, job) +- json_devices = os.path.join(dir_job, 'device.json') ++ files = os.listdir(dir_job) ++ for file in files: ++ if "factory.json" in file: ++ json_devices = os.path.join(dir_job, file) + if not os.path.exists(json_devices): + abort(404) + +diff -Naur rpm/server/templates/job.html oech/server/templates/job.html +--- rpm/server/templates/job.html 2023-10-24 22:25:50.000000000 +0800 ++++ oech/server/templates/job.html 2023-12-07 15:01:42.225942288 +0800 +@@ -41,6 +41,7 @@ + +

Testcase

+ ++ {% if json_results == "factory.json" %} + +

Device

+ +@@ -56,6 +57,7 @@ + +

boardModel

+ ++ {% endif %} + +

Result

+ +@@ -78,6 +80,7 @@ + {% endif %} + + {{ testcase }} ++ {% if json_results == "factory.json" %} + + {{ int }} + +@@ -85,6 +88,7 @@ + {{ d.get('driverVersion', '') }} + {{ d.get('chipModel', '') }} + {{ d.get('boardModel', '') }} ++ {% endif %} + + {{ result }} + +diff -Naur rpm/tests/acpi/acpi.py oech/tests/acpi/acpi.py +--- rpm/tests/acpi/acpi.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/tests/acpi/acpi.py 1970-01-01 08:00:00.000000000 +0800 +@@ -1,38 +0,0 @@ +-#!/usr/bin/env python3 +-# coding: utf-8 +- +-# Copyright (c) 2020 Huawei Technologies Co., Ltd. +-# oec-hardware is licensed under the Mulan PSL v2. +-# You can use this software according to the terms and conditions of the Mulan PSL v2. +-# You may obtain a copy of Mulan PSL v2 at: +-# http://license.coscl.org.cn/MulanPSL2 +-# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +-# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +-# PURPOSE. +-# See the Mulan PSL v2 for more details. +-# Create: 2020-04-01 +- +-from hwcompatible.test import Test +- +- +-class AcpiTest(Test): +- """ +- acpi test +- """ +- +- def __init__(self): +- Test.__init__(self) +- self.requirements = ["acpica-tools"] +- +- def test(self): +- """ +- Test case +- :return: +- """ +- result = self.command.run_cmd("acpidump") +- if result[2] == 0: +- self.logger.info("Test acpi succeed.") +- return True +- +- self.logger.error("Test acpi failed.\n%s" % result[1]) +- return False +diff -Naur rpm/tests/acpi/Makefile oech/tests/acpi/Makefile +--- rpm/tests/acpi/Makefile 2023-10-24 22:25:50.000000000 +0800 ++++ oech/tests/acpi/Makefile 1970-01-01 08:00:00.000000000 +0800 +@@ -1,22 +0,0 @@ +-# Copyright (c) 2020 Huawei Technologies Co., Ltd. +-# oec-hardware is licensed under the Mulan PSL v2. +-# You can use this software according to the terms and conditions of the Mulan PSL v2. +-# You may obtain a copy of Mulan PSL v2 at: +-# http://license.coscl.org.cn/MulanPSL2 +-# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +-# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +-# PURPOSE. +-# See the Mulan PSL v2 for more details. +-# Create: 2020-04-01 +- +-.PHONY: install clean +- +-all: ; +- +-install: +- mkdir -p $(DEST) +- cp -a *.py $(DEST) +- chmod a+x $(DEST)/*.py +- +-clean: +- rm -rf $(DEST) +diff -Naur rpm/tests/cdrom/cdrom.py oech/tests/cdrom/cdrom.py +--- rpm/tests/cdrom/cdrom.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/tests/cdrom/cdrom.py 1970-01-01 08:00:00.000000000 +0800 +@@ -1,271 +0,0 @@ +-#!/usr/bin/env python3 +-# coding: utf-8 +- +-# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. +-# oec-hardware is licensed under the Mulan PSL v2. +-# You can use this software according to the terms and conditions of the Mulan PSL v2. +-# You may obtain a copy of Mulan PSL v2 at: +-# http://license.coscl.org.cn/MulanPSL2 +-# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +-# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +-# PURPOSE. +-# See the Mulan PSL v2 for more details. +-# Create: 2020-04-01 +-# Desc: CDRom test +- +-import os +-import shutil +-import argparse +-from time import sleep +-from hwcompatible.test import Test +-from hwcompatible.command_ui import CommandUI +-from hwcompatible.command import Command +- +- +-class CDRomTest(Test): +- def __init__(self): +- Test.__init__(self) +- self.requirements = ["dvd+rw-tools", +- "cdrkit", "genisoimage", "util-linux"] +- self.method = None +- self.device = None +- self.type = None +- self.com_ui = CommandUI() +- self.test_dir = "/usr/share/doc" +- read_dir = os.getcwd() +- self.mnt_dir = os.path.join(read_dir, "mnt_cdrom") +- self.device_dir = os.path.join(read_dir, "device_dir") +- +- def setup(self, args=None): +- """ +- The Setup before testing +- :param args: +- :return: +- """ +- self.args = args or argparse.Namespace() +- self.logger = getattr(args, "test_logger", None) +- self.device = getattr(args, "device", None) +- self.type = self.get_type(self.device) +- self.command = Command(self.logger) +- self.get_mode(self.type) +- +- def test(self): +- """ +- Test case +- :return: +- """ +- if not (self.method and self.device and self.type): +- return False +- +- if self.method not in dir(self): +- return False +- +- devname = self.device.get_property("DEVNAME") +- self.command.run_cmd("eject %s" % devname, ignore_errors=True) +- while True: +- self.logger.info("Please insert %s disc into %s, then close the tray manually." % ( +- self.type.lower(), devname)) +- if self.method == "write_test": +- self.logger.info("Tips: disc should be new.") +- elif self.method == "read_test": +- self.logger.info("Tips: disc should not be blank.") +- if self.com_ui.prompt_confirm("Done well?"): +- break +- self.command.run_cmd("eject -t %s" % devname, ignore_errors=True) +- self.logger.info( +- "Please wait seconds for media to be inserted.", terminal_print=True) +- sleep(20) +- +- if not getattr(self, self.method)(): +- return False +- return True +- +- def get_type(self, device): +- """ +- Get the type of CDROM +- :param device: +- :return: +- """ +- if not device: +- return None +- +- bd_types = ["BD_RE", "BD_R", "BD"] +- dvd_types = ["DVD_RW", "DVD_PLUS_RW", "DVD_R", "DVD_PLUS_R", "DVD"] +- cd_types = ["CD_RW", "CD_R", "CD"] +- for bd_type in bd_types: +- if device.get_property("ID_CDROM_" + bd_type) == "1": +- return bd_type +- for dvd_type in dvd_types: +- if device.get_property("ID_CDROM_" + dvd_type) == "1": +- return dvd_type +- for cd_type in cd_types: +- if device.get_property("ID_CDROM_" + cd_type) == "1": +- return cd_type +- +- self.logger.error("Find proper test-type for %s failed." % +- device.get_name()) +- return None +- +- def get_mode(self, device_type): +- """ +- Get the read-write mode of CDROM +- :param device_type: +- :return: +- """ +- if not device_type: +- return +- +- if "RW" in device_type or "RE" in device_type: +- self.method = "rw_test" +- elif "_R" in device_type: +- self.method = "write_test" +- else: +- self.method = "read_test" +- +- def rw_test(self): +- """ +- RW mode test of CDROM +- :return: +- """ +- devname = self.device.get_property("DEVNAME") +- self.command.run_cmd("umount %s" % devname, ignore_errors=True) +- if "BD" in self.type: +- self.logger.info("It will format the cdrom.", terminal_print=True) +- self.command.run_cmd("dvd+rw-format -format=full %s" % devname) +- self.reload_disc(devname) +- return self.write_test() +- elif "DVD_PLUS" in self.type: +- self.logger.info("It will format the cdrom.", terminal_print=True) +- self.command.run_cmd("dvd+rw-format -force %s" % devname) +- self.reload_disc(devname) +- return self.write_test() +- else: +- self.logger.info("It will clear data in cdrom.", +- terminal_print=True) +- self.command.run_cmd("cdrecord -v dev=%s blank=fast" % devname) +- self.reload_disc(devname) +- return self.write_test() +- +- def write_test(self): +- """ +- Write mode test of CDROM +- :return: +- """ +- devname = self.device.get_property("DEVNAME") +- self.command.run_cmd("umount %s" % devname, ignore_errors=True) +- if "BD" in self.type or "DVD_PLUS" in self.type: +- grow_cmd = self.command.run_cmd( +- "growisofs -Z %s --quiet -R %s " % (devname, self.test_dir)) +- reload_flag = self.reload_disc(devname) +- if grow_cmd[2] == 0 and reload_flag: +- return True +- return False +- +- write_opts = "-sao" +- cmd_result = self.command.run_cmd( +- "cdrecord dev=%s -checkdrive | grep 'Supported modes'" % devname, ignore_errors=True) +- modes = cmd_result[0] +- if "TAO" in modes: +- write_opts = "-tao" +- if "SAO" in modes: +- write_opts = "-sao" +- cmd_result = self.command.run_cmd( +- "cdrecord dev=%s -checkdrive | grep 'Driver flags'" % devname, ignore_errors=True) +- if "BURNFREE" in cmd_result[0]: +- write_opts += " driveropts=burnfree" +- +- size = self.command.run_cmd( +- "mkisofs -quiet -R -print-size %s" % self.test_dir) +- blocks = int(size[0]) +- +- self.command.run_cmd( +- "mkisofs -o test_cdrom.iso --quiet -r %s" % self.test_dir) +- mkisofs_cmd = self.command.run_cmd( +- "cdrecord -v %s dev=%s fs=32M test_cdrom.iso" % (write_opts, devname)) +- reload_flag = self.reload_disc(devname) +- os.remove("test_cdrom.iso") +- if mkisofs_cmd[2] == 0 and reload_flag: +- return True +- return False +- +- def read_test(self): +- """ +- Read mode test of CDROM +- :return: +- """ +- devname = self.device.get_property("DEVNAME") +- if os.path.exists(self.mnt_dir): +- shutil.rmtree(self.mnt_dir) +- os.mkdir(self.mnt_dir) +- self.logger.info("Check to mount media.", terminal_print=True) +- self.command.run_cmd("umount %s" % devname, ignore_errors=True) +- self.command.run_cmd("mount -o ro %s %s" % (devname, self.mnt_dir)) +- +- cmd_result = self.command.run_cmd( +- "df %s | tail -n1 | awk '{print $3}'" % devname) +- size = int(cmd_result[0]) +- if size == 0: +- self.logger.error("This is a blank disc.") +- self.command.run_cmd("umount %s" % self.mnt_dir) +- shutil.rmtree(self.mnt_dir) +- return False +- +- if os.path.exists(self.device_dir): +- shutil.rmtree(self.device_dir) +- os.mkdir(self.device_dir) +- self.logger.info("Check to copy files.", terminal_print=True) +- self.command.run_cmd("cp -dprf %s/. %s" % (self.mnt_dir, self.device_dir)) +- +- self.logger.info( +- "Check to compare files in directory.", terminal_print=True) +- return_code = self.cmp_tree(self.mnt_dir, self.device_dir) +- self.command.run_cmd("umount %s" % self.mnt_dir) +- if return_code: +- self.logger.info("Compare directory succeed.") +- else: +- self.logger.error("Compare directory failed.") +- +- return return_code +- +- def cmp_tree(self, dir1, dir2): +- """ +- Compare the differences between the two directories +- :param dir1: +- :param dir2: +- :return: +- """ +- if not (dir1 and dir2): +- self.logger.error("Invalid input directory.") +- return False +- +- cmd_result = self.command.run_cmd("diff -r %s %s" % (dir1, dir2)) +- return cmd_result[2] == 0 +- +- def reload_disc(self, device): +- """ +- Reloading the media +- :param device: +- :return: +- """ +- if not device: +- return False +- +- self.logger.info("Check to reload the media.") +- self.command.run_cmd("eject %s" % device) +- self.logger.info("Tray ejected.") +- +- cmd = self.command.run_cmd("eject -t %s" % device) +- if cmd[2] != 0: +- self.logger.error( +- "Could not auto-close the tray, please close the tray manually.") +- self.com_ui.prompt_confirm("Done well?") +- +- sleep(20) +- self.logger.info("Tray auto-closed.\n") +- return True +- +- def teardown(self): +- if os.path.exists(self.mnt_dir): +- shutil.rmtree(self.mnt_dir) +- if os.path.exists(self.device_dir): +- shutil.rmtree(self.device_dir) +diff -Naur rpm/tests/cdrom/Makefile oech/tests/cdrom/Makefile +--- rpm/tests/cdrom/Makefile 2023-10-24 22:25:50.000000000 +0800 ++++ oech/tests/cdrom/Makefile 1970-01-01 08:00:00.000000000 +0800 +@@ -1,22 +0,0 @@ +-# Copyright (c) 2020 Huawei Technologies Co., Ltd. +-# oec-hardware is licensed under the Mulan PSL v2. +-# You can use this software according to the terms and conditions of the Mulan PSL v2. +-# You may obtain a copy of Mulan PSL v2 at: +-# http://license.coscl.org.cn/MulanPSL2 +-# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +-# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +-# PURPOSE. +-# See the Mulan PSL v2 for more details. +-# Create: 2020-04-01 +- +-.PHONY: install clean +- +-all: ; +- +-install: +- mkdir -p $(DEST) +- cp -a *.py $(DEST) +- chmod a+x $(DEST)/*.py +- +-clean: +- rm -rf $(DEST) +diff -Naur rpm/tests/clock/clock.c oech/tests/clock/clock.c +--- rpm/tests/clock/clock.c 2023-10-24 22:25:50.000000000 +0800 ++++ oech/tests/clock/clock.c 1970-01-01 08:00:00.000000000 +0800 +@@ -1,94 +0,0 @@ +-/* +- * Copyright (c) 2020 Huawei Technologies Co., Ltd. +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of version 2 of the GNU General Public +- * License as published by the Free Software Foundation. +- * +- * This program is distributed in the hope that it will be useful, but +- * WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +- * 02110-1301, USA +- */ +- +-#define _GNU_SOURCE 1 +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-int test_clock_direction() +-{ +- time_t starttime = 0; +- time_t stoptime = 0; +- int sleeptime = 60; +- int delta = 0; +- +- printf("clock direction test start\n"); +- time(&starttime); +- sleep(sleeptime); +- time(&stoptime); +- +- delta = (int)stoptime - (int)starttime - sleeptime; +- if (delta != 0) { +- printf("clock direction test fail\n"); +- return 1; +- } else { +- printf("clock direction test complete\n"); +- return 0; +- } +-} +- +-int test_rtc_clock() +-{ +- int rtc, delta; +- struct tm rtc_tm1, rtc_tm2; +- int sleeptime = 120; +- +- printf("rtc_clock test start\n"); +- if ((rtc = open("/dev/rtc", O_WRONLY)) < 0) { +- perror("could not open RTC device"); +- return 1; +- } +- +- if (ioctl(rtc, RTC_RD_TIME, &rtc_tm1) < 0) { +- perror("could not get the RTC time"); +- close(rtc); +- return 1; +- } +- sleep(sleeptime); +- if (ioctl(rtc, RTC_RD_TIME, &rtc_tm2) < 0) { +- perror("could not get the RTC time"); +- close(rtc); +- return 1; +- } +- +- close(rtc); +- delta = (int)mktime(&rtc_tm2) - (int)mktime(&rtc_tm1) - sleeptime; +- if (delta != 0) { +- printf("rtc_clock test fail\n"); +- return 1; +- } else { +- printf("rtc_clock test complete\n"); +- return 0; +- } +-} +- +-int main() +-{ +- int ret = 0; +- ret += test_clock_direction(); +- ret += test_rtc_clock(); +- return ret; +-} +diff -Naur rpm/tests/clock/clock.py oech/tests/clock/clock.py +--- rpm/tests/clock/clock.py 2023-10-24 22:25:50.000000000 +0800 ++++ oech/tests/clock/clock.py 1970-01-01 08:00:00.000000000 +0800 +@@ -1,37 +0,0 @@ +-#!/usr/bin/env python3 +-# coding: utf-8 +- +-# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. +-# oec-hardware is licensed under the Mulan PSL v2. +-# You can use this software according to the terms and conditions of the Mulan PSL v2. +-# You may obtain a copy of Mulan PSL v2 at: +-# http://license.coscl.org.cn/MulanPSL2 +-# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +-# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +-# PURPOSE. +-# See the Mulan PSL v2 for more details. +-# Create: 2020-04-01 +-# Desc: Clock test +- +-import os +-from hwcompatible.test import Test +- +-clock_dir = os.path.dirname(os.path.realpath(__file__)) +- +- +-class ClockTest(Test): +- def __init__(self): +- Test.__init__(self) +- +- def test(self): +- """ +- Clock test case +- :return: +- """ +- result = self.command.run_cmd("%s/clock" % clock_dir) +- if result[2] == 0: +- self.logger.info("Test clock succeed.") +- return True +- +- self.logger.error("Test clock failed.\n %s" % result[1]) +- return False +diff -Naur rpm/tests/clock/Makefile oech/tests/clock/Makefile +--- rpm/tests/clock/Makefile 2023-10-24 22:25:50.000000000 +0800 ++++ oech/tests/clock/Makefile 1970-01-01 08:00:00.000000000 +0800 +@@ -1,34 +0,0 @@ +-# Copyright (c) 2020 Huawei Technologies Co., Ltd. +-# oec-hardware is licensed under the Mulan PSL v2. +-# You can use this software according to the terms and conditions of the Mulan PSL v2. +-# You may obtain a copy of Mulan PSL v2 at: +-# http://license.coscl.org.cn/MulanPSL2 +-# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +-# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +-# PURPOSE. +-# See the Mulan PSL v2 for more details. +-# Create: 2020-04-01 +- +-.PHONY: all install clean +- +-all: clock +- +-CFLAGS+=-Wall +-CFLAGS+=-DCPU_ALLOC +-# sched_setaffinity has no size_t argument on older systems. +-ifeq ($(shell grep 'sched_setaffinity.*size_t' /usr/include/sched.h),) +-CFLAGS+=-DOLD_SCHED_SETAFFINITY +-endif +- +-clock: clock.c +- $(CC) $(CFLAGS) -lrt $< -o $@ +- +-install: +- mkdir -p $(DEST) +- cp -a clock *.py $(DEST) +- chmod a+x $(DEST)/*.py +- +-clean: +- rm -rf $(DEST) +- rm -rf clock +- +diff -Naur rpm/tests/compatible/acpi/acpi.py oech/tests/compatible/acpi/acpi.py +--- rpm/tests/compatible/acpi/acpi.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/acpi/acpi.py 2023-12-07 15:01:42.225942288 +0800 +@@ -0,0 +1,38 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2020 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++ ++from hwcompatible.test import Test ++ ++ ++class AcpiTest(Test): ++ """ ++ acpi test ++ """ ++ ++ def __init__(self): ++ Test.__init__(self) ++ self.requirements = ["acpica-tools"] ++ ++ def test(self): ++ """ ++ Test case ++ :return: ++ """ ++ result = self.command.run_cmd("acpidump") ++ if result[2] == 0: ++ self.logger.info("Test acpi succeed.") ++ return True ++ ++ self.logger.error("Test acpi failed.\n%s" % result[1]) ++ return False +diff -Naur rpm/tests/compatible/acpi/Makefile oech/tests/compatible/acpi/Makefile +--- rpm/tests/compatible/acpi/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/acpi/Makefile 2023-12-07 15:01:42.225942288 +0800 +@@ -0,0 +1,22 @@ ++# Copyright (c) 2020 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a *.py $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/cdrom/cdrom.py oech/tests/compatible/cdrom/cdrom.py +--- rpm/tests/compatible/cdrom/cdrom.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/cdrom/cdrom.py 2023-12-07 15:01:42.225942288 +0800 +@@ -0,0 +1,271 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++# Desc: CDRom test ++ ++import os ++import shutil ++import argparse ++from time import sleep ++from hwcompatible.test import Test ++from hwcompatible.command_ui import CommandUI ++from hwcompatible.command import Command ++ ++ ++class CDRomTest(Test): ++ def __init__(self): ++ Test.__init__(self) ++ self.requirements = ["dvd+rw-tools", ++ "cdrkit", "genisoimage", "util-linux"] ++ self.method = None ++ self.device = None ++ self.type = None ++ self.com_ui = CommandUI() ++ self.test_dir = "/usr/share/doc" ++ read_dir = os.getcwd() ++ self.mnt_dir = os.path.join(read_dir, "mnt_cdrom") ++ self.device_dir = os.path.join(read_dir, "device_dir") ++ ++ def setup(self, args=None): ++ """ ++ The Setup before testing ++ :param args: ++ :return: ++ """ ++ self.args = args or argparse.Namespace() ++ self.logger = getattr(args, "test_logger", None) ++ self.device = getattr(args, "device", None) ++ self.type = self.get_type(self.device) ++ self.command = Command(self.logger) ++ self.get_mode(self.type) ++ ++ def test(self): ++ """ ++ Test case ++ :return: ++ """ ++ if not (self.method and self.device and self.type): ++ return False ++ ++ if self.method not in dir(self): ++ return False ++ ++ devname = self.device.get_property("DEVNAME") ++ self.command.run_cmd("eject %s" % devname, ignore_errors=True) ++ while True: ++ self.logger.info("Please insert %s disc into %s, then close the tray manually." % ( ++ self.type.lower(), devname)) ++ if self.method == "write_test": ++ self.logger.info("Tips: disc should be new.") ++ elif self.method == "read_test": ++ self.logger.info("Tips: disc should not be blank.") ++ if self.com_ui.prompt_confirm("Done well?"): ++ break ++ self.command.run_cmd("eject -t %s" % devname, ignore_errors=True) ++ self.logger.info( ++ "Please wait seconds for media to be inserted.", terminal_print=True) ++ sleep(20) ++ ++ if not getattr(self, self.method)(): ++ return False ++ return True ++ ++ def get_type(self, device): ++ """ ++ Get the type of CDROM ++ :param device: ++ :return: ++ """ ++ if not device: ++ return None ++ ++ bd_types = ["BD_RE", "BD_R", "BD"] ++ dvd_types = ["DVD_RW", "DVD_PLUS_RW", "DVD_R", "DVD_PLUS_R", "DVD"] ++ cd_types = ["CD_RW", "CD_R", "CD"] ++ for bd_type in bd_types: ++ if device.get_property("ID_CDROM_" + bd_type) == "1": ++ return bd_type ++ for dvd_type in dvd_types: ++ if device.get_property("ID_CDROM_" + dvd_type) == "1": ++ return dvd_type ++ for cd_type in cd_types: ++ if device.get_property("ID_CDROM_" + cd_type) == "1": ++ return cd_type ++ ++ self.logger.error("Find proper test-type for %s failed." % ++ device.get_name()) ++ return None ++ ++ def get_mode(self, device_type): ++ """ ++ Get the read-write mode of CDROM ++ :param device_type: ++ :return: ++ """ ++ if not device_type: ++ return ++ ++ if "RW" in device_type or "RE" in device_type: ++ self.method = "rw_test" ++ elif "_R" in device_type: ++ self.method = "write_test" ++ else: ++ self.method = "read_test" ++ ++ def rw_test(self): ++ """ ++ RW mode test of CDROM ++ :return: ++ """ ++ devname = self.device.get_property("DEVNAME") ++ self.command.run_cmd("umount %s" % devname, ignore_errors=True) ++ if "BD" in self.type: ++ self.logger.info("It will format the cdrom.", terminal_print=True) ++ self.command.run_cmd("dvd+rw-format -format=full %s" % devname) ++ self.reload_disc(devname) ++ return self.write_test() ++ elif "DVD_PLUS" in self.type: ++ self.logger.info("It will format the cdrom.", terminal_print=True) ++ self.command.run_cmd("dvd+rw-format -force %s" % devname) ++ self.reload_disc(devname) ++ return self.write_test() ++ else: ++ self.logger.info("It will clear data in cdrom.", ++ terminal_print=True) ++ self.command.run_cmd("cdrecord -v dev=%s blank=fast" % devname) ++ self.reload_disc(devname) ++ return self.write_test() ++ ++ def write_test(self): ++ """ ++ Write mode test of CDROM ++ :return: ++ """ ++ devname = self.device.get_property("DEVNAME") ++ self.command.run_cmd("umount %s" % devname, ignore_errors=True) ++ if "BD" in self.type or "DVD_PLUS" in self.type: ++ grow_cmd = self.command.run_cmd( ++ "growisofs -Z %s --quiet -R %s " % (devname, self.test_dir)) ++ reload_flag = self.reload_disc(devname) ++ if grow_cmd[2] == 0 and reload_flag: ++ return True ++ return False ++ ++ write_opts = "-sao" ++ cmd_result = self.command.run_cmd( ++ "cdrecord dev=%s -checkdrive | grep 'Supported modes'" % devname, ignore_errors=True) ++ modes = cmd_result[0] ++ if "TAO" in modes: ++ write_opts = "-tao" ++ if "SAO" in modes: ++ write_opts = "-sao" ++ cmd_result = self.command.run_cmd( ++ "cdrecord dev=%s -checkdrive | grep 'Driver flags'" % devname, ignore_errors=True) ++ if "BURNFREE" in cmd_result[0]: ++ write_opts += " driveropts=burnfree" ++ ++ size = self.command.run_cmd( ++ "mkisofs -quiet -R -print-size %s" % self.test_dir) ++ blocks = int(size[0]) ++ ++ self.command.run_cmd( ++ "mkisofs -o test_cdrom.iso --quiet -r %s" % self.test_dir) ++ mkisofs_cmd = self.command.run_cmd( ++ "cdrecord -v %s dev=%s fs=32M test_cdrom.iso" % (write_opts, devname)) ++ reload_flag = self.reload_disc(devname) ++ os.remove("test_cdrom.iso") ++ if mkisofs_cmd[2] == 0 and reload_flag: ++ return True ++ return False ++ ++ def read_test(self): ++ """ ++ Read mode test of CDROM ++ :return: ++ """ ++ devname = self.device.get_property("DEVNAME") ++ if os.path.exists(self.mnt_dir): ++ shutil.rmtree(self.mnt_dir) ++ os.mkdir(self.mnt_dir) ++ self.logger.info("Check to mount media.", terminal_print=True) ++ self.command.run_cmd("umount %s" % devname, ignore_errors=True) ++ self.command.run_cmd("mount -o ro %s %s" % (devname, self.mnt_dir)) ++ ++ cmd_result = self.command.run_cmd( ++ "df %s | tail -n1 | awk '{print $3}'" % devname) ++ size = int(cmd_result[0]) ++ if size == 0: ++ self.logger.error("This is a blank disc.") ++ self.command.run_cmd("umount %s" % self.mnt_dir) ++ shutil.rmtree(self.mnt_dir) ++ return False ++ ++ if os.path.exists(self.device_dir): ++ shutil.rmtree(self.device_dir) ++ os.mkdir(self.device_dir) ++ self.logger.info("Check to copy files.", terminal_print=True) ++ self.command.run_cmd("cp -dprf %s/. %s" % (self.mnt_dir, self.device_dir)) ++ ++ self.logger.info( ++ "Check to compare files in directory.", terminal_print=True) ++ return_code = self.cmp_tree(self.mnt_dir, self.device_dir) ++ self.command.run_cmd("umount %s" % self.mnt_dir) ++ if return_code: ++ self.logger.info("Compare directory succeed.") ++ else: ++ self.logger.error("Compare directory failed.") ++ ++ return return_code ++ ++ def cmp_tree(self, dir1, dir2): ++ """ ++ Compare the differences between the two directories ++ :param dir1: ++ :param dir2: ++ :return: ++ """ ++ if not (dir1 and dir2): ++ self.logger.error("Invalid input directory.") ++ return False ++ ++ cmd_result = self.command.run_cmd("diff -r %s %s" % (dir1, dir2)) ++ return cmd_result[2] == 0 ++ ++ def reload_disc(self, device): ++ """ ++ Reloading the media ++ :param device: ++ :return: ++ """ ++ if not device: ++ return False ++ ++ self.logger.info("Check to reload the media.") ++ self.command.run_cmd("eject %s" % device) ++ self.logger.info("Tray ejected.") ++ ++ cmd = self.command.run_cmd("eject -t %s" % device) ++ if cmd[2] != 0: ++ self.logger.error( ++ "Could not auto-close the tray, please close the tray manually.") ++ self.com_ui.prompt_confirm("Done well?") ++ ++ sleep(20) ++ self.logger.info("Tray auto-closed.\n") ++ return True ++ ++ def teardown(self): ++ if os.path.exists(self.mnt_dir): ++ shutil.rmtree(self.mnt_dir) ++ if os.path.exists(self.device_dir): ++ shutil.rmtree(self.device_dir) +diff -Naur rpm/tests/compatible/cdrom/Makefile oech/tests/compatible/cdrom/Makefile +--- rpm/tests/compatible/cdrom/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/cdrom/Makefile 2023-12-07 15:01:42.225942288 +0800 +@@ -0,0 +1,22 @@ ++# Copyright (c) 2020 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a *.py $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/clock/clock.c oech/tests/compatible/clock/clock.c +--- rpm/tests/compatible/clock/clock.c 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/clock/clock.c 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (c) 2020 Huawei Technologies Co., Ltd. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#define _GNU_SOURCE 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++int test_clock_direction() ++{ ++ time_t starttime = 0; ++ time_t stoptime = 0; ++ int sleeptime = 60; ++ int delta = 0; ++ ++ printf("clock direction test start\n"); ++ time(&starttime); ++ sleep(sleeptime); ++ time(&stoptime); ++ ++ delta = (int)stoptime - (int)starttime - sleeptime; ++ if (delta != 0) { ++ printf("clock direction test fail\n"); ++ return 1; ++ } else { ++ printf("clock direction test complete\n"); ++ return 0; ++ } ++} ++ ++int test_rtc_clock() ++{ ++ int rtc, delta; ++ struct tm rtc_tm1, rtc_tm2; ++ int sleeptime = 120; ++ ++ printf("rtc_clock test start\n"); ++ if ((rtc = open("/dev/rtc", O_WRONLY)) < 0) { ++ perror("could not open RTC device"); ++ return 1; ++ } ++ ++ if (ioctl(rtc, RTC_RD_TIME, &rtc_tm1) < 0) { ++ perror("could not get the RTC time"); ++ close(rtc); ++ return 1; ++ } ++ sleep(sleeptime); ++ if (ioctl(rtc, RTC_RD_TIME, &rtc_tm2) < 0) { ++ perror("could not get the RTC time"); ++ close(rtc); ++ return 1; ++ } ++ ++ close(rtc); ++ delta = (int)mktime(&rtc_tm2) - (int)mktime(&rtc_tm1) - sleeptime; ++ if (delta != 0) { ++ printf("rtc_clock test fail\n"); ++ return 1; ++ } else { ++ printf("rtc_clock test complete\n"); ++ return 0; ++ } ++} ++ ++int main() ++{ ++ int ret = 0; ++ ret += test_clock_direction(); ++ ret += test_rtc_clock(); ++ return ret; ++} +diff -Naur rpm/tests/compatible/clock/clock.py oech/tests/compatible/clock/clock.py +--- rpm/tests/compatible/clock/clock.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/clock/clock.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,37 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++# Desc: Clock test ++ ++import os ++from hwcompatible.test import Test ++ ++clock_dir = os.path.dirname(os.path.realpath(__file__)) ++ ++ ++class ClockTest(Test): ++ def __init__(self): ++ Test.__init__(self) ++ ++ def test(self): ++ """ ++ Clock test case ++ :return: ++ """ ++ result = self.command.run_cmd("%s/clock" % clock_dir) ++ if result[2] == 0: ++ self.logger.info("Test clock succeed.") ++ return True ++ ++ self.logger.error("Test clock failed.\n %s" % result[1]) ++ return False +diff -Naur rpm/tests/compatible/clock/Makefile oech/tests/compatible/clock/Makefile +--- rpm/tests/compatible/clock/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/clock/Makefile 2023-12-07 15:01:42.225942288 +0800 +@@ -0,0 +1,34 @@ ++# Copyright (c) 2020 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++ ++.PHONY: all install clean ++ ++all: clock ++ ++CFLAGS+=-Wall ++CFLAGS+=-DCPU_ALLOC ++# sched_setaffinity has no size_t argument on older systems. ++ifeq ($(shell grep 'sched_setaffinity.*size_t' /usr/include/sched.h),) ++CFLAGS+=-DOLD_SCHED_SETAFFINITY ++endif ++ ++clock: clock.c ++ $(CC) $(CFLAGS) -lrt $< -o $@ ++ ++install: ++ mkdir -p $(DEST) ++ cp -a clock *.py $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) ++ rm -rf clock ++ +diff -Naur rpm/tests/compatible/cpufreq/cal.py oech/tests/compatible/cpufreq/cal.py +--- rpm/tests/compatible/cpufreq/cal.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/cpufreq/cal.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,34 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++ ++import decimal ++import time ++ ++ ++def cal(): ++ """Call test_case""" ++ decimal.getcontext().prec = 1000 ++ one = decimal.Decimal(1) ++ for i in range(1000): ++ (i * one).sqrt() ++ ++ ++if __name__ == '__main__': ++ time_start = time.time() ++ while 1: ++ cal() ++ time_delta = time.time() - time_start ++ if time_delta >= 2: ++ print(time_delta) ++ break +diff -Naur rpm/tests/compatible/cpufreq/cpufreq.py oech/tests/compatible/cpufreq/cpufreq.py +--- rpm/tests/compatible/cpufreq/cpufreq.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/cpufreq/cpufreq.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,460 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++# Desc: cpufreq test ++ ++import argparse ++from random import randint ++from time import sleep ++from threading import Thread ++from hwcompatible.env import CertEnv ++from hwcompatible.test import Test ++from hwcompatible.command import Command ++ ++ ++class CPU: ++ """ ++ cpufreq test ++ """ ++ ++ def __init__(self, logger, command): ++ self.cpu = None ++ self.nums = 0 ++ self.list = None ++ self.original_governor = None ++ self.max_freq = 0 ++ self.min_freq = 0 ++ self.logger = logger ++ self.command = command ++ ++ def get_info(self): ++ """ ++ Get CPU info ++ :return: ++ """ ++ cmd_result = self.command.run_cmd( ++ "lscpu | grep '^CPU(s):' | awk '{print $2}'") ++ self.logger.info("Get the CPU(s) succeed.") ++ self.nums = int(cmd_result[0]) ++ self.list = range(self.nums) ++ ++ cmd = self.command.run_cmd( ++ "cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq") ++ if cmd[2] != 0: ++ self.logger.error("Get the scaling_max_freq of cpu failed.") ++ return False ++ self.max_freq = int(cmd[0]) ++ ++ cmd = self.command.run_cmd( ++ "cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq") ++ if cmd[2] != 0: ++ self.logger.error("Get the scaling_min_freq of cpu failed.") ++ return False ++ self.min_freq = int(cmd[0]) ++ ++ return True ++ ++ def set_freq(self, freq, cpu='all'): ++ """ ++ Set CPU frequency ++ :param freq: ++ :param cpu: ++ :return: ++ """ ++ cmd = self.command.run_cmd( ++ "cpupower -c %s frequency-set --freq %s" % (cpu, freq), log_print=False) ++ return cmd[2] == 0 ++ ++ def get_freq(self, cpu): ++ """ ++ Get CPU frequency ++ :param cpu: ++ :return: ++ """ ++ cmd = self.command.run_cmd( ++ "cpupower -c %s frequency-info -w | grep 'frequency' | cut -d ' ' -f 6" % cpu) ++ try: ++ if int(cmd[0]) and cmd[2] == 0: ++ self.logger.info("Get cpu frequency succeed.") ++ except ValueError as e: ++ self.logger.error("Get cpu frequency failed, %s" % e) ++ self.logger.info("Please use 'cpupower frequency-info' to check current frequency manually.") ++ return False ++ return int(cmd[0]) ++ ++ def set_governor(self, governor, cpu='all'): ++ """ ++ Set the frequency governor mode of CPU ++ :param governor: ++ :param cpu: ++ :return: ++ """ ++ cmd = self.command.run_cmd( ++ "cpupower -c %s frequency-set --governor %s" % (cpu, governor), log_print=False) ++ return cmd[2] == 0 ++ ++ def get_governor(self, cpu): ++ """ ++ Get cpu governor ++ :param cpu: ++ :return: ++ """ ++ cmd = self.command.run_cmd( ++ "cpupower -c %s frequency-info -p | grep governor | cut -d '\"' -f 2" % cpu) ++ if cmd[2] != 0: ++ self.logger.error("Get cpu governor failed.") ++ return False ++ self.logger.info("Get cpu governor succeed.") ++ return cmd[0].strip() ++ ++ ++class Load(Thread): ++ """ ++ Let a program run on a specific CPU ++ """ ++ ++ def __init__(self, cpu, command): ++ Thread.__init__(self) ++ self.cpu = cpu ++ self.command = command ++ self.process = None ++ self.returncode = None ++ ++ def run(self): ++ """ ++ Process started ++ :return: ++ """ ++ self.process = self.command.run_cmd( ++ "taskset -c %s python -u %s/cpufreq/cal.py" % (self.cpu, CertEnv.testdirectoy), log_print=False) ++ ++ def get_runtime(self): ++ """ ++ Get the running time of the process ++ :return: ++ """ ++ while self.is_alive(): ++ sleep(0.02) ++ ++ self.returncode = self.process[2] ++ if self.returncode == 0: ++ line = self.process[0] ++ return float(line) ++ return 0 ++ ++ ++class CPUFreqTest(Test): ++ """ ++ CPU frequency test ++ """ ++ ++ def __init__(self): ++ Test.__init__(self) ++ self.requirements = ['util-linux', 'kernel-tools'] ++ self.cpu = None ++ self.original_governor = None ++ ++ def setup(self, args=None): ++ """ ++ Initialization before test ++ :param args: ++ :return: ++ """ ++ self.args = args or argparse.Namespace() ++ self.logger = getattr(self.args, "test_logger", None) ++ self.command = Command(self.logger) ++ self.cpu = CPU(self.logger, self.command) ++ self.original_governor = self.cpu.get_governor(0) ++ ++ def test_userspace(self): ++ """ ++ userspace mode of testing CPU frequency ++ :return: ++ """ ++ target_cpu = randint(0, self.cpu.nums-1) ++ target_freq = randint(self.cpu.min_freq, self.cpu.max_freq) ++ if not self.cpu.set_freq(target_freq, cpu=target_cpu): ++ self.logger.error("Set CPU%s to freq %d failed." % ++ (target_cpu, target_freq)) ++ return False ++ self.logger.info("Set CPU%s to freq %d." % (target_cpu, target_freq)) ++ target_cpu_freq = self.cpu.get_freq(target_cpu) ++ self.logger.info("Current freq of CPU%s is %d." % ++ (target_cpu, target_cpu_freq)) ++ ++ target_cpu_governor = self.cpu.get_governor(target_cpu) ++ if target_cpu_governor != 'userspace': ++ self.logger.error("The governor of CPU%s(%s) is not userspace." % ++ (target_cpu, target_cpu_governor)) ++ return False ++ self.logger.info("The governor of CPU%s is %s." % ++ (target_cpu, target_cpu_governor)) ++ ++ # min_freq -> max_runtime ++ self.cpu.set_freq(self.cpu.min_freq) ++ load_list = [] ++ runtime_list = [] ++ for cpu in self.cpu.list: ++ load_test = Load(cpu, self.command) ++ load_test.start() ++ load_list.append(load_test) ++ for cpu in self.cpu.list: ++ runtime = load_list[cpu].get_runtime() ++ runtime_list.append(runtime) ++ max_average_runtime = 1.0 * sum(runtime_list) / len(runtime_list) ++ if max_average_runtime == 0: ++ self.logger.error("Max average time is 0.") ++ return False ++ self.logger.info( ++ "Max average time of all CPUs userspace load test: %.2f" % max_average_runtime) ++ ++ # max_freq -> min_runtime ++ self.cpu.set_freq(self.cpu.max_freq) ++ load_list = [] ++ runtime_list = [] ++ for cpu in self.cpu.list: ++ load_test = Load(cpu, self.command) ++ load_test.start() ++ load_list.append(load_test) ++ for cpu in self.cpu.list: ++ runtime = load_list[cpu].get_runtime() ++ runtime_list.append(runtime) ++ min_average_runtime = 1.0 * sum(runtime_list) / len(runtime_list) ++ if min_average_runtime == 0: ++ self.logger.info("Min average time is 0.") ++ return False ++ self.logger.info( ++ "Min average time of all CPUs userspace load test: %.2f" % min_average_runtime) ++ ++ measured_speedup = 1.0 * max_average_runtime / min_average_runtime ++ expected_speedup = 1.0 * self.cpu.max_freq / self.cpu.min_freq ++ tolerance = 1.0 ++ min_speedup = expected_speedup - (expected_speedup - 1.0) * tolerance ++ max_speedup = expected_speedup + (expected_speedup - 1.0) * tolerance ++ if not min_speedup <= measured_speedup <= max_speedup: ++ self.logger.error("The speedup(%.2f) is not between %.2f and %.2f" % ( ++ measured_speedup, min_speedup, max_speedup)) ++ return False ++ self.logger.info("The speedup(%.2f) is between %.2f and %.2f" % ++ (measured_speedup, min_speedup, max_speedup)) ++ ++ return True ++ ++ def test_ondemand(self): ++ """ ++ ondemand mode of testing CPU frequency ++ :return: ++ """ ++ if not self.cpu.set_governor('powersave'): ++ self.logger.error("Set governor of all CPUs to powersave failed.") ++ return False ++ self.logger.info("Set governor of all CPUs to powersave succeed.") ++ ++ if not self.cpu.set_governor('ondemand'): ++ self.logger.error("Set governor of all CPUs to ondemand failed.") ++ return False ++ self.logger.info("Set governor of all CPUs to ondemand succeed.") ++ ++ target_cpu = randint(0, self.cpu.nums-1) ++ target_cpu_governor = self.cpu.get_governor(target_cpu) ++ if target_cpu_governor != 'ondemand': ++ self.logger.error("The governor of CPU%s(%s) is not ondemand." % ( ++ target_cpu, target_cpu_governor)) ++ return False ++ self.logger.info("The governor of CPU%s is %s." % ++ (target_cpu, target_cpu_governor)) ++ ++ load_test = Load(target_cpu, self.command) ++ load_test.start() ++ sleep(1) ++ target_cpu_freq = self.cpu.get_freq(target_cpu) ++ if target_cpu_freq != self.cpu.max_freq: ++ self.logger.error("The freq of CPU%s(%d) is not scaling_max_freq(%d)." % ( ++ target_cpu, target_cpu_freq, self.cpu.max_freq)) ++ return False ++ self.logger.info("The freq of CPU%s is scaling_max_freq(%d)." % ++ (target_cpu, target_cpu_freq)) ++ ++ load_test_time = load_test.get_runtime() ++ self.logger.info("Time of CPU%s ondemand load test: %.2f" % ++ (target_cpu, load_test_time)) ++ target_cpu_freq = self.cpu.get_freq(target_cpu) ++ if not target_cpu_freq <= self.cpu.max_freq: ++ self.logger.error("The freq of CPU%s(%d) is not less equal than %d." % ( ++ target_cpu, target_cpu_freq, self.cpu.max_freq)) ++ return False ++ self.logger.info("The freq of CPU%s(%d) is less equal than %d." % ( ++ target_cpu, target_cpu_freq, self.cpu.max_freq)) ++ ++ return True ++ ++ def test_conservative(self): ++ """ ++ conservative mode of testing CPU frequency ++ :return: ++ """ ++ if not self.cpu.set_governor('powersave'): ++ self.logger.error("Set governor of all CPUs to powersave failed.") ++ return False ++ self.logger.info("Set governor of all CPUs to powersave.") ++ ++ if not self.cpu.set_governor('conservative'): ++ self.logger.error( ++ "Set governor of all CPUs to conservative failed.") ++ return False ++ self.logger.info("Set governor of all CPUs to conservative.") ++ ++ target_cpu = randint(0, self.cpu.nums-1) ++ target_cpu_governor = self.cpu.get_governor(target_cpu) ++ if target_cpu_governor != 'conservative': ++ self.logger.error("The governor of CPU%s(%s) is not conservative." % ++ (target_cpu, target_cpu_governor)) ++ return False ++ self.logger.info("The governor of CPU%s is %s." % ++ (target_cpu, target_cpu_governor)) ++ ++ load_test = Load(target_cpu, self.command) ++ load_test.start() ++ sleep(1) ++ target_cpu_freq = self.cpu.get_freq(target_cpu) ++ if not self.cpu.min_freq <= target_cpu_freq <= self.cpu.max_freq: ++ self.logger.error("The freq of CPU%s(%d) is not between %d~%d." % ++ (target_cpu, target_cpu_freq, self.cpu.min_freq, self.cpu.max_freq)) ++ return False ++ self.logger.info("The freq of CPU%s(%d) is between %d~%d." % ++ (target_cpu, target_cpu_freq, self.cpu.min_freq, self.cpu.max_freq)) ++ ++ load_test_time = load_test.get_runtime() ++ self.logger.info("Time of CPU%s conservative load test: %.2f" % ++ (target_cpu, load_test_time)) ++ target_cpu_freq = self.cpu.get_freq(target_cpu) ++ self.logger.info("Current freq of CPU%s is %d." % ++ (target_cpu, target_cpu_freq)) ++ ++ return True ++ ++ def test_powersave(self): ++ """ ++ Powersave mode of testing CPU frequency ++ :return: ++ """ ++ if not self.cpu.set_governor('powersave'): ++ self.logger.error("Set governor of all CPUs to powersave failed.") ++ return False ++ self.logger.info("Set governor of all CPUs to powersave.") ++ ++ target_cpu = randint(0, self.cpu.nums-1) ++ target_cpu_governor = self.cpu.get_governor(target_cpu) ++ if target_cpu_governor != 'powersave': ++ self.logger.error("The governor of CPU%s(%s) is not powersave." % ++ (target_cpu, target_cpu_governor)) ++ return False ++ self.logger.info("The governor of CPU%s is %s." % ++ (target_cpu, target_cpu_governor)) ++ ++ target_cpu_freq = self.cpu.get_freq(target_cpu) ++ if target_cpu_freq != self.cpu.min_freq: ++ self.logger.error("The freq of CPU%s(%d) is not scaling_min_freq(%d)." % ++ (target_cpu, target_cpu_freq, self.cpu.min_freq)) ++ return False ++ self.logger.info("The freq of CPU%s is %d." % ++ (target_cpu, target_cpu_freq)) ++ ++ load_test = Load(target_cpu, self.command) ++ load_test.start() ++ load_test_time = load_test.get_runtime() ++ self.logger.info("Time of CPU%s powersave load test: %.2f" % ++ (target_cpu, load_test_time)) ++ target_cpu_freq = self.cpu.get_freq(target_cpu) ++ self.logger.info("Current freq of CPU%s is %d." % ++ (target_cpu, target_cpu_freq)) ++ ++ return True ++ ++ def test_performance(self): ++ """ ++ Performance mode of testing CPU frequency ++ :return: ++ """ ++ if not self.cpu.set_governor('performance'): ++ self.logger.error( ++ "Set governor of all CPUs to performance failed.") ++ return False ++ self.logger.info("Set governor of all CPUs to performance.") ++ ++ target_cpu = randint(0, self.cpu.nums-1) ++ target_cpu_governor = self.cpu.get_governor(target_cpu) ++ if target_cpu_governor != 'performance': ++ self.logger.error("The governor of CPU%s(%s) is not performance." % ++ (target_cpu, target_cpu_governor)) ++ return False ++ self.logger.info("The governor of CPU%s is %s." % ++ (target_cpu, target_cpu_governor)) ++ ++ target_cpu_freq = self.cpu.get_freq(target_cpu) ++ if target_cpu_freq != self.cpu.max_freq: ++ self.logger.error("The freq of CPU%s(%d) is not scaling_max_freq(%d)." % ++ (target_cpu, target_cpu_freq, self.cpu.max_freq)) ++ return False ++ self.logger.info("The freq of CPU%s is %d." % ++ (target_cpu, target_cpu_freq)) ++ ++ load_test = Load(target_cpu, self.command) ++ load_test.start() ++ load_test_time = load_test.get_runtime() ++ self.logger.info("Time of CPU%s performance load test: %.2f" % ++ (target_cpu, load_test_time)) ++ target_cpu_freq = self.cpu.get_freq(target_cpu) ++ self.logger.info("Current freq of CPU%s is %d." % ++ (target_cpu, target_cpu_freq)) ++ ++ return True ++ ++ def test(self): ++ """ ++ Test case ++ :return: ++ """ ++ if not self.cpu.get_info(): ++ self.logger.error( ++ "Fail to get CPU info.\n Please check if the CPU supports cpufreq.") ++ return False ++ ++ ret = True ++ self.logger.info("Test userspace.") ++ if not self.test_userspace(): ++ self.logger.error("Test userspace failed.") ++ ret = False ++ ++ self.logger.info("Test ondemand.") ++ if not self.test_ondemand(): ++ self.logger.error("Test ondemand failed.") ++ ret = False ++ ++ self.logger.info("Test conservative.") ++ if not self.test_conservative(): ++ self.logger.error("Test conservative failed.") ++ ret = False ++ ++ self.logger.info("Test powersave.") ++ if not self.test_powersave(): ++ self.logger.error("Test powersave failed.") ++ ret = False ++ ++ self.logger.info("Test performance.") ++ if not self.test_performance(): ++ self.logger.error("Test performance failed.") ++ ret = False ++ ++ self.cpu.set_governor(self.original_governor) ++ return ret +diff -Naur rpm/tests/compatible/cpufreq/Makefile oech/tests/compatible/cpufreq/Makefile +--- rpm/tests/compatible/cpufreq/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/cpufreq/Makefile 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,22 @@ ++# Copyright (c) 2020 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a *.py $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/disk/common.py oech/tests/compatible/disk/common.py +--- rpm/tests/compatible/disk/common.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/disk/common.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,208 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @cuixucui ++# Create: 2022-09-23 ++ ++import os ++import shutil ++from subprocess import getoutput ++from hwcompatible.device import CertDevice ++ ++ ++def query_disk(logger, command): ++ """ ++ query disk info ++ """ ++ logger.info("Disk Info:", terminal_print=False) ++ command.run_cmd("fdisk -l") ++ logger.info("Partition Info:", terminal_print=False) ++ command.run_cmd("df -h") ++ logger.info("Mount Info:", terminal_print=False) ++ command.run_cmd("mount") ++ logger.info("Swap Info:", terminal_print=False) ++ command.run_cmd("cat /proc/swaps") ++ logger.info("LVM Info:", terminal_print=False) ++ command.run_cmd("pvdisplay") ++ command.run_cmd("vgdisplay") ++ command.run_cmd("lvdisplay") ++ logger.info("Md Info:", terminal_print=False) ++ command.run_cmd("cat /proc/mdstat") ++ ++ ++def get_disk(logger, command, config_data, pci_num=""): ++ """ ++ Get disk info ++ """ ++ disks = list() ++ test_disks = [] ++ devices = CertDevice(logger).get_devices() ++ for device in devices: ++ if (device.get_property("DEVTYPE") == "disk" and not device.get_property("ID_TYPE")) or\ ++ device.get_property("ID_TYPE") == "disk": ++ if "/host" in device.get_property("DEVPATH"): ++ if isinstance(config_data, str): ++ disks.append(device.get_name()) ++ elif pci_num in device.get_property("DEVPATH"): ++ disks.append(device.get_name()) ++ ++ command.run_cmd("/usr/sbin/swapon -a") ++ with open("/proc/partitions", "r") as partition_file: ++ partition = partition_file.read() ++ ++ with open("/proc/swaps", "r") as swap_file: ++ swap = swap_file.read() ++ ++ with open("/proc/mdstat", "r") as mdstat_file: ++ mdstat = mdstat_file.read() ++ ++ with open("/proc/mounts", "r") as mount_file: ++ mounts = mount_file.read() ++ ++ for disk in disks: ++ if disk not in partition or ("/dev/%s" % disk) in swap: ++ continue ++ if ("/dev/%s" % disk) in mounts or disk in mdstat: ++ continue ++ result = command.run_cmd("pvs | grep -q '/dev/%s'" % disk) ++ if result[2] == 0: ++ continue ++ test_disks.append(disk) ++ ++ un_suitable = list(set(disks).difference(set(test_disks))) ++ if len(un_suitable) > 0: ++ logger.info("These disks %s are in use now, skip them." % "|".join(un_suitable)) ++ return test_disks ++ ++ ++def raw_test(logger, command, disk): ++ """ ++ Raw test ++ """ ++ logger.info("%s raw IO test" % disk) ++ device = os.path.join("/dev", disk) ++ if not os.path.exists(device): ++ logger.error("Device %s doesn't exist." % device) ++ return False ++ proc_path = os.path.join("/sys/block/", disk) ++ if not os.path.exists(proc_path): ++ proc_path = os.path.join("/sys/block/*/", disk) ++ size = getoutput("cat %s/size" % proc_path) ++ size = int(size) / 2 ++ if size <= 0: ++ logger.error( ++ "Device %s size is not suitable for testing." % device) ++ return False ++ elif size > 1048576: ++ size = 1048576 ++ ++ logger.info("Starting sequential raw IO test...") ++ opts = "-direct=1 -iodepth 4 -rw=rw -rwmixread=50 -group_reporting -name=file -runtime=300" ++ if not do_fio(logger, command, device, size, opts): ++ logger.error("%s sequential raw IO test failed." % device) ++ return False ++ ++ logger.info("Starting rand raw IO test...") ++ opts = "-direct=1 -iodepth 4 -rw=randrw -rwmixread=50 " \ ++ "-group_reporting -name=file -runtime=300" ++ if not do_fio(logger, command, device, size, opts): ++ logger.error("%s rand raw IO test failed." % device) ++ return False ++ ++ return True ++ ++ ++def vfs_test(logger, command, disk, filesystems): ++ """ ++ Vfs test ++ """ ++ logger.info("%s vfs test" % disk) ++ device = os.path.join("/dev/", disk) ++ if not os.path.exists(device): ++ logger.error("Device %s doesn't exist." % device) ++ return False ++ proc_path = os.path.join("/sys/block/", disk) ++ if not os.path.exists(proc_path): ++ proc_path = os.path.join("/sys/block/*/", disk) ++ size = getoutput("cat %s/size" % proc_path) ++ size = int(size) / 2 / 2 ++ if size <= 0: ++ logger.error( ++ "Device %s size is not suitable for testing." % device) ++ return False ++ elif size > 1048576: ++ size = 1048576 ++ ++ if os.path.exists("vfs_test"): ++ shutil.rmtree("vfs_test") ++ os.mkdir("vfs_test") ++ path = os.path.join(os.getcwd(), "vfs_test") ++ ++ return_code = True ++ for file_sys in filesystems: ++ logger.info("Formatting %s to %s ..." % ++ (device, file_sys), terminal_print=False) ++ command.run_cmd("umount %s" % device, ignore_errors=True) ++ command.run_cmd("mkfs -t %s -F %s" % (file_sys, device)) ++ command.run_cmd("mount -t %s %s %s" % ++ (file_sys, device, "vfs_test")) ++ logger.info("Starting sequential vfs IO test...") ++ opts = "-direct=1 -iodepth 4 -rw=rw -rwmixread=50 -name=directoy -runtime=300" ++ if not do_fio(logger, command, path, size, opts): ++ return_code = False ++ break ++ ++ logger.info("Starting rand vfs IO test...") ++ opts = "-direct=1 -iodepth 4 -rw=randrw -rwmixread=50 -name=directoy -runtime=300" ++ if not do_fio(logger, command, path, size, opts): ++ return_code = False ++ break ++ ++ command.run_cmd("umount %s" % device) ++ shutil.rmtree("vfs_test") ++ return return_code ++ ++ ++def do_fio(logger, command, filepath, size, option): ++ """ ++ Fio test ++ """ ++ if os.path.isdir(filepath): ++ file_opt = "-directory=%s" % filepath ++ else: ++ file_opt = "-filename=%s" % filepath ++ max_bs = 64 ++ a_bs = 4 ++ while a_bs <= max_bs: ++ cmd_result = command.run_cmd( ++ "fio %s -size=%dK -bs=%dK %s" % (file_opt, size, a_bs, option)) ++ if cmd_result[2] != 0: ++ logger.error("%s fio failed." % filepath) ++ return False ++ a_bs = a_bs * 2 ++ logger.info("%s fio succeed." % filepath) ++ return True ++ ++ ++def valid_disk(logger, disk, disks): ++ """ ++ Is the disk valid ++ """ ++ result = True ++ if disk: ++ if disk != "all" and disk not in disks: ++ logger.error("%s is in use or disk does not exist." % disk) ++ result = False ++ else: ++ logger.error("Failed to get disk information.") ++ result = False ++ return result +diff -Naur rpm/tests/compatible/disk/disk.py oech/tests/compatible/disk/disk.py +--- rpm/tests/compatible/disk/disk.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/disk/disk.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,66 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++# Desc: Disk test ++ ++import argparse ++from hwcompatible.test import Test ++from hwcompatible.command import Command ++from common import query_disk, get_disk, raw_test, vfs_test, valid_disk ++ ++ ++class DiskTest(Test): ++ def __init__(self): ++ Test.__init__(self) ++ self.disks = list() ++ self.requirements = ["fio"] ++ self.filesystems = ["ext4"] ++ self.config_data = "" ++ ++ def setup(self, args=None): ++ """ ++ The Setup before testing ++ :return: ++ """ ++ self.args = args or argparse.Namespace() ++ self.logger = getattr(self.args, "test_logger", None) ++ self.command = Command(self.logger) ++ self.config_data = getattr(self.args, "config_data", None) ++ query_disk(self.logger, self.command) ++ ++ def test(self): ++ """ ++ Start test ++ """ ++ self.disks = get_disk(self.logger, self.command, self.config_data) ++ if len(self.disks) == 0: ++ self.logger.error("No suite disk found to test.") ++ return False ++ ++ if not self.config_data: ++ self.logger.error("Failed to get disk from configuration file.") ++ return False ++ disk = self.config_data ++ result = valid_disk(self.logger, disk, self.disks) ++ if not result: ++ return False ++ ++ return_code = True ++ if disk != "all": ++ self.disks = [disk] ++ for disk in self.disks: ++ if not raw_test(self.logger, self.command, disk): ++ return_code = False ++ if not vfs_test(self.logger, self.command, disk, self.filesystems): ++ return_code = False ++ return return_code +diff -Naur rpm/tests/compatible/disk/Makefile oech/tests/compatible/disk/Makefile +--- rpm/tests/compatible/disk/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/disk/Makefile 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,22 @@ ++# Copyright (c) 2020 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a *.py $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/dpdk/dpdk.py oech/tests/compatible/dpdk/dpdk.py +--- rpm/tests/compatible/dpdk/dpdk.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/dpdk/dpdk.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,439 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++# Author: @ylzhangah ++# Create: 2022-12-01 ++# Desc: DPDK test ++ ++ ++import os ++import argparse ++import json ++import time ++import subprocess ++ ++from urllib.parse import urlencode ++from urllib.request import urlopen, Request ++ ++from hwcompatible.test import Test ++from hwcompatible.command import Command ++from hwcompatible.document import CertDocument ++from hwcompatible.env import CertEnv ++from hwcompatible.constants import FILE_FLAGS, FILE_MODES ++from hugepages import ShowHugepages ++ ++ ++class DPDKTest(Test): ++ """ ++ DPDK test ++ """ ++ ++ def __init__(self): ++ Test.__init__(self) ++ self.requirements = ["dpdk", "dpdk-tools", "dpdk-devel"] ++ self.config_data = dict() ++ self.interface = None ++ self.server_ip = "" ++ self.server_port = 80 ++ self.portmask = "0xffff" ++ self.packet_size = 1514 ++ self.support_driver = ['mlx4_core', 'mlx5_core', 'ixgbe', 'ice', 'hinic', 'igc'] ++ self.dpdk_driver = 'uio_pci_generic' ++ self.kernel_driver = None ++ self.retries = 3 ++ self.speed = 0 # Mb/s ++ self.target_bandwidth_percent = 0.8 ++ self.device = "" ++ self.pci = "" ++ self.card_id = None ++ self.ethpeer = None ++ self.test_dpdk_file = "" ++ ++ def setup(self, args=None): ++ """ ++ Initialization before test ++ :return: ++ """ ++ self.args = args or argparse.Namespace() ++ self.logger = getattr(self.args, "test_logger", None) ++ self.command = Command(self.logger) ++ self.hugepage = ShowHugepages(self.logger, self.command) ++ self.test_dpdk_file = os.path.join(self.logger.logdir, 'test_dpdk.log') ++ self.device = getattr(self.args, 'device', None) ++ self.interface = self.device.get_property("INTERFACE") ++ self.show_driver_info() ++ self.pci = self.device.get_pci() ++ self.kernel_driver = self.device.get_driver() ++ self.card_id = self.device.get_quadruple() ++ self.command.run_cmd("dpdk-hugepages.py -u", terminal_print=False) ++ self.command.run_cmd("dpdk-hugepages.py -c", terminal_print=False) ++ self.command.run_cmd("dpdk-hugepages.py --setup 2G", terminal_print=True) ++ self.config_data = getattr(args, "config_data", None) ++ self.server_ip = CertDocument(CertEnv.certificationfile, self.logger).get_server() ++ self.test_prepare() ++ ++ def get_interface_speed(self): ++ """ ++ Get speed on the interface ++ :return: ++ """ ++ speed = self.command.run_cmd( ++ "ethtool %s | grep Speed | awk '{print $2}'" % self.interface) ++ if speed[2] != 0: ++ self.logger.error("No speed found on the interface.") ++ return 0 ++ ++ return int(speed[0][:-5]) ++ ++ def check_bind(self): ++ """ ++ Check whether binding card is required ++ :return: ++ """ ++ # set interface down so that bind the dpdk driver. ++ if self.kernel_driver not in self.support_driver: ++ self.logger.error("The card driver %s doesn't support dpdk test, Supported drivers are %s." ++ % (self.kernel_driver, self.support_driver)) ++ return False ++ else: ++ self.logger.info("DPDK driver is loading...") ++ subprocess.getoutput("modprobe uio; modprobe %s" % self.dpdk_driver) ++ if self.command.run_cmd("lsmod | grep %s" % self.dpdk_driver, terminal_print=True)[2] != 0: ++ self.logger.error("DPDK driver is loaded failed!") ++ return False ++ else: ++ self.logger.info("Get server card's ethpeer...") ++ if not self.get_ethpeer(): ++ return False ++ if self.kernel_driver == "mlx4_core" or self.kernel_driver == "mlx5_core": ++ self.logger.info("The mellanox network card does not need to be bound.") ++ self.command.run_cmd("modprobe -a ib_uverbs mlx5_core mlx5_ib mlx4_core", terminal_print=True) ++ else: ++ self.logger.info("Server dpdk is binding...") ++ if not self.server_dpdk_bind(): ++ return False ++ self.logger.info("Client dpdk is binding...") ++ if not self.client_dpdk_bind(): ++ return False ++ return True ++ ++ def get_ethpeer(self): ++ """ ++ Get ethpeer. ++ :return: ++ """ ++ form = {'serverip': self.server_ip, 'cardid': self.card_id} ++ url = 'http://{}:%s/api/get/ethpeer'.format(self.server_ip) % self.server_port ++ data = urlencode(form).encode('utf8') ++ headers = { ++ 'Content-type': 'application/x-www-form-urlencoded', ++ 'Accept': 'text/plain' ++ } ++ request = Request(url, data=data, headers=headers) ++ try: ++ response = urlopen(request) ++ except Exception: ++ self.logger.error("Call remote server url %s failed." % url) ++ return False ++ self.logger.info(str(response.headers), terminal_print=False) ++ self.ethpeer = json.loads(response.read())['ethpeer'] ++ self.logger.info("The mac of the server card is %s" % self.ethpeer) ++ self.logger.info("Status: %u %s" % (response.code, response.msg)) ++ if response.code != 200: ++ return False ++ return True ++ ++ def client_dpdk_bind(self): ++ """ ++ Bind client card with dpdk driver ++ :return: ++ """ ++ self.logger.info("Setting client interface %s down." % self.interface) ++ if not self.ifdown(self.interface): ++ self.logger.error("Setting client interface down failed!") ++ return False ++ else: ++ self.logger.info("Client dpdk is binding...") ++ cmd = self.command.run_cmd("dpdk-devbind.py -b %s %s" % (self.dpdk_driver, self.interface)) ++ if cmd[2] == 0: ++ self.logger.info("Client dpdk is bound successfully!") ++ self.command.run_cmd("dpdk-devbind.py -s") ++ return True ++ else: ++ self.logger.error("Bind card with dpdk driver failed!") ++ return False ++ ++ def server_dpdk_bind(self): ++ """ ++ Bind the server card. ++ :return: ++ """ ++ form = {'serverip': self.server_ip, 'cardid': self.card_id} ++ url = 'http://{}:%s/api/bind/server'.format(self.server_ip) % self.server_port ++ data = urlencode(form).encode('utf8') ++ headers = { ++ 'Content-type': 'application/x-www-form-urlencoded', ++ 'Accept': 'text/plain' ++ } ++ request = Request(url, data=data, headers=headers) ++ try: ++ response = urlopen(request) ++ except Exception: ++ self.logger.error("Call remote server url %s failed." % url) ++ return False ++ self.logger.info(str(response.headers), terminal_print=False) ++ self.logger.info("Status: %u %s" % (response.code, response.msg)) ++ if response.code != 200: ++ return False ++ return True ++ ++ def test(self): ++ """ ++ Test case ++ :return: ++ """ ++ if not self.test_icmp(): ++ return False ++ ++ if not self.check_bind(): ++ return False ++ ++ self.logger.info("Start dpdk-testpmd server...") ++ if not self.call_remote_server('dpdk-testpmd', 'start'): ++ self.logger.error("[X] start dpdk-testpmd server failed.") ++ return False ++ ++ self.logger.info("Test dpdk speed...") ++ if not self.test_speed(): ++ self.logger.error("Test dpdk speed failed.") ++ return False ++ ++ self.logger.info("Stop dpdk-testpmd server...") ++ if not self.call_remote_server('dpdk-testpmd', 'stop'): ++ self.logger.error("[X] Stop dpdk-testpmd server failed.") ++ return False ++ ++ return True ++ ++ def show_hugepage(self): ++ """ ++ Show Hugepages on system. ++ :return: ++ """ ++ if self.hugepage.is_numa(): ++ self.hugepage.show_numa_pages() ++ else: ++ self.hugepage.show_non_numa_pages() ++ ++ def test_prepare(self): ++ """ ++ Preparation before test ++ :return: ++ """ ++ if not self.hugepage.check_hugepage_allocate(self.hugepage.is_numa()): ++ self.logger.error("No hugepage allocated.") ++ return False ++ ++ if not self.hugepage.get_mountpoints(): ++ self.logger.error("No hugepage mounted.") ++ return False ++ ++ self.logger.info("Hugepage successfully configured.") ++ self.show_hugepage() ++ ++ return True ++ ++ def test_speed(self): ++ """ ++ Test speed ++ :return: ++ """ ++ command = [ ++ 'dpdk-testpmd', ++ '-l', '0-1', ++ '-n', '1', ++ '-a', self.pci, ++ '--', ++ '--portmask=0x1', ++ '--txpkts=%d' % self.packet_size, ++ '--rxq=4', ++ '--txq=4', ++ '--forward-mode=txonly', ++ '--eth-peer=0,%s' % self.ethpeer, ++ '--stats-period=2' ++ ] ++ res = subprocess.Popen(command, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) ++ self.logger.info("Please wait 30 seconds.") ++ time.sleep(30) ++ res.terminate() ++ with os.fdopen(os.open(self.test_dpdk_file, FILE_FLAGS, FILE_MODES), "w") as log: ++ log.write(str(res.stdout.read(), 'UTF-8')) ++ time.sleep(30) ++ res = self.command.run_cmd("grep Tx-bps %s | awk '{print $4}'" % self.test_dpdk_file) ++ if res[2] != 0: ++ self.logger.error("The test data result is empty, Please check if the server is configured properly!") ++ res_list = res[0].split("\n")[-10:-1] ++ int_list = [int(x) for x in res_list] ++ number = len(int_list) ++ if number != 0: ++ bandwidth = float(sum(int_list) / number / 1e6) ++ # 1e6 = 1000000.0 ++ target_bandwidth = self.target_bandwidth_percent * self.speed ++ self.logger.info("Current bandwidth is around %.2f Mb/s, target is %.2fMb/s" % ++ (bandwidth, target_bandwidth)) ++ if bandwidth > target_bandwidth: ++ self.logger.info("Test dpdk bandwidth successfully.") ++ return True ++ self.logger.error("Test dpdk bandwidth failed!") ++ return False ++ else: ++ self.logger.error("No data obtained for testing dpdk, Please manually check!") ++ return False ++ ++ def ifdown(self, interface): ++ """ ++ Judge whether the specified interface is closed successfully ++ :param interface: ++ :return: ++ """ ++ self.command.run_cmd("ip link set down %s" % interface) ++ for _ in range(10): ++ result = self.command.run_cmd( ++ "ip link show %s | grep 'state DOWN'" % interface, ignore_errors=True) ++ if result[2] == 0: ++ self.logger.info("Set interface %s down succeed." % self.interface) ++ return True ++ time.sleep(1) ++ ++ self.logger.error("Set interface %s down failed." % self.interface) ++ return False ++ ++ def ifup(self, interface): ++ """ ++ Judge whether the specified interface is enabled successfully ++ :param interface: ++ :return: ++ """ ++ self.command.run_cmd("ip link set up %s" % interface) ++ for _ in range(10): ++ result = self.command.run_cmd( ++ "ip link show %s | grep 'state UP'" % interface, ignore_errors=True) ++ if result[2] == 0: ++ self.logger.info("Set interface %s up succeed." % self.interface) ++ return True ++ time.sleep(1) ++ ++ self.logger.error("Set interface %s up failed." % self.interface) ++ return False ++ ++ def test_icmp(self): ++ """ ++ Test ICMP ++ :return: ++ """ ++ self.speed = self.get_interface_speed() ++ if self.speed: ++ self.logger.info("The speed of %s is %sMb/s." % ++ (self.interface, self.speed)) ++ else: ++ self.logger.error("Set speed of %s failed." % self.interface) ++ ++ count = 500 ++ cmd = "ping -q -c %d -i 0 %s | grep 'packet loss' | awk '{print $6}'" % ( ++ count, self.server_ip) ++ for _ in range(self.retries): ++ result = self.command.run_cmd(cmd, ignore_errors=True) ++ if result[0].strip() == "0%": ++ self.logger.info("Test icmp succeed.") ++ return True ++ self.logger.error("Test icmp failed.") ++ return False ++ ++ def call_remote_server(self, cmd, act='start'): ++ """ ++ Connect to the server somehow. ++ :param cmd: ++ :param act: ++ :return: ++ """ ++ form = dict() ++ form = {'cmd': cmd, 'serverip': self.server_ip, 'cardid': self.card_id} ++ url = 'http://%s/api/%s' % (self.server_ip, act) ++ data = urlencode(form).encode('utf8') ++ headers = { ++ 'Content-type': 'application/x-www-form-urlencoded', ++ 'Accept': 'text/plain' ++ } ++ request = Request(url, data=data, headers=headers) ++ try: ++ response = urlopen(request) ++ except Exception: ++ self.logger.error("Call remote dpdk server url %s failed." % url) ++ return False ++ self.logger.info("Status: %u %s" % (response.code, response.msg)) ++ return int(response.code) == 200 ++ ++ def server_dpdk_unbind(self): ++ """ ++ Unbind the server card. ++ :return: ++ """ ++ form = {'serverip': self.server_ip, 'cardid': self.card_id} ++ url = 'http://{}/api/unbind/server'.format(self.server_ip) ++ data = urlencode(form).encode('utf8') ++ headers = { ++ 'Content-type': 'application/x-www-form-urlencoded', ++ 'Accept': 'text/plain' ++ } ++ request = Request(url, data=data, headers=headers) ++ try: ++ response = urlopen(request) ++ except Exception: ++ self.logger.error("Call remote server url %s failed." % url) ++ return False ++ ++ self.logger.info("Status: %u %s" % (response.code, response.msg)) ++ if response.code != 200: ++ return False ++ return True ++ ++ def dev_unbind(self): ++ """ ++ dpdk unbind ++ :return: ++ """ ++ self.logger.info("Unbinding server card...") ++ if self.server_dpdk_unbind(): ++ self.logger.info("Unbind server card successfully!") ++ ++ self.logger.info("Unbinding client card...") ++ self.command.run_cmd("dpdk-devbind.py -u %s" % self.pci) ++ cmd = self.command.run_cmd("dpdk-devbind.py -b %s %s" % (self.kernel_driver, self.pci)) ++ if cmd[0] == "": ++ self.logger.info("Unbinding client card successfully!") ++ ++ self.logger.info("Setting client interface %s up..." % self.interface) ++ if not self.ifup(self.interface): ++ return False ++ return True ++ ++ def teardown(self): ++ """ ++ Environment recovery after test ++ :return: ++ """ ++ if self.kernel_driver == "mlx4_core" or self.kernel_driver == "mlx5_core": ++ self.logger.info("The Mellanox card need not unbind!") ++ else: ++ self.dev_unbind() ++ self.call_remote_server('all', 'stop') ++ self.logger.info("Stop all test servers.") +diff -Naur rpm/tests/compatible/dpdk/hugepages.py oech/tests/compatible/dpdk/hugepages.py +--- rpm/tests/compatible/dpdk/hugepages.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/dpdk/hugepages.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,106 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @ylzhangah ++# Create: 2022-12-01 ++# Desc: DPDK test ++ ++ ++import os ++import glob ++from math import log2 ++ ++ ++class ShowHugepages: ++ """ ++ Format memsize, get moutpoint, show hugepages ++ """ ++ ++ def __init__(self, logger, command): ++ self.logger = logger ++ self.command = command ++ ++ def format_memsize(self, kb): ++ """" ++ format memsize. this is a code snippit from dpdk repo ++ """ ++ binary_prefix = "KMG" ++ logk = int(log2(kb) / 10) ++ suffix = binary_prefix[logk] ++ unit = 2 ** (logk * 10) ++ if unit != 0: ++ return '{}{}b'.format(int(kb / unit), suffix) ++ else: ++ return False ++ ++ def get_mountpoints(self): ++ """ ++ Get list of where hugepage filesystem is mounted ++ """ ++ mounted = self.command.run_cmd("mount | grep hugetlbfs | awk '{print $2}'")[0].strip('\n') ++ return mounted ++ ++ def is_numa(self): ++ """ ++ Test if numa is used on this system ++ """ ++ return os.path.exists('/sys/devices/system/node') ++ ++ def show_numa_pages(self): ++ """ ++ Show huge page reservations on numa system ++ """ ++ self.logger.info('Node Pages Size Total') ++ for numa_path in glob.glob('/sys/devices/system/node/node*'): ++ node = numa_path[29:] # slice after /sys/devices/system/node/node ++ path = os.path.join(numa_path, 'hugepages') ++ for hdir in os.listdir(path): ++ comm = self.command.run_cmd("cat %s/%s/nr_hugepages" % (path, hdir)) ++ pages = int(comm[0].strip('\n')) ++ if pages > 0: ++ kb = int(hdir[10:-2]) # slice out of hugepages-NNNkB ++ self.logger.info('{:<4} {:<5} {:<6} {}'.format(node, pages, ++ self.format_memsize(kb), self.format_memsize(pages * kb))) ++ ++ def show_non_numa_pages(self): ++ """ ++ Show huge page reservations on non numa system ++ """ ++ self.logger.info('Pages Size Total') ++ hugepagedir = '/sys/kernel/mm/hugepages/' ++ for hdir in os.listdir(hugepagedir): ++ comm = self.command.run_cmd("cat %s/%s/nr_hugepages" % (hugepagedir, hdir)) ++ pages = int(comm[0].strip('\n')) ++ if pages > 0: ++ kb = int(hdir[10:-2]) ++ ++ self.logger.info('{:<5} {:<6} {}'.format(pages, self.format_memsize(kb), ++ self.format_memsize(pages * kb))) ++ ++ def check_hugepage_allocate(self, isnuma): ++ if not isnuma: ++ hugepagedir = '/sys/kernel/mm/hugepages/' ++ else: ++ numaid = 0 ++ hugepagedir = '/sys/devices/system/node/node%d/hugepages/' % numaid ++ ++ for (_, dirs, _) in os.walk(hugepagedir): ++ for directory in dirs: ++ comm = self.command.run_cmd("cat %s/%s/nr_hugepages" % (hugepagedir, directory)) ++ if comm[0] != 0: ++ return True ++ break ++ ++ return False ++ ++ # return false when ++ # 1. no files in hugepagedir; ++ # 2. no non-zero entry was found; +diff -Naur rpm/tests/compatible/dpdk/Makefile oech/tests/compatible/dpdk/Makefile +--- rpm/tests/compatible/dpdk/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/dpdk/Makefile 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,24 @@ ++# Copyright (c) 2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @ylzhangah ++# Create: 2022-12-01 ++# Desc: DPDK test ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a $(SUBDIR)/build *.py $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/fc/fc.py oech/tests/compatible/fc/fc.py +--- rpm/tests/compatible/fc/fc.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/fc/fc.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,96 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2022-04-09 ++# Desc: Fibre channel test ++ ++import argparse ++from hwcompatible.test import Test ++from hwcompatible.command import Command ++from tests.compatible.disk.common import query_disk, get_disk, raw_test, vfs_test, valid_disk ++ ++ ++class FCTest(Test): ++ def __init__(self): ++ Test.__init__(self) ++ self.disks = list() ++ self.requirements = ["fio"] ++ self.filesystems = ["ext4"] ++ self.device = "" ++ self.pci_num = "" ++ self.config_data = dict() ++ ++ def setup(self, args=None): ++ """ ++ The Setup before testing ++ :return: ++ """ ++ self.args = args or argparse.Namespace() ++ self.logger = getattr(self.args, "test_logger", None) ++ self.command = Command(self.logger) ++ self.config_data = getattr(self.args, "config_data", None) ++ ++ self.device = getattr(self.args, 'device', None) ++ self.pci_num = self.device.get_property("DEVPATH").split('/')[-1] ++ self.show_driver_info() ++ self.logger.info("Vendor Info:", terminal_print=False) ++ self.command.run_cmd("lspci -s %s -v" % self.pci_num) ++ query_disk(self.logger, self.command) ++ ++ def test(self): ++ """ ++ Start test ++ """ ++ pci_num = self.check_link_state() ++ if not pci_num: ++ return False ++ self.disks = get_disk(self.logger, self.command, self.config_data, pci_num) ++ if len(self.disks) == 0: ++ self.logger.error("No suite disk found to test.") ++ return False ++ ++ if not self.config_data: ++ self.logger.error("Failed to get disk from configuration file.") ++ return False ++ ++ disk = self.config_data.get('disk', '') ++ if not valid_disk(self.logger, disk, self.disks): ++ return False ++ ++ return_code = True ++ if disk != "all": ++ self.disks = [disk] ++ for disk in self.disks: ++ if not raw_test(self.logger, self.command, disk): ++ return_code = False ++ if not vfs_test(self.logger, self.command, disk, self.filesystems): ++ return_code = False ++ return return_code ++ ++ def check_link_state(self): ++ """ ++ check HBA link state ++ """ ++ host_name = self.command.run_cmd("ls -l /sys/class/fc_host | grep %s | awk '{print $9}'" ++ % self.pci_num)[0].strip('\n') ++ port_state = self.command.run_cmd("cat /sys/class/fc_host/%s/port_state" % host_name)[0].strip('\n') ++ if port_state == "Linkdown": ++ self.logger.error("The HBA's port_state is linkdown, Please check the connection state!") ++ return "" ++ elif port_state == "Online": ++ pci_num = self.pci_num ++ self.logger.info("The HBA's port_state is Online, start testing...") ++ return pci_num ++ else: ++ self.logger.info("The HBA's port_state can't be viewed") ++ return False ++ +diff -Naur rpm/tests/compatible/fc/Makefile oech/tests/compatible/fc/Makefile +--- rpm/tests/compatible/fc/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/fc/Makefile 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,22 @@ ++# Copyright (c) 2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2022-04-09 ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a *.py $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/gpu/amd_gpu.py oech/tests/compatible/gpu/amd_gpu.py +--- rpm/tests/compatible/gpu/amd_gpu.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/gpu/amd_gpu.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,141 @@ ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @meitingli ++# Create: 2022-10-15 ++# Desc: AMD GPU test (This test could only execute on graphical.target) ++ ++import os ++from subprocess import getstatusoutput ++ ++gpu_dir = os.path.dirname(os.path.realpath(__file__)) ++ ++ ++class AMDGpuTest(): ++ def __init__(self, device, logger, command): ++ self.device = device ++ self.logger = logger ++ self.command = command ++ self.radeontop_log = os.path.join(self.logger.logdir, 'radeontop.log') ++ self.screen_info_log = os.path.join( ++ self.logger.logdir, 'screen_info.log') ++ self.glmark_log = os.path.join(self.logger.logdir, 'glmark2.log') ++ ++ def get_driver_info(self): ++ """ ++ Get driver info, includings name, version ++ """ ++ self.logger.info("Vendor Info:", terminal_print=False) ++ self.command.run_cmd('lspci -vs %s' % self.device.pci) ++ ++ self.logger.info("Driver Info:", terminal_print=False) ++ driver = self.device.driver ++ self.logger.info("Driver Name: %s" % driver) ++ ++ driver_version = self.device.get_driver_version() ++ if driver_version: ++ self.logger.info("Driver Version: %s" % driver_version) ++ else: ++ self.logger.warning( ++ "The driver version information cannot be obtained. Please view it manually.") ++ ++ def test_pressure(self): ++ """ ++ Set pressure for gpu to test ++ This test need graphical.target to support ++ Returns: ++ bool: ++ """ ++ os.chdir("/opt/glmark2/build/src") ++ cmd = getstatusoutput( ++ './glmark2 --off-screen | tee %s' % self.glmark_log) ++ if cmd[0] != 0: ++ self.logger.error("Test gpu pressure failed.") ++ return False ++ self.logger.info("Test gpu pressure succeed.") ++ ++ cmd = self.command.run_cmd( ++ "grep 'glmark2 Score' %s" % self.glmark_log) ++ if cmd[2] == 0: ++ self.logger.info("Check gpu glmark2 score succeed.") ++ else: ++ self.logger.error("Check gpu glmark2 score failed.") ++ return False ++ ++ return True ++ ++ def test_screen_info(self): ++ """ ++ Test screen information for gpu ++ This test need graphical.target to support ++ Returns: ++ bool: ++ """ ++ os.chdir("/opt/glmark2/build/src") ++ cmd = self.command.run_cmd( ++ "./glmark2 -l | tee %s " % self.screen_info_log) ++ if cmd[2] == 0: ++ self.logger.info("Test gpu screen information succeed.") ++ else: ++ self.logger.error("Test gpu screen information failed.") ++ return False ++ ++ return True ++ ++ def test_radeontop(self): ++ """ ++ Check gpu utilization by radeontop, it can execute multi times and has log file ++ Returns: ++ bool: ++ """ ++ os.chdir("/opt/radeontop") ++ cmd = getstatusoutput( ++ "echo q | ./radeontop | tee %s" % self.radeontop_log) ++ if cmd[0] == 0: ++ self.logger.info("Check gpu radeontop succeed.") ++ else: ++ self.logger.error("Check gpu radeontop failed.") ++ return False ++ ++ return True ++ ++ def test_amd_gpu(self): ++ """ ++ AMD gpu test entry function ++ Returns: ++ bool: ++ """ ++ result = True ++ self.get_driver_info() ++ self.command.run_cmd( ++ "bash %s/test_amd_gpu.sh install_readontop" % gpu_dir) ++ self.command.run_cmd( ++ "bash %s/test_amd_gpu.sh install_glmark2" % gpu_dir) ++ ++ self.logger.info("Check gpu radeontop.") ++ try: ++ if not self.test_radeontop(): ++ result = False ++ ++ if not self.test_screen_info(): ++ result = False ++ ++ self.logger.info("Start to test gpu pressure.") ++ if not self.test_pressure(): ++ result = False ++ self.logger.info("End to test gpu pressure.") ++ ++ except Exception as e: ++ self.logger.error( ++ "Failed to run the script because compiling or setting variables: %s" % e) ++ result = False ++ ++ return result +diff -Naur rpm/tests/compatible/gpu/gpu.py oech/tests/compatible/gpu/gpu.py +--- rpm/tests/compatible/gpu/gpu.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/gpu/gpu.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,54 @@ ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @meitingli ++# Create: 2022-04-13 ++# Desc: GPU test, support AMD/NVIDIA series gpu ++ ++import argparse ++from hwcompatible.command import Command ++from hwcompatible.test import Test ++from nvidia_gpu import NvidiaGpuTest ++from amd_gpu import AMDGpuTest ++ ++ ++class GpuTest(Test): ++ def __init__(self): ++ Test.__init__(self) ++ self.requirements = ["gcc-c++", "make", "git"] ++ self.device = None ++ ++ def setup(self, args=None): ++ """ ++ Initialization before test ++ """ ++ self.args = args or argparse.Namespace() ++ self.logger = getattr(args, "test_logger", None) ++ self.device = getattr(args, 'device', None) ++ self.command = Command(self.logger) ++ ++ def test(self): ++ """ ++ Test case ++ Returns: ++ bool: Execution result ++ """ ++ driver = self.device.driver ++ if driver == "amdgpu": ++ amd_test = AMDGpuTest(self.device, self.logger, self.command) ++ result = amd_test.test_amd_gpu() ++ else: ++ nvidia_test = NvidiaGpuTest(self.device, self.logger, self.command) ++ result = nvidia_test.test_nvidia_gpu() ++ ++ return result ++ ++ +\ No newline at end of file +diff -Naur rpm/tests/compatible/gpu/Makefile oech/tests/compatible/gpu/Makefile +--- rpm/tests/compatible/gpu/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/gpu/Makefile 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,23 @@ ++# Copyright (c) 2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2022-04-13 ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a *.py $(DEST) ++ cp -a *.sh $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/gpu/nvidia_gpu.py oech/tests/compatible/gpu/nvidia_gpu.py +--- rpm/tests/compatible/gpu/nvidia_gpu.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/gpu/nvidia_gpu.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,154 @@ ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2022-10-14 ++# Desc: Nvidia GPU test ++ ++import os ++import re ++import time ++from subprocess import getstatusoutput ++gpu_dir = os.path.dirname(os.path.realpath(__file__)) ++ ++ ++class NvidiaGpuTest(): ++ def __init__(self, device, logger, command): ++ self.device = device ++ self.logger = logger ++ self.command = command ++ self.cuda_samples_log = os.path.join( ++ self.logger.logdir, 'cuda_samples.log') ++ self.gpu_burn = os.path.join(self.logger.logdir, 'gpu_burn.log') ++ self.smi_name = "nvidia-smi" ++ ++ def get_driver_info(self): ++ """ ++ Get driver info, includings name, version ++ """ ++ self.logger.info("Vendor Info:", terminal_print=False) ++ self.command.run_cmd('lspci -vs %s' % self.device.pci) ++ ++ self.logger.info("Driver Info:", terminal_print=False) ++ driver = self.device.driver ++ if driver == "iluvatar-itr": ++ self.smi_name = "ixsmi" ++ driver = "bi_driver" ++ self.device.set_driver(driver) ++ self.logger.info("Driver Name: %s" % driver) ++ ++ driver_version = self.device.get_driver_version() ++ if driver_version: ++ self.logger.info("Driver Version: %s" % driver_version) ++ else: ++ self.logger.warning( ++ "The driver version information cannot be obtained. Please view it manually.") ++ ++ def set_default_gpu(self): ++ pci = [] ++ num = [] ++ pci_key = "GPU 0000" + self.device.get_pci() ++ gpu = self.command.run_cmd('%s -q' % self.smi_name, log_print=False) ++ for line in gpu[0].split("\n"): ++ if "GPU 0000" in line: ++ pci.append(line) ++ if "Minor Number" in line: ++ num.append(line) ++ id_num = 0 ++ output = dict(zip(pci, num)) ++ if pci_key in output.keys(): ++ id_num = str(re.findall("\d+", output[pci_key])).strip("['']") ++ os.environ['CUDA_VISIBLE_DEVICES'] = id_num ++ ++ self.logger.info("Set default test gpu as %s." % id_num) ++ ++ def test_pressure(self): ++ """ ++ Set pressure for gpu to test ++ Returns: ++ bool: ++ """ ++ self.logger.info("Monitor GPU temperature and utilization rate.") ++ pci_num = self.device.get_pci() ++ self.command.run_cmd(self.smi_name) ++ self.command.run_cmd( ++ "bash %s/test_nvidia_gpu.sh install_gpu_burn" % gpu_dir) ++ ++ os.chdir("/opt/gpu-burn") ++ cmd = self.command.run_cmd( ++ "nvidia-smi -q | grep -i -A1 '%s' | grep 'Product Name' | cut -d ':' -f 2" % pci_num) ++ device_name = cmd[0].strip() ++ cmd = self.command.run_cmd( ++ "./gpu_burn -l | grep -i '%s' | cut -d ':' -f 1 | awk '{print $2}'" % device_name) ++ run_id = cmd[0].strip() ++ cmd = getstatusoutput( ++ 'nohup ./gpu_burn -i%s 10 &> %s &' % (run_id, self.gpu_burn)) ++ if cmd[0] != 0: ++ self.logger.error("Execute gpu_burn failed.") ++ return False ++ self.logger.info("Execute gpu_burn succeed.") ++ ++ time_start = time.time() ++ while 1: ++ cmd = self.command.run_cmd( ++ "ps -ef | grep 'gpu_burn' | grep -v grep", ignore_errors=True) ++ if cmd[2] != 0: ++ break ++ time_delta = time.time() - time_start ++ if time_delta >= 500: ++ break ++ self.command.run_cmd(self.smi_name) ++ time.sleep(5) ++ ++ return True ++ ++ def test_nvidia_gpu(self): ++ """ ++ Nvidia gpu test entry function ++ Returns: ++ bool: ++ """ ++ result = True ++ self.get_driver_info() ++ ++ self.logger.info("Check gpu information.") ++ self.command.run_cmd('%s -q' % self.smi_name) ++ self.logger.info("Check cuda version.") ++ self.command.run_cmd('/usr/local/cuda/bin/nvcc --version') ++ ++ self.logger.info("Start to test gpu pressure.") ++ try: ++ if not self.test_pressure(): ++ result = False ++ ++ check_result = self.command.run_cmd( ++ "grep 'GPU 0: OK' %s" % self.gpu_burn) ++ if os.path.exists(self.gpu_burn) and check_result[2] == 0: ++ self.logger.info("Test gpu pressure succeed.") ++ else: ++ self.logger.error("Test gpu pressure failed.") ++ result = False ++ ++ self.logger.info("Start to test cuda samples.") ++ self.set_default_gpu() ++ sample_case = "simpleOccupancy,bandwidthTest,p2pBandwidthLatencyTest,deviceQuery,clock" ++ code = self.command.run_cmd( ++ "bash %s/test_nvidia_gpu.sh test_cuda_samples '%s %s'" % (gpu_dir, self.cuda_samples_log, sample_case)) ++ if code[2] == 0: ++ self.logger.info("Test cuda samples succeed.") ++ else: ++ result = False ++ self.logger.error("Test cuda samples failed.") ++ except Exception as e: ++ self.logger.error( ++ "Failed to run the script because compiling or setting variables: %s" % e) ++ result = False ++ ++ return result +diff -Naur rpm/tests/compatible/gpu/test_amd_gpu.sh oech/tests/compatible/gpu/test_amd_gpu.sh +--- rpm/tests/compatible/gpu/test_amd_gpu.sh 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/gpu/test_amd_gpu.sh 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,56 @@ ++#!/usr/bin/bash ++# Copyright (c) 2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @meitingli ++# Create: 2022-10-13 ++# Desc: Shell script used for testing AMD gpu ++ ++function install_readontop() { ++ cd /opt ++ res_code=0 ++ if [ ! -d radeontop ]; then ++ git clone https://github.com/clbr/radeontop.git ++ dnf install -y libdrm-devel ncurses-devel ncurses-libs libpciaccess-devel libxcb-devel ++ fi ++ cd radeontop ++ make &>/dev/null || res_code=1 ++ ++ return $res_code ++} ++ ++function install_glmark2() { ++ cd /opt ++ res_code=0 ++ if [ ! -d glmark2 ]; then ++ git clone https://github.com/glmark2/glmark2.git ++ dnf install -y meson libX11-devel libpng-devel cmake pkgconf libjpeg libjpeg-turbo-devel libdrm-devel mesa-libgbm-devel libgudev-devel ++ fi ++ cd glmark2 ++ meson setup build -Dflavors=drm-gl,drm-glesv2,wayland-gl,wayland-glesv2,x11-gl,x11-glesv2 ++ ninja -C build &>/dev/null ++ ninja -C build install &>/dev/null || res_code=1 ++ ++ return $res_code ++} ++ ++function main() { ++ func_name=$1 ++ ++ if [[ $func_name == "install_readontop" ]]; then ++ install_readontop ++ elif [[ $func_name == "install_glmark2" ]]; then ++ install_glmark2 ++ else ++ echo "The function doesn't exist, please check!" ++ return 1 ++ fi ++} ++ ++main "$@" +diff -Naur rpm/tests/compatible/gpu/test_nvidia_gpu.sh oech/tests/compatible/gpu/test_nvidia_gpu.sh +--- rpm/tests/compatible/gpu/test_nvidia_gpu.sh 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/gpu/test_nvidia_gpu.sh 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,135 @@ ++#!/usr/bin/bash ++# Copyright (c) 2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @meitingli ++# Create: 2022-05-05 ++# Desc: Shell script used for testing nvidia gpu ++ ++cuda_version=$(nvidia-smi -q | grep "CUDA Version" | awk '{print $4}') ++cuda_name="cuda-samples-${cuda_version}" ++ ++function install_gpu_burn() { ++ cd /opt ++ res_code=0 ++ if [ ! -d gpu-burn ]; then ++ git clone https://github.com/wilicc/gpu-burn.git ++ fi ++ cd gpu-burn ++ lsmod | grep bi_driver >/dev/null ++ if [ $? -eq 0 ]; then ++ COREX_PATH=${COREX_PATH:-/usr/local/corex} ++ clang++ compare.cu -o compare.ll -I${COREX_PATH}/include --cuda-gpu-arch=ivcore10 --cuda-path=${COREX_PATH} --cuda-device-only -S -x cuda || res_code=1 ++ llc -mcpu=ivcore10 -mtriple=bi-iluvatar-ilurt -show-mc-encoding -filetype=obj compare.ll -o compare.o || res_code=1 ++ lld -flavor ld.lld --no-undefined compare.o -o compare.ptx || res_code=1 ++ rm compare.ll compare.o ++ sed -i '/cuFuncSet/d' gpu_burn-drv.cpp ++ sed -i '/cuParamSet/d' gpu_burn-drv.cpp ++ sed -i 's/nvidia-smi/ixsmi/g' gpu_burn-drv.cpp ++ sed -i 's/.*cuLaunchGridAsync.*/void\* kargs[] = {\&d_Cdata, \&d_faultyElemData, \&d_iters};checkError(cuLaunchKernel(d_function, SIZE\/g_blockSize, SIZE\/g_blockSize, 1, g_blockSize, g_blockSize, 1, 0, 0, kargs, nullptr));/g' gpu_burn-drv.cpp ++ clang++ -std=c++11 -I${COREX_PATH}/include -L${COREX_PATH}/lib64 -lcudart -lcuda -lcublas -o gpu_burn ./gpu_burn-drv.cpp || res_code=1 ++ else ++ make &>/dev/null || res_code=1 ++ fi ++ return $res_code ++} ++ ++function install_cuda_samples() { ++ cd /opt ++ if [ ! -d ${cuda_name} ]; then ++ wget https://github.com/NVIDIA/cuda-samples/archive/refs/tags/v${cuda_version}.zip ++ unzip v${cuda_version}.zip >/dev/null ++ rm -rf v${cuda_version}.zip ++ fi ++ return 0 ++} ++ ++function test_nvidia_case() { ++ casename=$1 ++ logfile=$2 ++ res_code=0 ++ cd /opt/${cuda_name} ++ path=$(find ./ -name $casename -type d) ++ cd $path ++ make &>/dev/null ++ ./$casename &>>$logfile ++ if [[ $? -eq 0 ]]; then ++ echo "Test $casename succeed." >>$logfile ++ else ++ echo "Test $casename failed." >>$logfile ++ res_code=1 ++ fi ++ return $res_code ++} ++ ++function test_iluvatar_case() { ++ casename=$1 ++ logfile=$2 ++ res_code=0 ++ CUDA_PATH=${CUDA_PATH:-/usr/local/corex} ++ cd /opt/${cuda_name} ++ path=$(find ./ -name $casename) ++ cd $path ++ src_file=${casename}.cu ++ if [ ! -f ./$src_file ] && [ -f ./${casename}.cpp ]; then ++ src_file=${casename}.cpp ++ fi ++ clang++ -std=c++11 -I../../../Common -I${CUDA_PATH}/include --cuda-path=${CUDA_PATH} -L${CUDA_PATH}/lib64 -lcudart -lixlogger -lcuda -lixthunk -o ${casename} ./${src_file} ++ ./$casename &>>$logfile ++ if [[ $? -eq 0 ]]; then ++ echo "Test $casename succeed." ++ else ++ echo "Test $casename failed." ++ res_code=1 ++ fi ++ return $res_code ++} ++ ++function test_cuda_samples() { ++ logfile=$1 ++ allcases=(${2//,/ }) ++ res_code=0 ++ install_cuda_samples ++ cd /opt/${cuda_name} ++ lsmod | grep bi_driver ++ if [[ $? -eq 0 ]]; then ++ for casename in ${allcases[@]}; do ++ test_iluvatar_case $casename $logfile ++ if [[ $? -eq 1 ]]; then ++ res_code=1 ++ fi ++ done ++ else ++ for casename in ${allcases[@]}; do ++ test_nvidia_case $casename $logfile ++ if [[ $? -eq 1 ]]; then ++ res_code=1 ++ fi ++ done ++ fi ++ return $res_code ++} ++ ++function main() { ++ func_name=$1 ++ param_list=$2 ++ ++ if [[ $func_name == "install_gpu_burn" ]]; then ++ install_gpu_burn ++ elif [[ $func_name == "install_cuda_samples" ]]; then ++ install_cuda_samples ++ elif [[ $func_name == "test_cuda_samples" ]]; then ++ test_cuda_samples $param_list ++ else ++ echo "The function doesn't exist, please check!" ++ return 1 ++ fi ++} ++ ++main "$@" +diff -Naur rpm/tests/compatible/infiniband/infiniband.py oech/tests/compatible/infiniband/infiniband.py +--- rpm/tests/compatible/infiniband/infiniband.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/infiniband/infiniband.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,47 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2022-05-24 ++# Desc: InfiniBand Test ++ ++from tests.compatible.network.rdma import RDMATest ++ ++ ++class InfiniBandTest(RDMATest): ++ def __init__(self): ++ RDMATest.__init__(self) ++ self.subtests = [self.test_ip_info, self.test_ibstatus, ++ self.test_ib_link, self.test_icmp, self.test_rdma] ++ ++ def test_ib_link(self): ++ """ ++ IB Link test ++ :return: ++ """ ++ if 'LinkUp' not in self.phys_state: ++ self.logger.error("Device is not LinkUp.") ++ ++ if 'ACTIVE' not in self.state: ++ self.logger.error("Link is not ACTIVE.") ++ ++ if self.base_lid == 0x0: ++ self.logger.error("Fail to get base lid of %s." % self.interface) ++ return False ++ self.logger.info("The base lid is %s." % self.base_lid) ++ ++ if self.sm_lid == 0x0: ++ self.logger.error( ++ "Fail to get subnet manager lid of %s." % self.interface) ++ return False ++ self.logger.info("The subnet manager lid is %s." % self.sm_lid) ++ ++ return True +diff -Naur rpm/tests/compatible/infiniband/Makefile oech/tests/compatible/infiniband/Makefile +--- rpm/tests/compatible/infiniband/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/infiniband/Makefile 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,22 @@ ++# Copyright (c) 2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2022-05-23 ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a *.py $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/__init__.py oech/tests/compatible/__init__.py +--- rpm/tests/compatible/__init__.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/__init__.py 2023-12-07 15:01:42.225942288 +0800 +@@ -0,0 +1,10 @@ ++# Copyright (c) 2020 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 +diff -Naur rpm/tests/compatible/ipmi/ipmi.py oech/tests/compatible/ipmi/ipmi.py +--- rpm/tests/compatible/ipmi/ipmi.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/ipmi/ipmi.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,60 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++# Desc: Intelligent Platform Management Interface test ++ ++from hwcompatible.test import Test ++ ++ ++class IpmiTest(Test): ++ def __init__(self): ++ Test.__init__(self) ++ self.requirements = ["OpenIPMI", "ipmitool"] ++ ++ def start_ipmi(self): ++ """ ++ Start IPMI test ++ :return: ++ """ ++ self.command.run_cmd("systemctl start ipmi") ++ result = self.command.run_cmd("systemctl status ipmi.service | grep 'Active: active'" ) ++ if result[2] != 0: ++ self.logger.error("Ipmi service start failed.") ++ return False ++ self.logger.info("Ipmi service start succeed.") ++ return True ++ ++ def ipmitool(self): ++ """ ++ Testing with iptool tools ++ :return: ++ """ ++ cmd_list = ["ipmitool fru", "ipmitool sensor"] ++ for cmd in cmd_list: ++ result = self.command.run_cmd(cmd) ++ if result[2] != 0: ++ self.logger.error("%s execute failed." % cmd) ++ return False ++ self.logger.info("%s execute successfully." % cmd) ++ return True ++ ++ def test(self): ++ """ ++ Test case ++ :return: ++ """ ++ if not self.start_ipmi(): ++ return False ++ if not self.ipmitool(): ++ return False ++ return True +diff -Naur rpm/tests/compatible/ipmi/Makefile oech/tests/compatible/ipmi/Makefile +--- rpm/tests/compatible/ipmi/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/ipmi/Makefile 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,22 @@ ++# Copyright (c) 2020 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a *.py $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/kabi/kabi.py oech/tests/compatible/kabi/kabi.py +--- rpm/tests/compatible/kabi/kabi.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/kabi/kabi.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,144 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++# Copyright (c) 2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2.gica's ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @meitingli ++# Create: 2022-05-30 ++# Desc: Public kabi test ++ ++import os ++import argparse ++from subprocess import getoutput ++from hwcompatible.command import Command ++from hwcompatible.test import Test ++from hwcompatible.constants import TEST_KABI_ARCH ++from hwcompatible.sysinfo import SysInfo ++from hwcompatible.env import CertEnv ++from hwcompatible.document import Document ++ ++kabi_dir = os.path.dirname(os.path.realpath(__file__)) ++ ++ ++class KabiTest(Test): ++ def __init__(self): ++ Test.__init__(self) ++ self.kernel_version = getoutput("uname -r") ++ self.requirements = ["gzip", "rpm-build"] ++ self.symvers = None ++ self.wl_logpath = "" ++ self.miss_logpath = "" ++ self.changed_logpath = "" ++ self.sysinfo = SysInfo(CertEnv.releasefile) ++ ++ def setup(self, args=None): ++ """ ++ Initialization before test ++ """ ++ self.args = args or argparse.Namespace() ++ self.logger = getattr(self.args, "test_logger", None) ++ self.command = Command(self.logger) ++ self.wl_logpath = os.path.join( ++ self.logger.logdir, "kabi-whitelist.log") ++ self.miss_logpath = os.path.join( ++ self.logger.logdir, "kabi-missing.log") ++ self.changed_logpath = os.path.join( ++ self.logger.logdir, "kabi-changed.log") ++ self.symvers = os.path.join( ++ CertEnv.datadirectory, "symvers-" + self.kernel_version) ++ ++ def test(self): ++ """ ++ Run kabi test case ++ return: result ++ """ ++ arch = self.command.run_cmd("uname -m")[0].strip() ++ if arch not in TEST_KABI_ARCH: ++ self.logger.info(" %s architecture does not support kabi testing." % arch) ++ return True ++ ++ result = True ++ self.logger.info("Start to test, please wait...") ++ if not os.path.exists(self.symvers): ++ symvers_gz = "symvers-" + self.kernel_version + ".gz" ++ self.command.run_cmd("cp /boot/%s %s" % ++ (symvers_gz, CertEnv.datadirectory)) ++ self.command.run_cmd("gzip -d %s/%s" % ++ (CertEnv.datadirectory, symvers_gz)) ++ ++ standard_symvers = self._get_kernel_source_rpm(arch) ++ with open(standard_symvers, "r") as f: ++ for line in f.readlines(): ++ line = line.strip().replace("\n", "") ++ if line == "": ++ continue ++ ++ hsdp = line.split() ++ if len(hsdp) < 4 : ++ continue ++ ++ result = self.command.run_cmd("grep %s %s" % ( ++ hsdp[1], self.symvers), log_print=False) ++ data = result[0] ++ if data and hsdp[0] in data: ++ continue ++ elif data and hsdp[0] not in data: ++ if not os.path.exists(self.changed_logpath): ++ self.command.run_cmd("echo 'standard_symvers cur_symvers' | tee %s" % ( ++ self.changed_logpath), log_print=False) ++ ++ self.command.run_cmd("echo '{%s} {%s}' | tee %s" % ( ++ line, data, self.changed_logpath), log_print=False) ++ result = False ++ else: ++ self.command.run_cmd("echo '%s' | tee %s" % ( ++ line, self.miss_logpath), log_print=False) ++ result = False ++ ++ if result: ++ self.logger.info("Test kabi succeed.") ++ else: ++ self.logger.error("Test kabi failed.") ++ ++ return result ++ ++ def _get_kernel_source_rpm(self, arch): ++ """ ++ get the path of kernel source rpm ++ """ ++ rpmpath = "/root/rpmbuild/SOURCES" ++ standard_symvers = os.path.join(rpmpath, "Module.kabi_" + arch) ++ if os.path.exists(standard_symvers): ++ return standard_symvers ++ ++ product = self.sysinfo.product.split(" ")[0] ++ if product == "openEuler": ++ standard_kernel_version = getoutput( ++ "dnf list --repo=source | grep '^kernel.src' | awk '{print $2}'") ++ self.command.run_cmd("dnf download --source kernel-%s" ++ % standard_kernel_version) ++ elif product == "KylinSec": ++ kylinsec_version = getoutput("cat /etc/dnf/vars/osversion | sed 's/[^0-9]//g'") ++ kernel_dict = Document(CertEnv.kernelinfo, self.logger) ++ if not kernel_dict.load(): ++ self.logger.error("Failed to get kernel info.") ++ return False ++ openeuler_version = kernel_dict.document[product][kylinsec_version].split('/')[0] ++ standard_kernel_version = kernel_dict.document[product][kylinsec_version].split('/')[1] ++ url = "https://repo.openeuler.org/%s/source/Packages/kernel-%s.src.rpm" \ ++ % (openeuler_version, standard_kernel_version) ++ self.command.run_cmd("wget %s -P %s" % (url, rpmpath)) ++ else: ++ self.logger.info("Currently, this system is not supported to test kabi," ++ " Please add the corresponding system in kernelrelease.json.") ++ ++ rpm = os.path.join("kernel-" + standard_kernel_version + ".src.rpm") ++ getoutput("rpm -ivh %s" % rpm) ++ os.remove(rpm) ++ return standard_symvers +diff -Naur rpm/tests/compatible/kabi/Makefile oech/tests/compatible/kabi/Makefile +--- rpm/tests/compatible/kabi/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/kabi/Makefile 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,23 @@ ++# Copyright (c) 2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2.gica's ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @meitingli ++# Create: 2022-05-30 ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a *.py $(DEST) ++ chmod a+x $(DEST)/*.py ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/kabiwhitelist/kabi_check.sh oech/tests/compatible/kabiwhitelist/kabi_check.sh +--- rpm/tests/compatible/kabiwhitelist/kabi_check.sh 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/kabiwhitelist/kabi_check.sh 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,179 @@ ++#!/usr/bin/bash ++# Copyright (c) 2023 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @liqiang1118 ++# Create: 2023-05-15 ++ ++mkdir /usr/share/oech/lib/tests/kabiwhitelist/test_log ++testdir="/usr/share/oech/lib/tests/kabiwhitelist/test_log" ++cd $testdir ++ ++os_version=`cat /etc/openEuler-latest|grep openeulerversion |awk -F = '{print $2}'` ++arch=`uname -m` ++url="https://gitee.com/src-openeuler/kernel/raw/$os_version/kabi_whitelist_$arch" ++wget $url ++kernel_version=`uname -r` ++symvers_gz="symvers-"$kernel_version".gz" ++cp /boot/$symvers_gz /usr/share/oech/lib/tests/kabiwhitelist/test_log ++gunzip /usr/share/oech/lib/tests/kabiwhitelist/test_log/$symvers_gz ++ ++# Desc: Test kabi ++# Input: xxx.ko or xxx.rpm ++function test_kabi() { ++ cat $kabi.kabi |while read line; ++ do ++ kabiname=`echo $line |awk '{print $2}'` ++ filename=`echo $line |awk '{print $1}'` ++ cat kabi_whitelist_$arch|grep "$kabiname" >> $filename.txt ++ have=`cat $filename.txt|wc -l` ++ if [ $have == 0 ]; then ++ echo $line >> $kabi"_change_"$arch ++ fi ++ done ++ cat $kabi.kabi |while read line; ++ do ++ real=`echo $line|awk '{print $2}'` ++ if [ -f $kabi"_change_"$arch ]; then ++ white_list=`cat $kabi"_change_"$arch|grep "$real" |wc -l` ++ if [ $white_list == 0 ]; then ++ echo $line >> $kabi"_white_"$arch ++ fi ++ else ++ echo $line >> $kabi"_white_"$arch ++ fi ++ done ++} ++ ++ ++function test_inlist(){ ++ if [ -f $kabi"_change_"$arch ]; then ++ cat $kabi"_change_"$arch |while read line; ++ do ++ changekb=`echo $line |awk '{print $2}'` ++ inos=`cat symvers-"$kernel_version" |grep $changekb|wc -l` ++ if [ $inos == 0 ]; then ++ echo $changekb >> $kabi"_changeos" ++ else ++ echo $changekb >> $kabi"_inlist" ++ fi ++ done ++ fi ++} ++ ++ ++function real_result(){ ++ if [ -f $kabi"_change_"$arch ]; then ++ cat $kabi"_change_"$arch|while read line; ++ do ++ inlist=`echo $line|awk '{print $2}'` ++ noin=`cat $kabi"_changeos" |grep $inlist|wc -l` ++ if [ $noin == 0 ]; then ++ echo $line >> $kabi"_change" ++ ++ fi ++ ++ done ++ fi ++} ++ ++echo "####################KABI TEST START####################" ++cat /usr/share/oech/lib/config/test_config.yaml|grep name|awk -F "'" '{print $2}' >> dir.txt ++if_test=`cat dir.txt|wc -w` ++if [ $if_test == 0 ]; then ++ echo "Please configure the board information in the configuration file" > change.txt ++ echo "no ko or rpm" >> nokorpm.txt ++ cat change.txt ++fi ++cat dir.txt|while read line; ++do ++ lineword=`echo $line |wc -w` ++ if [ "$lineword" -gt 0 ]; then ++ echo $line >> dirt.txt ++ fi ++done ++cat dirt.txt |while read line; ++do ++ if [ -f /root/$line ]; then ++ cp /root/$line ./ ++ echo $line >> dirth ++ fi ++done ++cat dirth|while read line; ++do ++ for i in $line ++ do ++ class=`echo $i|awk -F . '{print $NF}'` ++ if [ $class == ko ]; then ++ kabi=`echo $i|awk -F . '{print $1}'` ++ modprobe --dump $i > $kabi.kabi ++ test_kabi ++ test_inlist ++ real_result ++ elif [ $class == rpm ]; then ++ echo "this is a rpm please wait" > /dev/null ++ rpm2cpio $i |cpio -div ++ find ./ -name "*.ko*" |grep module >> rpmko ++ ifrpm=`cat rpmko|wc -l` ++ if [ $ifrpm == 0 ]; then ++ echo "Please check rpm" > rpmchange ++ echo "Please check rpm" ++ exit 0 ++ else ++ echo "$i rpm decompression completed" ++ fi ++ cat rpmko|while read line; ++ do ++ cp $line ./ ++ koname=`echo $line |awk -F "/" '{print $NF}'` ++ kabi=`echo $koname|awk -F . '{print $1}' ` ++ modprobe --dump $koname > $kabi.kabi ++ echo $koname >> realname ++ test_kabi ++ test_inlist ++ real_result ++ done ++ fi ++ done ++done ++ ++ ++# save test log ++cat dirth |grep ko >> realname ++cat realname |while read line; ++do ++ kabi=`echo $line |awk -F . '{print $1}'` ++ if [ ! -f $kabi"_change_"$arch ]; then ++ echo "$kabi kabi $arch test pass" >> result ++ else ++ echo "$kabi kabi $arch test fail" >> result ++ fi ++done ++echo "Test results are as follows" ++cat result ++cat realname|grep ko |awk -F . '{print $1}' > res.txt ++cat res.txt |while read line; ++do ++ if [ -f $line"_change" ] || [ -f $line"_white_"$arch ]; then ++ if [ -f $line"_change" ]; then ++ whitenum=`cat $line"_change" |wc -l` ++ echo "Here are $line.ko KABI not in whitelist count=$whitenum" ++ cat $line"_change" ++ fi ++ if [ -f $line"_white_"$arch ]; then ++ notnum=`cat $line"_white_"$arch |wc -l` ++ echo "Here are $line.ko KABI in whitelist count=$notnum" ++ cat $line"_white_"$arch ++ fi ++ fi ++ if [ -f $line"_changeos" ]; then ++ echo "Here are $line.ko KABI not in OS KABI list" ++ cat $line"_changeos" ++ fi ++done +diff -Naur rpm/tests/compatible/kabiwhitelist/kabiwhitelist.py oech/tests/compatible/kabiwhitelist/kabiwhitelist.py +--- rpm/tests/compatible/kabiwhitelist/kabiwhitelist.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/kabiwhitelist/kabiwhitelist.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,64 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++# Copyright (c) 2023 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2.gica's ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @liqiang1118 ++# Create: 2023-05-15 ++# Desc: Public kabi test ++ ++import os ++import shutil ++import argparse ++from subprocess import getoutput ++from hwcompatible.command import Command ++from hwcompatible.test import Test ++ ++kabi_whitelist_dir = os.path.dirname(os.path.realpath(__file__)) ++ ++ ++class KabiWhiteListTest(Test): ++ def __init__(self): ++ Test.__init__(self) ++ self.requirements = ["gzip", "rpm-build"] ++ ++ def setup(self, args=None): ++ """ ++ Initialization before test ++ """ ++ self.args = args or argparse.Namespace() ++ self.logger = getattr(self.args, "test_logger", None) ++ self.command = Command(self.logger) ++ ++ def test(self): ++ """ ++ Run kabi test case ++ return: result ++ """ ++ self.command.run_cmd("bash %s/kabi_check.sh" % kabi_whitelist_dir) ++ ko_result = self.command.run_cmd("ls %s/test_log/ | grep noko" % kabi_whitelist_dir) ++ if ko_result[2] == 0: ++ self.logger.error("Please configure the board information in the configuration file") ++ return False ++ self.logger.info("Ko or rpm check complete") ++ ++ test_result = self.command.run_cmd("ls %s/test_log | grep change" % kabi_whitelist_dir) ++ if test_result[2] == 0: ++ self.logger.error("Kabiwhitelist test fail") ++ return False ++ return True ++ ++ def teardown(self): ++ """ ++ Clear temporary files ++ """ ++ file_name = "/usr/share/oech/lib/tests/kabiwhitelist/test_log" ++ if os.path.exists(file_name): ++ shutil.rmtree(file_name) ++ self.logger.info("Clearing temporary files is complete") +diff -Naur rpm/tests/compatible/kabiwhitelist/Makefile oech/tests/compatible/kabiwhitelist/Makefile +--- rpm/tests/compatible/kabiwhitelist/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/kabiwhitelist/Makefile 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,26 @@ ++# Copyright (c) 2023 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Author: @liqiang1118 ++# Create: 2023-05-15 ++# Desc: KabiWhitelist test ++ ++.PHONY: install clean ++ ++all: ; ++ ++install: ++ mkdir -p $(DEST) ++ cp -a $(SUBDIR)/build *.py $(DEST) ++ cp -a $(SUBDIR)/build *.sh $(DEST) ++ chmod a+x $(DEST)/*.py ++ chmod a+x $(DEST)/*.sh ++ ++clean: ++ rm -rf $(DEST) +diff -Naur rpm/tests/compatible/kdump/kdump.py oech/tests/compatible/kdump/kdump.py +--- rpm/tests/compatible/kdump/kdump.py 1970-01-01 08:00:00.000000000 +0800 ++++ oech/tests/compatible/kdump/kdump.py 2023-12-07 15:01:42.229942342 +0800 +@@ -0,0 +1,119 @@ ++#!/usr/bin/env python3 ++# coding: utf-8 ++ ++# Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. ++# oec-hardware is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++# Create: 2020-04-01 ++# Desc: Kdump Test ++ ++import os ++import re ++from time import sleep ++from subprocess import getoutput ++from hwcompatible.test import Test ++from hwcompatible.command import Command ++from hwcompatible.command_ui import CommandUI ++from hwcompatible.document import ConfigFile ++ ++ ++class KdumpTest(Test): ++ def __init__(self): ++ Test.__init__(self) ++ self.pri = 9 ++ self.reboot = True ++ self.kernel_version = getoutput("uname -r") ++ self.rebootup = "verify_vmcore" ++ self.kdump_conf = "/etc/kdump.conf" ++ self.vmcore_path = "/var/crash" ++ self.requirements = ["crash", "kexec-tools"] ++ ++ def test(self): ++ """ ++ Test case ++ :return: ++ """ ++ cmd_result = self.command.run_cmd("yum install -y kernel-debuginfo-%s" % self.kernel_version) ++ if len(cmd_result[1]) != 0 and cmd_result[2] != 0: ++ self.logger.error( ++ "Fail to install required packages.\n %s" % cmd_result[1]) ++ return False ++ ++ cmd_result = self.command.run_cmd("grep crashkernel /proc/cmdline") ++ if cmd_result[2] != 0: ++ self.logger.error( ++ "The /proc/cmdline file cannot find crashkernel.") ++ return False ++ crash_kernel = cmd_result[0].split(" ") ++ crash_size = "" ++ for line in crash_kernel: ++ if "crashkernel" in line: ++ crash_size = line.split("=")[1] ++ break ++ self.logger.info("The value of crashkernel is %s" % crash_size) ++ ++ config = ConfigFile(self.kdump_conf) ++ if not config.get_parameter("path"): ++ config.add_parameter("path", self.vmcore_path) ++ else: ++ self.vmcore_path = config.get_parameter("path") ++ ++ if config.get_parameter("kdump_obj") == "kbox": ++ config.remove_parameter("kdump_obj") ++ config.add_parameter("kdump_obj", "all") ++ ++ self.command.run_cmd("systemctl restart kdump") ++ cmd = self.command.run_cmd( ++ "systemctl status kdump | grep 'Active: active'") ++ if cmd[2] != 0: ++ self.logger.error("Kdump service is not active.") ++ return False ++ self.logger.info("Start kdump service succeed.") ++ ++ self.logger.info("kdump config.") ++ config.dump() ++ ++ com_ui = CommandUI() ++ if com_ui.prompt_confirm("System will reboot, are you ready?"): ++ self.logger.info("Trigger crash, please wait seconds.") ++ self.command.run_cmd("sync", log_print=False) ++ self.command.run_cmd("echo 'c' | tee /proc/sysrq-trigger") ++ sleep(30) ++ return False ++ ++ return False ++ ++ def verify_vmcore(self, logger): ++ """ ++ Verify vmcore ++ :return: ++ """ ++ config = ConfigFile(self.kdump_conf) ++ if config.get_parameter("path"): ++ self.vmcore_path = config.get_parameter("path") ++ ++ dir_pattern = re.compile( ++ r'(?P[0-9]+\.[0-9]+\.[0-9]+)-(?P[0-9]+[-.][0-9]+[-.][0-9]+)-' ++ r'(?P