def comp_meta(file_bef, file_aft, mode="pfail"): """Compare chunk meta, mode=[pfail, power, reboot]""" if env(): cij.err("cij.nvme.comp_meta: Invalid NVMe ENV.") return 1 nvme = cij.env_to_dict(PREFIX, EXPORTED + REQUIRED) num_chk = int(nvme["LNVM_TOTAL_CHUNKS"]) meta_bef = cij.bin.Buffer(types=get_descriptor_table(nvme['SPEC_VERSION']), length=num_chk) meta_aft = cij.bin.Buffer(types=get_descriptor_table(nvme['SPEC_VERSION']), length=num_chk) meta_bef.read(file_bef) meta_aft.read(file_aft) for chk in range(num_chk): ignore = ["WL", "RSV0"] # PFAIL: BEFORE IS OPEN CHUNK, WRITE POINTER IS NOT SURE, IGNORE if mode == "pfail" and meta_bef[chk].CS == 4: ignore.append("WP") # COMPARE CHUNK META if meta_bef.compare(meta_aft, chk, ignore=ignore): cij.warn("META_BUFF_BEF[%s]:" % chk) meta_bef.dump(chk) cij.warn("META_BUFF_AFT[%s]:" % chk) meta_aft.dump(chk) cij.err("Error compare, CHUNK: %s" % chk) return 1 return 0
def execute(cmd=None, shell=True, echo=True): """ Execute the given 'cmd' @returns (rcode, stdout, stderr) """ if echo: cij.emph("cij.util.execute: shell: %r, cmd: %r" % (shell, cmd)) rcode = 1 stdout, stderr = ("", "") if cmd: if shell: cmd = " ".join(cmd) proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=shell, close_fds=True) stdout, stderr = proc.communicate() rcode = proc.returncode if rcode and echo: cij.warn("cij.util.execute: stdout: %s" % stdout) cij.err("cij.util.execute: stderr: %s" % stderr) cij.err("cij.util.execute: rcode: %s" % rcode) return rcode, stdout, stderr
def main(args): """Main entry point""" trun = cij.runner.trun_from_file(args.trun_fpath) # pylint: disable=no-member rehome(trun.args.output, args.output, trun) postprocess(trun) cij.emph("main: reports are uses tmpl_fpath: %r" % args.tmpl_fpath) cij.emph("main: reports are here args.output: %r" % args.output) _, ext = os.path.splitext(args.tmpl_fpath) html_fpath = os.path.join(args.output, "".join([args.tmpl_name, ext])) cij.emph("html_fpath: %r" % html_fpath) try: # Create and store HTML report with open(html_fpath, 'w', encoding="UTF-8") as html_file: html_file.write(dset_to_html(trun, args.tmpl_fpath)) except (IOError, OSError, ValueError) as exc: traceback.print_exc() cij.err("rprtr:main: exc: %s" % exc) return 1 return 0
def tcase_comment(tcase): """ Extract testcase comment section / testcase description @returns the testcase-comment from the tcase["fpath"] as a list of strings """ src = open(tcase["fpath"]).read() if len(src) < 3: cij.err("rprtr::tcase_comment: invalid src, tcase: %r" % tcase["name"]) return None ext = os.path.splitext(tcase["fpath"])[-1] if ext not in [".sh", ".py"]: cij.err("rprtr::tcase_comment: invalid ext: %r, tcase: %r" % (ext, tcase["name"])) return None comment = [] for line in src.splitlines()[2:]: if ext == ".sh" and not line.startswith("#"): break elif ext == ".py" and not '"""' in line: break comment.append(line) return comment
def power_on(self, interval=200): """230v power on""" if self.__power_on_port is None: cij.err("cij.usb.relay: Invalid USB_RELAY_POWER_ON") return 1 return self.__press(self.__power_on_port, interval=interval)
def tcase_comment(tcase): """ Extract testcase comment section / testcase description @returns the testcase-comment from the tcase.fpath as a list of strings """ src = "" with open(tcase.fpath, encoding="UTF-8") as tcase_f: src = tcase_f.read() if len(src) < 3: cij.err("rprtr::tcase_comment: invalid src, tcase: %r" % tcase.name) return None ext = os.path.splitext(tcase.fpath)[-1] if ext not in [".sh", ".py"]: cij.err("rprtr::tcase_comment: invalid ext: %r, tcase: %r" % (ext, tcase.name)) return None comment = [] for line in src.splitlines()[2:]: if ext == ".sh" and not line.startswith("#"): break if ext == ".py" and '"""' not in line: break comment.append(line) return comment
def command(cmd, shell=True, echo=True, suffix=None): """SSH: Run the given command over SSH as defined in environment""" if env(): cij.err("cij.ssh.command: Invalid SSH environment") return 1 prefix = [] if cij.ENV.get("SSH_CMD_TIME") == "1": prefix.append("/usr/bin/time") if cij.ENV.get("SSH_CMD_TIMEOUT"): prefix.append("timeout") prefix.append(cij.ENV.get("SSH_CMD_TIMEOUT")) prefix.append("ssh") args = [] if cij.ENV.get("SSH_KEY"): args.append("-i") args.append(cij.ENV.get("SSH_KEY")) if cij.ENV.get("SSH_PORT"): args.append("-p") args.append(cij.ENV.get("SSH_PORT")) args.append("@".join([cij.ENV.get("SSH_USER"), cij.ENV.get("SSH_HOST")])) wrapped = prefix + args + ["'%s'" % " ".join(cmd)] if suffix: wrapped += suffix return cij.util.execute(wrapped, shell, echo)
def wait(timeout=300): """Wait util target connected""" if env(): cij.err("cij.ssh.wait: Invalid SSH environment") return 1 timeout_backup = cij.ENV.get("SSH_CMD_TIMEOUT") try: time_start = time.time() cij.ENV["SSH_CMD_TIMEOUT"] = "3" while True: time_current = time.time() if (time_current - time_start) > timeout: cij.err("cij.ssh.wait: Timeout") return 1 status, _, _ = command(["exit"], shell=True, echo=False) if not status: break cij.info("cij.ssh.wait: Time elapsed: %d seconds" % (time_current - time_start)) finally: if timeout_backup is None: del cij.ENV["SSH_CMD_TIMEOUT"] else: cij.ENV["SSH_CMD_TIMEOUT"] = timeout_backup return 0
def main(args): """ Run cij analyser steps. If `preqs` is set, log files in the given TRUN path are searched for metric.yml-files and the TRUN will be updated with pass/fail for performance requirements. """ trun = cij.runner.trun_from_file(args.trun_fpath) # pylint: disable=no-member rehome(trun.args.output, args.output, trun) try: err = 0 if args.preqs: preqs_declr = preqs_from_file(args.preqs) preq_err = analyse_prequirements(trun, preqs_declr) if preq_err: cij.err('Failed to analyse prequirements') else: cij.info('Successfully analyzed prequirements') err += preq_err cij.runner.trun_to_file(trun, fpath=cij.runner.yml_fpath(args.output)) except CIJError as ex: cij.err(f"main:FAILED to run analysis: {ex}") return err
def env(): """Verify FIO variables and construct exported variables""" if cij.ssh.env(): cij.err("cij.dmesg.env: invalid SSH environment") return 1 return 0
def tcase_parse_descr(tcase): """Parse descriptions from the the given tcase""" descr_short = "SHORT" descr_long = "LONG" try: comment = tcase_comment(tcase) except (IOError, OSError, ValueError) as exc: comment = [] cij.err("tcase_parse_descr: failed: %r, tcase: %r" % (exc, tcase)) comment = [l for l in comment if l.strip()] # Remove empty lines for line_number, line in enumerate(comment): if line.startswith("#"): comment[line_number] = line[1:] if comment: descr_short = comment[0] if len(comment) > 1: descr_long = "\n".join(comment[1:]) return descr_short, descr_long
def power_btn(self, interval=200): """TARGET power button""" if self.__power_btn_port is None: cij.err("cij.usb.relay: Invalid USB_RELAY_POWER_BTN") return 1 return self.__press(self.__power_btn_port, interval=interval)
def command_to_struct(cmd): """ Same as `command` except it tries to convert stdout to struct @returns (rcode, struct, stderr, struct) """ struct = None rcode, stdout, stderr = command(cmd) try: lines = [] for line in stdout.splitlines(): if line.strip().startswith("#"): continue lines.append(line) struct = yaml.safe_load("\n".join(lines)) except (yaml.YAMLError) as exc: cij.err("could not parse stdout as yaml, exc: %r" % exc) return rcode, stdout, stderr, struct
def hooks_setup(trun: TestRun, instance: Runnable, hnames=None): """ Setup hooks on the given 'instance' on the form: .hooks: {"enter": [], "exit": []} .hnames: ["hook1", "hook2"] """ hooks: Dict[str, List[Hook]] = {"enter": [], "exit": []} if hnames is None: # Setup empty hooks instance.hnames = [] instance.hooks = hooks return for hname in hnames: # Fill out paths for med, patterns in HOOK_PATTERNS.items(): for ptn in patterns: fpath = os.path.join(trun.conf.hooks, ptn % hname) if not os.path.exists(fpath): continue hook = hook_setup(instance, fpath) hooks[med].append(hook) if not hooks["enter"] + hooks["exit"]: msg = "rnr:hooks_setup:FAIL { hname: %r has no files }" % hname cij.err(msg) raise InitializationError(msg) instance.hooks = hooks instance.hnames = hnames
def hooks_setup(trun, parent, hnames=None): """ Setup test-hooks @returns dict of hook filepaths {"enter": [], "exit": []} """ hooks = { "enter": [], "exit": [] } if hnames is None: # Nothing to do, just return the struct return hooks for hname in hnames: # Fill out paths for med in HOOK_PATTERNS: for ptn in HOOK_PATTERNS[med]: fpath = os.sep.join([trun["conf"]["HOOKS"], ptn % hname]) if not os.path.exists(fpath): continue hook = hook_setup(parent, fpath) if not hook: continue hooks[med].append(hook) if not hooks["enter"] + hooks["exit"]: cij.err("rnr:hooks_setup:FAIL { hname: %r has no files }" % hname) return None return hooks
def get_meta(offset, length, output): """Get chunk meta of NVMe device""" if env(): cij.err("cij.nvme.meta: Invalid NVMe ENV.") return 1 nvme = cij.env_to_dict(PREFIX, EXPORTED + REQUIRED) max_size = 0x40000 with open(output, "wb") as fout: for off in range(offset, length, max_size): size = min(length - off, max_size) cmd = [ "nvme get-log", nvme["DEV_PATH"], "-i 0xca", "-o 0x%x" % off, "-l 0x%x" % size, "-b" ] status, stdout, _ = cij.ssh.command(cmd, shell=True) if status: cij.err("cij.nvme.meta: Error get chunk meta") return 1 fout.write(stdout) return 0
def __set(self, name, state): if name not in self.__field.keys(): cij.err("cij.usb.relay: Unknown name: %s" % name) return 1 status, _, _ = cij.util.execute(["usbrelay %s=%s" % (name, state)]) if status: return 1 return 0
def __reset(self): if self.__field is None: cij.err("cij.usb.relay: Error usbrelay field") return 1 for name, value in self.__field.items(): if value == "1": if self.__set(name, 0): return 1 return 0
def texit(msg=None, rcode=1): """Exit the test""" msg = ", msg: %r" % msg if msg else "" if rcode: cij.err("cij.test: FAILED%s" % msg) else: cij.good("cij.test: PASSED%s" % msg) sys.exit(rcode)
def script_run(trun, script): """Execute a script or testcase""" if trun["conf"]["VERBOSE"]: cij.emph("rnr:script:run { script: %s }" % script) cij.emph("rnr:script:run:evars: %s" % script["evars"]) launchers = {".py": "python", ".sh": "source"} ext = os.path.splitext(script["fpath"])[-1] if not ext in launchers.keys(): cij.err("rnr:script:run { invalid script[\"fpath\"]: %r }" % script["fpath"]) return 1 launch = launchers[ext] with open(script["log_fpath"], "a") as log_fd: log_fd.write("# script_fpath: %r\n" % script["fpath"]) log_fd.flush() bgn = time.time() cmd = [ 'bash', '-c', 'CIJ_ROOT=$(cij_root) && ' 'source $CIJ_ROOT/modules/cijoe.sh && ' 'source %s && ' 'CIJ_TEST_RES_ROOT="%s" %s %s ' % (trun["conf"]["ENV_FPATH"], script["res_root"], launch, script["fpath"]) ] if trun["conf"]["VERBOSE"] > 1: cij.emph("rnr:script:run { cmd: %r }" % " ".join(cmd)) evars = os.environ.copy() evars.update({k: str(script["evars"][k]) for k in script["evars"]}) process = Popen(cmd, stdout=log_fd, stderr=STDOUT, cwd=script["res_root"], env=evars) process.wait() script["rcode"] = process.returncode script["wallc"] = time.time() - bgn if trun["conf"]["VERBOSE"]: cij.emph("rnr:script:run { wallc: %02f }" % script["wallc"]) cij.emph("rnr:script:run { rcode: %r } " % script["rcode"], script["rcode"]) return script["rcode"]
def script_run(trun: TestRun, script: Runnable): """Execute a script or testcase""" if trun.args.verbose: cij.emph("rnr:script:run { script: %s }" % script) cij.emph("rnr:script:run:evars: %s" % script.evars) launchers = {".py": "python", ".sh": "source"} ext = os.path.splitext(script.fpath)[-1] if ext not in launchers.keys(): cij.err("rnr:script:run { invalid script.fpath: %r }" % script.fpath) return 1 launch = launchers[ext] with open(script.log_fpath, "a", encoding="UTF-8") as log_fd: log_fd.write("# script_fpath: %r\n" % script.fpath) log_fd.flush() script.stamp["begin"] = time.time() cmd = [ 'bash', '-c', 'CIJ_ROOT=$(cij_root) && ' 'source $CIJ_ROOT/modules/cijoe.sh && ' 'source %s && ' 'CIJ_TEST_RES_ROOT="%s" %s %s ' % (trun.args.env_fpath, script.res_root, launch, script.fpath) ] if trun.args.verbose > 1: cij.emph("rnr:script:run { cmd: %r }" % " ".join(cmd)) evars = os.environ.copy() evars.update({k: str(script.evars[k]) for k in script.evars}) with Popen(cmd, stdout=log_fd, stderr=STDOUT, cwd=script.res_root, env=evars) as process: process.wait() script.rcode = process.returncode script.stamp["end"] = time.time() script.wallc = script.stamp["end"] - script.stamp["begin"] if trun.args.verbose: cij.emph("rnr:script:run { wallc: %02f }" % (script.wallc if script.wallc is not None else 0.0)) cij.emph("rnr:script:run { rcode: %r } " % script.rcode, script.rcode) return script.rcode
def fmt(lbaf=3): """Do format for NVMe device""" if env(): cij.err("cij.nvme.exists: Invalid NVMe ENV.") return 1 nvme = cij.env_to_dict(PREFIX, EXPORTED + REQUIRED) cmd = ["nvme", "format", nvme["DEV_PATH"], "-l", str(lbaf)] rcode, _, _ = cij.ssh.command(cmd, shell=True) return rcode
def exists(): """Verify that the ENV defined NVMe device exists""" if env(): cij.err("cij.nvm.exists: Invalid NVMe ENV.") return 1 nvm = cij.env_to_dict(PREFIX, EXPORTED + REQUIRED) cmd = ['[[ -b "%s" ]]' % nvm["DEV_PATH"]] rcode, _, _ = cij.ssh.command(cmd, shell=True, echo=False) return rcode
def exists(): """Verify that the ENV defined BLOCK device exists""" if env(): cij.err("cij.block.exists: invalid BLOCK environment") return 1 block = cij.env_to_dict(PREFIX, EXPORTED + REQUIRED) cmd = ['[[ -b "%s" ]]' % block["DEV_PATH"]] rcode, _, _ = cij.ssh.command(cmd, shell=True, echo=False) return rcode
def env(): """Verify LNVM variables and construct exported variables""" if cij.ssh.env(): cij.err("cij.lnvm.env: invalid SSH environment") return 1 lnvm = cij.env_to_dict(PREFIX, REQUIRED) nvme = cij.env_to_dict("NVME", ["DEV_NAME"]) if "BGN" not in lnvm.keys(): cij.err("cij.lnvm.env: invalid LNVM_BGN") return 1 if "END" not in lnvm.keys(): cij.err("cij.lnvm.env: invalid LNVM_END") return 1 if "DEV_TYPE" not in lnvm.keys(): cij.err("cij.lnvm.env: invalid LNVM_DEV_TYPE") return 1 lnvm["DEV_NAME"] = "%sb%03de%03d" % (nvme["DEV_NAME"], int(lnvm["BGN"]), int(lnvm["END"])) lnvm["DEV_PATH"] = "/dev/%s" % lnvm["DEV_NAME"] cij.env_export(PREFIX, EXPORTED, lnvm) return 0
def env(): """Verify BLOCK variables and construct exported variables""" if cij.ssh.env(): cij.err("cij.block.env: invalid SSH environment") return 1 block = cij.env_to_dict(PREFIX, REQUIRED) block["DEV_PATH"] = "/dev/%s" % block["DEV_NAME"] cij.env_export(PREFIX, EXPORTED, block) return 0
def exists(): """Verify that the ENV defined NVMe device exists""" if env(): cij.err("cij.nvme.exists: Invalid NVMe ENV.") return 1 nvme = cij.env_to_dict(PREFIX, EXPORTED + REQUIRED) cmd = ["[[", "-b", nvme["DEV_PATH"], "]]"] rcode, _, _ = cij.ssh.command(cmd, shell=True, echo=False) if rcode: return False return True
def tcase_setup(trun: TestRun, parent, tcase_fname) -> TestCase: """ Create and initialize a testcase """ # pylint: disable=locally-disabled, unused-argument case = TestCase() case.fname = tcase_fname case.fpath_orig = os.path.join(trun.conf.testcases, case.fname) if not os.path.exists(case.fpath_orig): msg = ("rnr:tcase_setup: file case.fpath_orig does not exist: " "%r" % case.fpath_orig) cij.err(msg) raise InitializationError(msg)
def env(): """Verify PCI variables and construct exported variables""" if cij.ssh.env(): cij.err("cij.pci.env: invalid SSH environment") return 1 pci = cij.env_to_dict(PREFIX, REQUIRED) pci["BUS_PATH"] = "/sys/bus/pci" pci["DEV_PATH"] = os.sep.join( [pci["BUS_PATH"], "devices", pci["DEV_NAME"]]) cij.env_export(PREFIX, EXPORTED, pci) return 0
def trun_setup(conf): """ Setup the testrunner data-structure, embedding the parsed environment variables and command-line arguments and continues with setup for testplans, testsuites, and testcases """ declr = None try: with open(conf["TESTPLAN_FPATH"]) as declr_fd: declr = yaml.safe_load(declr_fd) except AttributeError as exc: cij.err("rnr: %r" % exc) if not declr: return None trun = copy.deepcopy(TRUN) trun["ver"] = cij.VERSION trun["conf"] = copy.deepcopy(conf) trun["res_root"] = conf["OUTPUT"] trun["aux_root"] = os.sep.join([trun["res_root"], "_aux"]) trun["evars"].update(copy.deepcopy(declr.get("evars", {}))) os.makedirs(trun["aux_root"]) hook_names = declr.get("hooks", []) if "lock" not in hook_names: hook_names = ["lock"] + hook_names if hook_names[0] != "lock": return None # Setup top-level hooks trun["hooks"] = hooks_setup(trun, trun, hook_names) for enum, declr in enumerate(declr["testsuites"]): # Setup testsuites tsuite = tsuite_setup(trun, declr, enum) if tsuite is None: cij.err("main::FAILED: setting up tsuite: %r" % tsuite) return 1 trun["testsuites"].append(tsuite) trun["progress"]["UNKN"] += len(tsuite["testcases"]) return trun