def Logs(): """ClickHouse and ODBC driver logs context manager. """ class _Logs: def __init__(self, *args): self.logs = args def read(self, timeout=None): for l in self.logs: l.readlines(timeout=timeout) if not settings.debug: yield None else: with Shell(name="clickhouse-server.log") as bash0, \ Shell(name="odbc-driver-trace.log") as bash1, \ Shell(name="odbc-driver-w-trace.log") as bash2, \ Shell(name="odbc-manager-trace.log") as bash3: bash1(f"touch {odbc_driver_trace_log_path}") bash2(f"touch {odbc_driver_w_trace_log_path}") bash3(f"touch {odbc_manager_trace_log_path}") with bash0(f"tail -f {clickhouse_log_path}", asyncronous=True, name="") as clickhouse_log, \ bash1(f"tail -f {odbc_driver_trace_log_path}", asyncronous=True, name="") as odbc_driver_log, \ bash2(f"tail -f {odbc_driver_w_trace_log_path}", asyncronous=True, name="") as odbc_driver_w_log, \ bash3(f"tail -f {odbc_manager_trace_log_path}", asyncronous=True, name="") as odbc_manager_log: logs = _Logs(clickhouse_log, odbc_driver_log, odbc_driver_w_log, odbc_manager_log) logs.read() yield logs
def shell(self, node): """Returns unique shell terminal to be used. """ if node is None: return Shell() return Shell(command=[ "/bin/bash", "--noediting", "-c", f"{self.docker_compose} exec {node} bash --noediting" ], name=node)
def check(command): with Shell(command=command, name=" ".join(command), new_prompt="terminal# ") as bash: for i in range(2048): c = bash(f"echo \"{'a'*i}\"") assert c.output == f"{'a'*i}", error()
def regression(self): """The `ls` utility regression module. """ with Shell() as shell: self.context.shell = shell Scenario(run=list_current_working_directory)
def bash(self, node, timeout=120): """Returns thread-local bash terminal to a specific node. :param node: name of the service """ current_thread = threading.current_thread() id = f"{current_thread.ident}-{node}" with self.lock: if self._bash.get(id) is None: if node is None: self._bash[id] = Shell().__enter__() else: self._bash[id] = Shell(command=[ "/bin/bash", "--noediting", "-c", f"{self.docker_compose} exec {node} bash --noediting" ], name=node).__enter__() self._bash[id].timeout = timeout return self._bash[id]
def bash(self, node, timeout=300, command="bash --noediting"): """Returns thread-local bash terminal to a specific node. :param node: name of the service """ test = current() if self.terminating: if test and (test.cflags & MANDATORY): pass else: raise InterruptedError("terminating") current_thread = threading.current_thread() id = f"{current_thread.name}-{node}" with self.lock: if self._bash.get(id) is None: if node is None: self._bash[id] = Shell().__enter__() else: self._bash[id] = Shell(command=[ "/bin/bash", "--noediting", "-c", f"{self.docker_compose} exec {node} {command}" ], name=node).__enter__() self._bash[id].timeout = timeout # clean up any stale open shells for threads that have exited active_thread_names = { thread.name for thread in threading.enumerate() } for bash_id in list(self._bash.keys()): thread_name, node_name = bash_id.rsplit("-", 1) if thread_name not in active_thread_names: self._bash[bash_id].__exit__(None, None, None) del self._bash[bash_id] return self._bash[id]
def check(command): with Shell(command=command, name=" ".join(command), new_prompt="terminal# ") as bash: for i in range(2048): cmd = f"echo \"{'a'*i}\"" bash.expect(bash.prompt) bash.send(cmd) bash.expect(re.escape(cmd)) bash.expect(bash.prompt) bash.send("\r", eol="")
import json import os import time from testflows.core import * from testflows.asserts import error from testflows.connect import Shell import e2e.settings as settings import e2e.yaml_manifest as yaml_manifest import e2e.util as util current_dir = os.path.dirname(os.path.abspath(__file__)) max_retries = 20 shell = Shell() shell.timeout = 300 namespace = settings.test_namespace kubectl_cmd = settings.kubectl_cmd def launch(command, ok_to_fail=False, ns=namespace, timeout=600): # Build command cmd = f"{kubectl_cmd} " cmd_args = command.split(" ") if ns is not None and ns != "" and ns != "--all-namespaces": cmd += f"{cmd_args[0]} --namespace={ns} " elif ns == "--all-namespaces": cmd += f"{cmd_args[0]} {ns} " else: cmd += f"{cmd_args[0]} "
import json import os import time import yaml from testflows.core import TestScenario, Name, When, Then, Given, And, main, run, Module from testflows.asserts import error from testflows.connect import Shell current_dir = os.path.dirname(os.path.abspath(__file__)) max_retries=10 shell = Shell() namespace = "test" def get_full_path(test_file): return os.path.join(current_dir, f"{test_file}") def get_ch_version(test_file): return yaml.safe_load(open(get_full_path(test_file),"r"))["spec"]["templates"]["podTemplates"][0]["spec"]["containers"][0]["image"] def get_chi_name(path): return yaml.safe_load(open(path,"r"))["metadata"]["name"] def kube_delete_chi(chi, ns = namespace): shell(f"kubectl delete chi {chi} -n {ns}", timeout = 60) kube_wait_objects(chi, [0,0,0], ns) def create_and_check(test_file, checks, ns = namespace): config=get_full_path(test_file)
def shell(self): """Suite of Shell tests. """ stress_count = self.context.stress_count with Given("import"): from testflows.connect import Shell with Test("open"): with Shell() as bash: pass with Test("execute command"): with Shell() as bash: bash("ls -la") with Test("custom shell name"): with Shell(name="shell") as shell: shell("ls -la") with Test("execute command with custom name"): with Shell() as bash: bash("ls -la", name="ls") with Test("execute multiple commands"): with Shell() as bash: bash("echo Hello World") bash("ls -la") bash("echo Bye World") with Test("execute command with utf-8"): with Shell() as bash: bash("echo Gãńdåłf_Thê_Gręât") with Test("share the same shell between different tests"): with Shell() as bash: with Step("first test"): bash("echo Hello World") with Step("second test"): bash("ls -la") with Step("third test"): bash("echo Bye World") with Test("check command output"): with Shell() as bash: with Step("one line output"): assert bash( "echo Hello World").output == "Hello World", error() with Step("empty output"): assert bash("echo ").output == "", error() with Step("multi line output"): text = "line1\\nline2" with values() as that: assert that( bash(f"echo -e \"{text}\"").output) == text.replace( "\\n", "\n"), error() with Test("check command exitcode"): with Shell() as bash: with Step("exit code 0"): assert bash("ls -la").exitcode == 0, error() with Step("exit code 2"): assert bash("ls /foo__").exitcode == 2, error() with Test("check timeout"): with Shell() as bash: bash.timeout = 6 with Step("timeout 1 sec"): bash("echo hello; sleep 0.75; " * 5) with Test("async command"): with Shell() as bash: with bash("tail -f /proc/cpuinfo", asyncronous=True) as tail: tail.readlines() with Test("async command with custom name"): with Shell() as bash: with bash("tail -f /proc/cpuinfo", asyncronous=True, name="cpuinfo") as tail: tail.readlines() with Test("check double prompts before command"): with Shell() as bash: bash.send("") bash("ls") with Test("check double prompts after command"): with Shell() as bash: for i in range(100): bash.send("") bash("ls\r\n") bash("ls; echo -e 'bash# \nbash# '") with Test("check empty lines before command"): with Shell() as bash: for i in range(stress_count): bash("\n\n\necho \"foo\"") with Test("check empty lines after command"): with Shell() as bash: for i in range(stress_count): bash("echo \"foo\"\n\n\n") with Test("check empty lines between commands"): with Shell() as bash: bash.timeout = 1 with raises(ExpectTimeoutError): bash("echo \"foo\"\n\n\necho\"foo\"") with Test("check empty lines before and after command"): with Shell() as bash: for i in range(stress_count): bash("\n\n\necho \"foo\"\n\n\n") with Test("check multiline command"): with Shell() as bash: for i in range(stress_count): bash("cat << HEREDOC > foo\nline 1\nline 2\nline 3\nHEREDOC") with Test("check matching long command (manual)"): def check(command): with Shell(command=command, name=" ".join(command), new_prompt="terminal# ") as bash: for i in range(2048): cmd = f"echo \"{'a'*i}\"" bash.expect(bash.prompt) bash.send(cmd) bash.expect(re.escape(cmd)) bash.expect(bash.prompt) bash.send("\r", eol="") with Example("sh"): check(["/bin/sh"]) with Example("bash --noediting"): check(["/bin/bash", "--noediting"]) with Example("bash"): check(["/bin/bash"]) with Test("check matching long command"): def check(command): with Shell(command=command, name=" ".join(command), new_prompt="terminal# ") as bash: for i in range(2048): c = bash(f"echo \"{'a'*i}\"") assert c.output == f"{'a'*i}", error() with Example("sh"): check(["/bin/sh"]) with Example("bash --noediting"): check(["/bin/bash", "--noediting"]) with Example("bash"): check(["/bin/bash"]) with Test("check multiline command with long lines"): with Shell() as bash: cmd = ( "cat << HEREDOC > foo\n" "'111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', '22222222222222222'\n" "'22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222', '33333333333333333'\n" "HEREDOC") for i in range(stress_count): bash(cmd) with Test("check multiline command using echo -e with long lines"): with Shell() as bash: cmd = textwrap.dedent(""" echo -e " SELECT hex( aes_decrypt_mysql( 'aes-256-cbc', dictGet('default.dict_user_data', 'secret', toUInt64(1)), '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', '22222222222222222$ ) ) " """) for i in range(stress_count): bash(cmd) with Test("check subshell"): with Shell() as bash: with Check("first subshell"): with bash.subshell("bash --noediting") as sub_bash: sub_bash("ls -la") bash("ls -la") with Check("second subshell"): with bash.subshell("bash --noediting") as sub_bash: sub_bash("ls -la") bash("ls -la")