def git_prepare(lab: linux.Lab) -> str: """Prepare a test git repo.""" global _GIT if _GIT is None: # Git committer and author information in case the user's git # environment is not set up yet lab.env("GIT_AUTHOR_NAME", "tbot selftest") lab.env("GIT_AUTHOR_EMAIL", "*****@*****.**") lab.env("GIT_COMMITTER_NAME", "tbot selftest") lab.env("GIT_COMMITTER_EMAIL", "*****@*****.**") p = lab.workdir / "selftest-git-remote" if p.exists(): lab.exec0("rm", "-rf", p) tbot.log.message("Setting up test repo ...") lab.exec0("mkdir", "-p", p) lab.exec0("git", "-C", p, "init") repo = git.GitRepository(p, clean=False) lab.exec0( "echo", """\ # tbot Selftest This repo exists to test tbot's git testcase. You can safely remove it, but please **do not** modify it as that might break the tests.""", linux.RedirStdout(repo / "README.md"), ) repo.add(repo / "README.md") repo.commit("Initial", author="tbot Selftest <none@none>") tbot.log.message("Creating test patch ...") lab.exec0( "echo", """\ # File 2 A second file that will have been added by patching.""", linux.RedirStdout(repo / "file2.md"), ) repo.add(repo / "file2.md") repo.commit("Add file2", author="tbot Selftest <none@none>") patch_name = repo.git0("format-patch", "HEAD~1").strip() lab.exec0("mv", repo / patch_name, lab.workdir / "selftest-git.patch") tbot.log.message("Resetting repo ...") repo.reset("HEAD~1", git.ResetMode.HARD) _GIT = p._local_str() return _GIT else: return _GIT
def selftest_path_integrity( lab: typing.Optional[selftest.SelftestHost] = None) -> None: """Test if using a path on the wrong host fails.""" with lab or selftest.SelftestHost() as lh: p = lh.workdir / "folder" / "file.txt" with tbot.acquire_lab() as lh2: raised = False try: # mypy detects that this is wrong lh2.exec0("echo", p) # type: ignore except tbot.error.WrongHostError: raised = True assert raised # It is ok to clone a machine and reuse the path with lh.clone() as lh3: lh3.exec0("echo", p) lh.exec0("mkdir", "-p", p.parent) assert p.parent.is_dir() lh.exec0("uname", "-a", linux.RedirStdout(p)) assert p.is_file() lh.exec0("rm", "-r", p.parent) assert not p.exists() assert not p.parent.exists()
def do_test(a: linux.Path, b: linux.Path, msg: str) -> None: if b.exists(): b.host.exec0("rm", b) a.host.exec0("echo", msg, linux.RedirStdout(a)) shell.copy(a, b) out = b.host.exec0("cat", b).strip() assert out == msg, repr(out) + " != " + repr(msg)
def selftest_tc_kconfig(lab: typing.Optional[linux.Lab] = None) -> None: """Test kconig setting.""" with lab or tbot.acquire_lab() as lh: conf = lh.workdir / "selftest-kconfig" for i in range(4): lh.exec0( "echo", """\ # tbot-selftest kconfig file # DO NOT EDIT! (Deleting is ok, though) CONFIG_FOO=y CONFIG_BAR=m # CONFIG_BAZ is not set CONFIG_STRING="a happy string" CONFIG_HEX=0xC0FFEE""", linux.RedirStdout(conf), ) if i == 0: tbot.log.message("Enabling all ...") kconfig.enable(conf, "CONFIG_FOO") kconfig.enable(conf, "CONFIG_BAR") kconfig.enable(conf, "CONFIG_BAZ") assert (lh.exec0("grep", "-c", "-E", "CONFIG_(FOO|BAR|BAZ)=y", conf).strip() == "3") elif i == 1: tbot.log.message("Disabling all ...") kconfig.disable(conf, "CONFIG_FOO") kconfig.disable(conf, "CONFIG_BAR") kconfig.disable(conf, "CONFIG_BAZ") assert (lh.exec0("grep", "-c", "-E", "# CONFIG_(FOO|BAR|BAZ)", conf).strip() == "3") assert (lh.exec("grep", "-c", "-E", "^CONFIG_(FOO|BAR|BAZ)", conf)[1].strip() == "0") elif i == 2: tbot.log.message("Moduling all ...") kconfig.module(conf, "CONFIG_FOO") kconfig.module(conf, "CONFIG_BAR") kconfig.module(conf, "CONFIG_BAZ") assert (lh.exec0("grep", "-c", "-E", "CONFIG_(FOO|BAR|BAZ)=m", conf).strip() == "3") elif i == 3: tbot.log.message("Testing values ...") kconfig.set_string_value(conf, "CONFIG_STRING", "abcdef") kconfig.set_hex_value(conf, "CONFIG_HEX", 0xDEADBEEF) assert (lh.exec0("grep", "-c", 'CONFIG_STRING="abcdef"', conf).strip() == "1") assert (lh.exec0("grep", "-c", "CONFIG_HEX=0xdeadbeef", conf).strip() == "1")
def test_redirection_stdout(any_linux_shell: AnyLinuxShell) -> None: with any_linux_shell() as linux_shell: f = linux_shell.workdir / ".redir test.txt" if f.exists(): linux_shell.exec0("rm", f) linux_shell.exec0("echo", "Some data - And some more", linux.RedirStdout(f)) out = f.read_text() assert out == "Some data - And some more\n" linux_shell.exec0("echo", "new data", linux.RedirStdout(f)) out = f.read_text() assert out == "new data\n" linux_shell.exec0("echo", "appended data", linux.AppendStdout(f)) out = f.read_text() assert out == "new data\nappended data\n"
def selftest_tc_git_apply( lab: typing.Optional[selftest.SelftestHost] = None) -> None: """Test applying patches.""" with lab or selftest.SelftestHost() as lh: remote = git_prepare(lh) target = lh.workdir / "selftest-git-apply" if target.exists(): lh.exec0("rm", "-rf", target) tbot.log.message("Cloning repo ...") repo = git.GitRepository(target, remote) assert (repo / "README.md").is_file() assert not (repo / "file2.md").is_file() tbot.log.message("Apply patch ...") repo.apply(lh.workdir / "selftest-git.patch") assert (repo / "file2.md").is_file() repo.add(repo / "file2.md") repo.commit("Add file2 from patch", author="tbot Selftest <none@none>") lh.exec0( "echo", """\ # File 2 A second file that will have been added by patching. ## 2.2 This section was added by a second patch""", linux.RedirStdout(repo / "file2.md"), ) repo.add(repo / "file2.md") repo.commit("Update file2", author="tbot Selftest <none@none>") patch_dir = lh.workdir / "selftest-git-patches" lh.exec0("mkdir", "-p", patch_dir) repo.git0("format-patch", "-o", patch_dir, "HEAD~2") repo.reset("HEAD~2", git.ResetMode.HARD) assert not (repo / "file2.md").is_file() tbot.log.message("Apply multiple patches ...") repo.apply(patch_dir) assert lh.test("grep", "2.2", repo / "file2.md") lh.exec0("rm", "-rf", target) lh.exec0("rm", "-rf", patch_dir)
def selftest_tc_git_checkout( lab: typing.Optional[selftest.SelftestHost] = None, ) -> None: """Test checking out a repository.""" with lab or selftest.SelftestHost() as lh: remote = git_prepare(lh) target = lh.workdir / "selftest-git-checkout" if target.exists(): lh.exec0("rm", "-rf", target) tbot.log.message("Cloning repo ...") repo = git.GitRepository(target, remote) assert (repo / "README.md").is_file() assert not (repo / "file2.md").is_file() tbot.log.message("Make repo dirty ...") lh.exec0("echo", "Test 123", linux.RedirStdout(repo / "file.txt")) repo = git.GitRepository(target, remote, clean=False) assert (repo / "file.txt").is_file() repo = git.GitRepository(target, remote, clean=True) assert not (repo / "file.txt").is_file() tbot.log.message("Add dirty commit ...") lh.exec0("echo", "Test 123", linux.RedirStdout(repo / "file.txt")) repo.add(repo / "file.txt") repo.commit("Add file.txt", author="tbot Selftest <none@none>") repo = git.GitRepository(target, remote, clean=False) assert (repo / "file.txt").is_file() repo = git.GitRepository(target, remote, clean=True) assert not (repo / "file.txt").is_file() lh.exec0("rm", "-rf", target)
def test_run_working_text(any_linux_shell: AnyLinuxShell) -> None: with any_linux_shell() as linux_shell: f = linux_shell.workdir / "test_run.txt" with linux_shell.run("cat", linux.RedirStdout(f)) as cat: cat.sendline("Hello World") cat.sendline("Lorem ipsum") cat.sendcontrol("D") cat.terminate0() with linux_shell.run("cat", f) as cat: content = cat.terminate0() assert content == "Hello World\nLorem ipsum\n"
def test_redirection_mixed(any_linux_shell: AnyLinuxShell) -> None: with any_linux_shell() as linux_shell: f = linux_shell.workdir / ".redir test.txt" if f.exists(): linux_shell.exec0("rm", f) res = linux_shell.exec0( "python3", "-c", "import sys; print('hello', flush=True); print('error', file=sys.stderr)", linux.RedirStdout(f), ) assert res == "error\n" out = f.read_text() assert out == "hello\n" res = linux_shell.exec0( "python3", "-c", "import sys; print('hello', flush=True); print('error', file=sys.stderr)", linux.RedirStderr(f), ) assert res == "hello\n" out = f.read_text() assert out == "error\n" res = linux_shell.exec0( "python3", "-c", "import sys; print('hello', flush=True); print('error', file=sys.stderr)", linux.AppendStdout(f), ) assert res == "error\n" out = f.read_text() assert out == "error\nhello\n" res = linux_shell.exec0( "python3", "-c", "import sys; print('hello', flush=True); print('error', file=sys.stderr)", linux.AppendStderr(f), ) assert res == "hello\n" out = f.read_text() assert out == "error\nhello\nerror\n"
def git_increment_commits(repo: git.GitRepository) -> str: counter = repo / "counter.txt" for i in range(0, 24): tbot.log.message(f"Create commit ({i+1:2}/24) ...") repo.host.exec0("echo", str(i), linux.RedirStdout(counter)) repo.add(counter) repo.commit(f"Set counter to {i}", author="tbot Selftest <none@none>") if i == 0: # Take the first commit with counter as good rev = repo.head return rev
def selftest_path_integrity(lab: typing.Optional[linux.Lab] = None, ) -> None: """Test if using a path on the wrong host fails.""" with lab or tbot.acquire_lab() as lh: p = lh.workdir / "folder" / "file.txt" with tbot.acquire_lab() as lh2: raised = False try: # mypy detects that this is wrong lh2.exec0("echo", p) # type: ignore # TODO: Proper exception type except: # noqa: E722 raised = True assert raised lh.exec0("mkdir", "-p", p.parent) assert p.parent.is_dir() lh.exec0("uname", "-a", linux.RedirStdout(p)) assert p.is_file() lh.exec0("rm", "-r", p.parent) assert not p.exists() assert not p.parent.exists()
def invalid_path() -> None: mach = machine.DummyMach() # should fail! path.Path(mach, "/tmp") mach_lnx = machine.DummyLinuxMach() p2 = path.Path(mach_lnx, "/tmp") # should fail! annotated(p2) mach2 = machine.DummyLinuxMach2() p3 = path.Path(mach2, "/tmp") annotated(p3) # should fail! mach_lnx.exec0("cat", p3) # should fail! mach_lnx.exec0("echo", linux.RedirStdout(p3 / "file")) # should fail! mach2.exec0("echo", linux.RedirStderr(p2 / "file2"))
def _uboot_prepare(h: linux.LinuxShell) -> uboot.UBootBuilder: remote = h.workdir / "selftest-ub-remote" if remote.exists(): h.exec0("rm", "-rf", remote) h.exec0("mkdir", remote) h.exec0("git", "-C", remote, "init") repo = git.GitRepository(target=remote, clean=False) makefile = """\ all: \t@echo "Making all ..." \ttest ${CC} = "dummy-none-gcc" \texit 1 defconfig: \t@echo "Configuring ..." \ttouch .config mrproper: \t@echo "Cleaning ..." \trm -f .config \ttouch .cleaned .PHONY: all defconfig mrproper """ h.exec0("echo", makefile, linux.RedirStdout(repo / "Makefile")) repo.add(repo / "Makefile") repo.commit("U-Boot Dummy", author="tbot selftest <tbot@tbot>") # Create Patch patch = """\ From 1d78601502661ae531b00540bf86e145a317f23f Mon Sep 17 00:00:00 2001 From: tbot Selftest <none@none> Date: Wed, 30 Jan 2019 13:31:12 +0100 Subject: [PATCH] Fix Makefile --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index b5319d7..0f01838 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,6 @@ all: \t@echo "Making all ..." \ttest ${CC} = "dummy-none-gcc" -\texit 1 \n defconfig: \t@echo "Configuring ..." -- \n2.20.1 """ patchfile = h.workdir / "uboot-selftest.patch" h.exec0("echo", patch, linux.RedirStdout(patchfile)) class UBootBuilder(uboot.UBootBuilder): name = "tbot-selftest" remote = repo._local_str() defconfig = "defconfig" toolchain = "selftest-toolchain" def do_patch(self, repo: git.GitRepository) -> None: patch = repo.host.workdir / "uboot-selftest.patch" repo.am(patch) return UBootBuilder()
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", "infinity", linux.Background, "echo", "Hello World").strip() t2 = time.monotonic() pid = m.env("!") tbot.log.message(pid) 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", pid, linux.Then, "wait", pid) f1 = m.workdir / "bg1.txt" f2 = m.workdir / "bg2.txt" out = m.exec0( "echo", "foo", linux.Background(stdout=f1), "echo", "bar", linux.Background(stdout=f2, stderr=f2), "wait", ) out = f1.read_text().strip() assert out == "foo", repr(out) out = f2.read_text().strip() assert out == "bar", repr(out) 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_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"]) # 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" ) 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 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 prepare(h: linux.LinuxShell) -> None: h.exec0( "echo", "export CC=dummy-none-gcc", linux.RedirStdout(h.workdir / ".selftest-toolchain.sh"), )