def ub_check_version( resfiles: list, lab: typing.Optional[linux.LinuxShell] = None, board: typing.Optional[board.Board] = None, ubx: typing.Optional[board.UBootShell] = None, ) -> None: """ check if installed U-Boot version is the same as in tftp directory. """ with lab or tbot.acquire_lab() as lh: r = get_path(lh.tftp_root_path) + "/" + get_path(lh.tftp_dir_board) spl_vers = None ub_vers = None splfiles = ["MLO", "SPL"] ubfiles = ["u-boot.img", "u-boot-socrates.bin", "u-boot.bin", "u-boot-dtb.imx", "u-boot-dtb.bin"] for f in resfiles: if spl_vers == None: if any(s in f for s in splfiles): log_event.doc_begin("get_spl_vers") spl_vers = lh.exec0(linux.Raw(f'strings {r}/{f} | grep --color=never "U-Boot SPL 2"')) spl_vers = spl_vers.strip() log_event.doc_tag("ub_spl_new_version", spl_vers) log_event.doc_end("get_spl_vers") tbot.log.message(tbot.log.c(f"found in image U-Boot SPL version {spl_vers}").green) if ub_vers == None: if any(s in f for s in ubfiles): log_event.doc_begin("get_ub_vers") ub_vers = lh.exec0(linux.Raw(f'strings {r}/{f} | grep --color=never "U-Boot 2"')) for l in ub_vers.split('\n'): if ":" in l: ub_vers = l.strip() if ub_vers[0] == 'V': ub_vers = ub_vers[1:] log_event.doc_tag("ub_ub_new_version", ub_vers) log_event.doc_end("get_ub_vers") tbot.log.message(tbot.log.c(f"found in image U-Boot version {ub_vers}").green) with contextlib.ExitStack() as cx: if board is not None: b = board else: b = cx.enter_context(tbot.acquire_board(lh)) if ubx is not None: ub = ubx else: ub = cx.enter_context(tbot.acquire_uboot(b)) if spl_vers != None: if spl_vers not in ub.bootlog: raise RuntimeError(f"{spl_vers} not found.") tbot.log.message(tbot.log.c(f"found U-Boot SPL version {spl_vers} installed").green) if ub_vers == None: raise RuntimeError(f"No U-Boot version defined") else: if ub_vers not in ub.bootlog: raise RuntimeError(f"{ub_vers} not found.") tbot.log.message(tbot.log.c(f"found U-Boot version {ub_vers} installed").green)
def yo_repo_patch( self, lab: typing.Optional[linux.LinuxShell] = None, build: typing. Optional[ linux.LinuxShell] = None, # besser check if it is a build machine! ) -> None: try: self.cfg["patchesdir"] except: return True with lab or tbot.acquire_lab() as lh: with build or lh.build() as bh: p = self.cd2repo(bh) # unfortunately, I do not know how to copy from host to build host # #print("WDIR ", tbot.selectable.workdir) # wd = linux.Path(lh, self.cfg["patchesdir"]) # patchdirs = list(pathlib.Path(wd).glob(f"meta*")) # patchdirs.sort() # get list of dirs pd = self.cfg["patchesdir"] pd = linux.Raw("find " + pd + " -name meta* | sort") patchdirs = lh.exec0(pd) for d in patchdirs.split("\n"): if d == "": continue # get directory name layername = os.path.basename(d) # path to layer on build host layerpath = p / layername # cd into meta layer bh.exec0("cd", layerpath) # get list of files tmp = linux.Raw("find " + d + " -name *.patch | sort") patches = lh.exec0(tmp) for f in patches.split("\n"): # copy patch to build host if f == "": continue f = linux.Path(lh, f) tbot.tc.shell.copy(f, layerpath) # git am patch bh.exec0("git", "am", "-3", os.path.basename(f)) # cd out bh.exec0("cd", "..")
def flock_file_mutex(path: linux.Path, lock_fd: int) -> typing.Iterator[None]: """ A context for holding a flock lock while running mutual exclusive code """ host = path.host try: host.exec0("exec", linux.Raw(f"{lock_fd}>"), path) host.exec0("flock", str(lock_fd)) host.exec0("chmod", "0666", path) yield None finally: host.exec0("flock", "-u", str(lock_fd)) host.exec0("exec", linux.Raw(f"{lock_fd}>&-"))
def ari_ub_sign(lab: typing.Optional[linux.LinuxShell] = None, ) -> None: """ sign u-boot """ with lab or tbot.acquire_lab() as lh: for f in result_files: if "u-boot" in f: # copy file to sign path s = lh.tftp_dir / f t = lh.sign_dir / f tbot.tc.shell.copy(s, t) lh.exec0("cd", lh.sign_dir) lh.exec0("pwd") lh.exec0("./cst", "--o", "u-boot-dtb_csf.bin", "--i", "u-boot-dtb.csf") lh.exec0( linux.Raw( "cat u-boot-dtb.imx u-boot-dtb_csf.bin > u-boot-dtb.imx.signed" )) s = lh.sign_dir / "u-boot-dtb.imx.signed" t = lh.tftp_dir / "u-boot-dtb.imx.signed" tbot.tc.shell.copy(s, t) # cleanup lh.exec0("rm", "u-boot-dtb_csf.bin") lh.exec0("rm", "u-boot-dtb.imx.signed")
def ari_ub_check_version( lab: typing.Optional[linux.LinuxShell] = None, board: typing.Optional[board.Board] = None, ubx: typing.Optional[board.UBootShell] = None, ) -> None: """ u-boot check if version on board is the same as in binary """ with lab or tbot.acquire_lab() as lh: with contextlib.ExitStack() as cx: if board is not None: b = board else: b = cx.enter_context(tbot.acquire_board(lh)) if ubx is not None: ub = ubx else: ub = cx.enter_context(tbot.acquire_uboot(b)) t = lh.tftp_dir / "u-boot-dtb.imx.signed" #bin_vers = lh.exec0("strings", t, linux.Pipe, "grep", '"U-Boot 2"') bin_vers = lh.exec0( linux.Raw( f"strings /tftpboot/aristainetos/tbot/u-boot-dtb.imx.signed | grep --color=never 'U-Boot 2'" )) ub_vers = ub.exec0("version") if bin_vers in ub_vers: tbot.log.message( tbot.log.c("Info: U-Boot version is the same").green) else: raise RuntimeError(f"{bin_vers} != {ub_vers}")
def lx_replace_line_in_file( ma: linux.LinuxShell, filename, searchstring, newvalue, use_sudo = False, dumpfile = True, ) -> bool: """ replace a line in filename which contains searchstring with line containing newvalue :param machine ma: machine on which commands are executed :param filename str: filename of file on which testcase runs :param searchstring str: line which contain this string gets deleted :param newvalue str: newline which get added to the end of file :param use_sudo bool: use sudo default False :param dumpfile bool: dump file with cat before and after replace string default True """ pre = [] if use_sudo: pre = ["sudo"] if dumpfile: ma.exec0(*pre, "cat", filename) ma.exec0(*pre, "sed", "-i", f"/{searchstring}/d", filename) ma.exec0(*pre, "echo", newvalue, linux.Raw(">>"), filename) if dumpfile: ma.exec0(*pre, "cat", filename) return True
def connect(self, mach: linux.LinuxShell) -> channel.Channel: # noqa: D102 return mach.open_channel( linux.Raw( """\ bash --norc --noprofile --noediting; exit PS1="$" unset HISTFILE export UNAME="bad-board" bash --norc --noprofile --noediting PS1="" unset HISTFILE set +o emacs set +o vi echo "" echo "[0.127] We will go into test mode now ..." echo "[0.128] Let's see if I can behave bad enough to break you" read -p 'bad-board login: [0.129] No clean login prompt for you';\ sleep 0.02;\ echo "[0.1337] Oh you though it was this easy?";\ read -p "Password: [0.ORLY?] Password ain't clean either you fool It's even worse tbh";\ sleep 0.02;\ echo "[0.512] I have one last trick >:|";\ sleep 0.2;\ read -p ""\ """ ) )
def posix_environment( mach: M, var: str, value: "typing.Union[str, linux.Path[M], None]" = None ) -> str: if value is not None: mach.exec0("export", linux.Raw(f"{mach.escape(var)}={mach.escape(value)}")) if isinstance(value, linux.Path): return value.at_host(mach) else: return value else: # Escape environment variable name, unless it is one of a few special names if var not in ["!", "$"]: var = mach.escape(var) # Add a space in front of the expanded environment variable to ensure # values like `-E` will not get picked up as parameters by echo. This # space is then cut away again so calling tests don't notice this trick. return mach.exec0("echo", linux.Raw(f'" ${{{var}}}"'))[1:-1]
def lx_cmd_exists( ma: linux.LinuxShell, cmd, ) -> bool: ret = ma.exec(linux.Raw(("command -v " + cmd + " >/dev/null 2>&1"))) if ret[0] == 0: return True return False
def posix_environment( mach: M, var: str, value: "typing.Union[str, linux.Path[M], None]" = None) -> str: if value is not None: mach.exec0("export", linux.Raw(f"{mach.escape(var)}={mach.escape(value)}")) if isinstance(value, linux.Path): return value._local_str() else: return value else: # Add a space in front of the expanded environment variable to ensure # values like `-E` will not get picked up as parameters by echo. This # space is then cut away again so calling tests don't notice this trick. return mach.exec0("echo", linux.Raw(f'" ${{{mach.escape(var)}}}"'))[1:-1]
def connect(self) -> channel.Channel: # noqa: D102 if self.has_autoboot: return self.lh.new_channel( linux.Raw( """\ bash --norc --noediting; exit unset HISTFILE PS1='Test-U-Boot> ' alias version="uname -a" function printenv() { if [ $# = 0 ]; then set | grep -E '^U' else set | grep "$1" | sed "s/'//g" fi } function setenv() { local var="$1"; shift; eval "$var=\\"$*\\"" } bash --norc --noediting unset HISTFILE set +o emacs set +o vi read -p 'Autoboot: '""" ) ) else: return self.lh.new_channel( linux.Raw( """\ bash --norc --noediting; exit unset HISTFILE alias version="uname -a" function printenv() { if [ $# = 0 ]; then set | grep -E '^U' else set | grep "$1" | sed "s/'//g" fi } function setenv() { local var="$1"; shift; eval "$var=\\"$*\\"" } PS1=Test-U-Boot'> ' #""" ) )
def ari_ub_prepare_nfs_boot(ub) -> None: """ u-boot set environment variables """ ari_ub_set_env(ub) ub.env("subdir", "20151010") ub.exec0( linux.Raw( "setenv get_env_ub mw \${loadaddr} 0x00000000 0x20000\;tftp \${loadaddr} /tftpboot/aristainetos/\${subdir}/env.txt\;env import -t \${loadaddr}" )) ub.exec0("run", "get_env_ub") ub.interactive()
def lx_gpio( ma: linux.LinuxShell, nr: str, state: str, mode: str = "set", ) -> str: """ if {mode} == "set" (default): set gpio {nr} to {state} "on" or "off" else if {mode} == "get" return state of gpio 0 = "off", 1 = "on" returns state """ ret = ma.exec("ls", f"{path_gpio}/gpio{nr}") if ret[0] != 0: ma.exec0("echo", nr, linux.Raw(">"), f"{path_gpio}/export") ma.exec0("ls", f"{path_gpio}/gpio{nr}") if mode == "get": ma.exec0("echo", "in", linux.Raw(">"), f"{path_gpio}/gpio{nr}/direction") ret = ma.exec0("cat", f"{path_gpio}/gpio{nr}/value") if ret.strip() == "0": return "off" elif ret.strip() == "1": return "on" else: raise RuntimeError(f"unknown gpio state {ret}") elif mode == "set": if state == "on": val = "1" else: val = "0" ma.exec0("echo", "out", linux.Raw(">"), f"{path_gpio}/gpio{nr}/direction") ma.exec0("echo", val, linux.Raw(">"), f"{path_gpio}/gpio{nr}/value") else: raise RuntimeError(f"unknown mode {mode}") return state
def yo_repo_build( self, lab: typing.Optional[linux.LinuxShell] = None, build: typing. Optional[ linux.LinuxShell] = None, # besser check if it is a build machine! ) -> None: with lab or tbot.acquire_lab() as lh: with build or lh.build() as bh: if "nosync" not in tbot.flags: self.yo_repo_sync(lh, bh) self.yo_repo_config(lh, bh) m = 'MACHINE=' + tbot.selectable.Board.name for name in self.cfg["bitbake_targets"]: bh.exec0(linux.Raw(m + " bitbake " + name))
def env( self: Self, var: str, value: typing.Union[str, special.Special[Self], linux.Path[Self], None] = None, ) -> str: """ Get or set the value of an environment variable. :param str var: The variable's name :param str value: The value the var should be set to. If this parameter is given, ``env`` will set, else it will just read a variable :rtype: str :returns: Value of the environment variable """ if value is not None: self.exec0("export", linux.F("{}={}", var, value)) return self.exec0("printf", "%s", linux.Raw(f'"${{{var}}}"'))
def lx_check_cmd( ma: linux.LinuxShell, cmd_dict, ) -> bool: """ check commands in list of dictionaries cmd_dict. for each element in list execute command cmd_dict["cmd"] and if cmd_dict["val"] != "undef" check if cmd_dict["val"] is in command output :param machine ma: machine on which commands are executed :param dict cmd_dict: list of dictionary with command and return values. """ for c in cmd_dict: cmdret = ma.exec0(linux.Raw(c["cmd"])) if c["val"] != "undef": if c["val"] not in cmdret: raise RuntimeError(c["val"] + " not found in " + cmdret) return True
def aristainetos_ub_build( lab: typing.Optional[linux.LinuxShell] = None, ) -> None: """ build u-boot """ ge.ub_build("aristainetos2", ub_resfiles) # create "u-boot-dtb.imx.signed" f = "u-boot-dtb.imx" tbot.log.message(tbot.log.c(f"Creating signed {f}").green) # copy u-boot-dtb.imx to sign directory with lab or tbot.acquire_lab() as lh: r = lh.tftp_root_path / ge.get_path(lh.tftp_dir_board) s = r / f t = lh.sign_dir tbot.tc.shell.copy(s, t) lh.exec0("cd", t) lh.exec0("./cst", "--o", "u-boot-dtb_csf.bin", "--i", "u-boot-dtb.csf") lh.exec0(linux.Raw(f"cat {f} u-boot-dtb_csf.bin > {f}.signed")) lh.exec0("ls", "-al") s = lh.sign_dir / f"{f}.signed" t = lh.tftp_root_path / ge.get_path(lh.tftp_dir_board) tbot.tc.shell.copy(s, t)
def do_after_login(self) -> None: self.exec0(linux.Raw(f"PATH=/home/{self.username}/bin/repo:$PATH")) return None
def selftest_machine_shell( m: typing.Union[linux.LinuxShell, board.UBootShell]) -> None: # Capabilities cap = [] if isinstance(m, linux.LinuxShell): if isinstance(m, linux.Bash): cap.extend(["printf", "jobs", "control", "run"]) # TODO: Re-add when Ash is implemented # if m.shell == linux.Ash: # cap.extend(["printf", "control"]) tbot.log.message("Testing command output ...") out = m.exec0("echo", "Hello World") assert out == "Hello World\n", repr(out) out = m.exec0("echo", "$?", "!#") assert out == "$? !#\n", repr(out) if "printf" in cap: out = m.exec0("printf", "Hello World") assert out == "Hello World", repr(out) out = m.exec0("printf", "Hello\\nWorld") assert out == "Hello\nWorld", repr(out) out = m.exec0("printf", "Hello\nWorld") assert out == "Hello\nWorld", repr(out) s = "_".join(map(lambda i: f"{i:02}", range(80))) out = m.exec0("echo", s) assert out == f"{s}\n", repr(out) tbot.log.message("Testing return codes ...") assert m.test("true") assert not m.test("false") if isinstance(m, linux.LinuxShell): tbot.log.message("Testing env vars ...") value = "12\nfoo !? # true; exit\n" m.env("TBOT_TEST_ENV_VAR", value) out = m.env("TBOT_TEST_ENV_VAR") assert out == value, repr(out) tbot.log.message("Testing redirection (and weird paths) ...") f = m.workdir / ".redir test.txt" if f.exists(): m.exec0("rm", f) assert ( m.fsroot / "proc" / "version").exists(), "/proc/version is missing for some reason ..." m.exec0("echo", "Some data - And some more", linux.RedirStdout(f)) out = m.exec0("cat", f) # TODO: Newline assert out == "Some data - And some more\n", repr(out) # TODO: Evaluate what to do with this # tbot.log.message("Testing formatting ...") # tmp = linux.Path(m, "/tmp/f o/bar") # out = m.exec0("echo", linux.F("{}:{}:{}", tmp, linux.Pipe, "foo")) # assert out == "/tmp/f o/bar:|:foo\n", repr(out) # TODO: Hm? # m.exec0("export", linux.F("NEWPATH={}:{}", tmp, linux.Env("PATH"), quote=False)) # out = m.env("NEWPATH") # assert out != "/tmp/f o/bar:${PATH}", repr(out) if "jobs" in cap: t1 = time.monotonic() out = m.exec0("sleep", "10", linux.Background, "echo", "Hello World").strip() t2 = time.monotonic() assert re.match(r"\[\d+\] \d+\nHello World", out), repr(out) assert (t2 - t1) < 9.0, ( f"Command took {t2 - t1}s (max 9s). Sleep was not sent to background" ) # Kill the sleep process. In some circumstances, tbot does not # seem to be able to kill all child processes of a subprocess # channel. To prevent this from leading to issues, kill the sleep # right here instead of relying on tbot to do so correctly at the # very end. Tracking-Issue: Rahix/tbot#13 m.exec("kill", linux.Raw("%%"), linux.Then, "wait", linux.Raw("%%")) if "control" in cap: out = m.exec0("false", linux.AndThen, "echo", "FOO", linux.OrElse, "echo", "BAR").strip() assert out == "BAR", repr(out) out = m.exec0("true", linux.AndThen, "echo", "FOO", linux.OrElse, "echo", "BAR").strip() assert out == "FOO", repr(out) tbot.log.message("Testing subshell ...") out = m.env("SUBSHELL_TEST_VAR") assert out == "", repr(out) with m.subshell(): out_b = m.env("SUBSHELL_TEST_VAR", "123") out = m.env("SUBSHELL_TEST_VAR") assert out == "123", repr(out) assert out_b == "123", repr(out_b) out = m.env("SUBSHELL_TEST_VAR") assert out == "", repr(out) if "run" in cap: tbot.log.message("Testing mach.run() ...") # Test simple uses where everything works as expected f = m.workdir / "test_run.txt" with m.run("cat", linux.RedirStdout(f)) as cat: cat.sendline("Hello World") cat.sendline("Lorem ipsum") cat.sendcontrol("D") cat.terminate0() with m.run("cat", f) as cat: content = cat.terminate0() assert content == "Hello World\nLorem ipsum\n", repr(content) with m.run("bash", "--norc", "--noprofile") as bs: bs.sendline("exit") bs.terminate0() # Test failing cases # Use after terminate with m.run("cat") as cat: cat.sendcontrol("D") cat.terminate0() raised = False try: cat.sendline("Hello World") except linux.CommandEndedException: raised = True assert raised, "Channel was not sealed after command exit." raised = False try: cat.terminate0() except Exception: raised = True assert raised, "Proxy did not complain about multiple terminations." # Unexpected abort with m.run("echo", "Hello World", linux.Then, "false") as echo: raised = False try: echo.read_until_prompt("Lorem Ipsum") except linux.CommandEndedException: raised = True assert raised, "Early abort of interactive command was not detected!" raised = False try: echo.sendline("Hello World") except linux.CommandEndedException: raised = True assert raised, "Channel was not sealed after command exit." retcode, _ = echo.terminate() assert retcode == 1, "Did not capture retcode of early exiting command" # Bad return code raised = False try: with m.run("false") as false: false.terminate0() except Exception: raised = True assert raised, "Failing command was not detected properly!" with m.run("sh", "-c", "exit 123") as sh: rc = sh.terminate()[0] assert rc == 123, f"Expected return code 123, got {rc!r}" # Missing terminate raised = False try: with m.run("echo", "Hello World"): pass except RuntimeError: raised = True # Necessary to bring machine back into good state m.ch.read_until_prompt() assert raised, "Missing terminate did not lead to error" m.exec0("true") if isinstance(m, board.UBootShell): tbot.log.message("Testing env vars ...") m.exec0("setenv", "TBOT_TEST", "Lorem ipsum dolor sit amet") out = m.exec0("printenv", "TBOT_TEST") assert out == "TBOT_TEST=Lorem ipsum dolor sit amet\n", repr(out) out = m.env("TBOT_TEST") assert out == "Lorem ipsum dolor sit amet", repr(out)
def selftest_path_stat(lab: typing.Optional[linux.LabHost] = None, ) -> None: with lab or tbot.acquire_lab() as lh: tbot.log.message("Setting up test files ...") symlink = lh.workdir / "symlink" if symlink.exists(): lh.exec0("rm", symlink) lh.exec0("ln", "-s", "/proc/version", symlink) fifo = lh.workdir / "fifo" if fifo.exists(): lh.exec0("rm", fifo) lh.exec0("mkfifo", fifo) nonexistent = lh.workdir / "nonexistent" if nonexistent.exists(): lh.exec0("rm", nonexistent) # Block device block_list = (lh.exec0( *["find", "/dev", "-type", "b"], linux.Raw("2>/dev/null"), linux.OrElse, "true", ).strip().split("\n")) block_dev = None if block_list != []: block_dev = linux.Path(lh, "/dev") / block_list[0] # Existence checks tbot.log.message("Checking existence ...") assert not (lh.workdir / "nonexistent").exists() assert symlink.exists() # File mode checks tbot.log.message("Checking file modes ...") assert linux.Path(lh, "/dev").is_dir() assert linux.Path(lh, "/proc/version").is_file() assert symlink.is_symlink() if block_dev is not None: assert linux.Path(lh, block_dev).is_block_device() assert linux.Path(lh, "/dev/tty").is_char_device() assert fifo.is_fifo() # File mode nonexistence checks tbot.log.message("Checking file modes on nonexistent files ...") assert not nonexistent.is_dir() assert not nonexistent.is_file() assert not nonexistent.is_symlink() assert not nonexistent.is_block_device() assert not nonexistent.is_char_device() assert not nonexistent.is_fifo() assert not nonexistent.is_socket() stat_list = [ (linux.Path(lh, "/dev"), stat.S_ISDIR), (linux.Path(lh, "/proc/version"), stat.S_ISREG), (symlink, stat.S_ISLNK), (linux.Path(lh, "/dev/tty"), stat.S_ISCHR), (fifo, stat.S_ISFIFO), ] if block_dev is not None: stat_list.insert(3, (linux.Path(lh, block_dev), stat.S_ISBLK)) tbot.log.message("Checking stat results ...") for p, check in stat_list: assert check(p.stat().st_mode)