def assert_complete(bash: pexpect.spawn, cmd: str, **kwargs) -> CompletionResult: skipif = kwargs.get("skipif") if skipif: try: assert_bash_exec(bash, skipif, want_output=None) except AssertionError: pass else: pytest.skip(skipif) xfail = kwargs.get("xfail") if xfail: try: assert_bash_exec(bash, xfail, want_output=None) except AssertionError: pass else: pytest.xfail(xfail) with bash_env_saved(bash, sendintr=True) as bash_env: cwd = kwargs.get("cwd") if cwd: bash_env.chdir(str(cwd)) for k, v in kwargs.get("env", {}).items(): bash_env.write_env(k, v, quote=False) for k, v in kwargs.get("shopt", {}).items(): bash_env.shopt(k, v) bash.send(cmd + "\t") # Sleep a bit if requested, to avoid `.*` matching too early time.sleep(kwargs.get("sleep_after_tab", 0)) bash.expect_exact(kwargs.get("rendered_cmd", cmd)) bash.send(MAGIC_MARK) got = bash.expect([ # 0: multiple lines, result in .before r"\r\n" + re.escape(PS1 + cmd) + ".*" + re.escape(MAGIC_MARK), # 1: no completion r"^" + re.escape(MAGIC_MARK), # 2: on same line, result in .match r"^([^\r]+)%s$" % re.escape(MAGIC_MARK), pexpect.EOF, pexpect.TIMEOUT, ]) if got == 0: output = bash.before if output.endswith(MAGIC_MARK): output = bash.before[:-len(MAGIC_MARK)] return CompletionResult(output) elif got == 2: output = bash.match.group(1) return CompletionResult(output) else: # TODO: warn about EOF/TIMEOUT? return CompletionResult()
def assert_complete_at_point( bash: pexpect.spawn, cmd: str, trail: str ) -> CompletionResult: # TODO: merge to assert_complete fullcmd = "%s%s%s" % ( cmd, trail, "\002" * len(trail), ) # \002 = ^B = cursor left bash.send(fullcmd + "\t") bash.send(MAGIC_MARK) bash.expect_exact(fullcmd.replace("\002", "\b")) got = bash.expect_exact( [ # 0: multiple lines, result in .before PS1 + fullcmd.replace("\002", "\b"), # 1: no completion MAGIC_MARK, pexpect.EOF, pexpect.TIMEOUT, ] ) if got == 0: output = bash.before result = CompletionResult(output) # At this point, something weird happens. For most test setups, as # expected (pun intended!), MAGIC_MARK follows as is. But for some # others (e.g. CentOS 6, Ubuntu 14 test containers), we get MAGIC_MARK # one character a time, followed each time by trail and the corresponding # number of \b's. Don't know why, but accept it until/if someone finds out. # Or just be fine with it indefinitely, the visible and practical end # result on a terminal is the same anyway. repeat = "(%s%s)?" % (re.escape(trail), "\b" * len(trail)) fullexpected = "".join( "%s%s" % (re.escape(x), repeat) for x in MAGIC_MARK ) bash.expect(fullexpected) else: # TODO: warn about EOF/TIMEOUT? result = CompletionResult() return result
def _wait_connect(self, p: pexpect.spawn, password_manager: PasswordManager, azure_ad_config: AuthConfig): i = p.expect([ pexpect.EOF, re.compile(r"continue connecting \(yes/no(/\[fingerprint])?\)\? "), re.compile(r"authenticate\.") ]) if i == 0: if self.is_connected(): return else: raise GProxyError(f"Error when initializing SSH: {p.before}") elif i == 1: host_key_fingerprint = self._extract_host_key_fingerprint(p.before) if host_key_fingerprint != GPROXY_FINGERPRINT: raise GProxyError( f"!!!SEVERE!!! Host fingerprint is not matching expected!!! Report to CCOE!:" f"Actual:{host_key_fingerprint} != Expected:{GPROXY_FINGERPRINT}" ) LOG.info("Confirming host! Fingerprint is matching expected.") p.send("yes\r") self._wait_connect(p, password_manager, azure_ad_config) return p.send("\r") code = self._extract_code(p.before) url = self._extract_url(p.before) LOG.info(f"GProxy OTC Code: {code}, Url: {url}") if url != GProxyAdLogin.URL: raise GProxyError( f"Url does not match expected login-url. !={GProxyAdLogin.URL}" ) GProxyAdLogin(code=code, password_manager=password_manager, config=azure_ad_config).login_sync() p.expect(pexpect.EOF, timeout=30)
def assert_complete(bash: pexpect.spawn, cmd: str, **kwargs) -> CompletionResult: skipif = kwargs.get("skipif") if skipif: try: assert_bash_exec(bash, skipif) except AssertionError: pass else: pytest.skip(skipif) xfail = kwargs.get("xfail") if xfail: try: assert_bash_exec(bash, xfail) except AssertionError: pass else: pytest.xfail(xfail) cwd = kwargs.get("cwd") if cwd: assert_bash_exec(bash, "cd '%s'" % cwd) env_prefix = "_BASHCOMP_TEST_" env = kwargs.get("env", {}) if env: # Back up environment and apply new one assert_bash_exec( bash, " ".join('%s%s="$%s"' % (env_prefix, k, k) for k in env.keys()), ) assert_bash_exec( bash, "export %s" % " ".join("%s=%s" % (k, v) for k, v in env.items()), ) bash.send(cmd + "\t") bash.expect_exact(cmd) bash.send(MAGIC_MARK) got = bash.expect([ # 0: multiple lines, result in .before r"\r\n" + re.escape(PS1 + cmd) + ".*" + MAGIC_MARK, # 1: no completion r"^" + MAGIC_MARK, # 2: on same line, result in .match r"^([^\r]+)%s$" % MAGIC_MARK, pexpect.EOF, pexpect.TIMEOUT, ]) if got == 0: output = bash.before if output.endswith(MAGIC_MARK): output = bash.before[:-len(MAGIC_MARK)] result = CompletionResult(output) elif got == 2: output = bash.match.group(1) result = CompletionResult(output, [shlex.split(cmd + output)[-1]]) else: # TODO: warn about EOF/TIMEOUT? result = CompletionResult("", []) bash.sendintr() bash.expect_exact(PS1) if env: # Restore environment, and clean up backup # TODO: Test with declare -p if a var was set, backup only if yes, and # similarly restore only backed up vars. Should remove some need # for ignore_env. assert_bash_exec( bash, "export %s" % " ".join('%s="$%s%s"' % (k, env_prefix, k) for k in env.keys()), ) assert_bash_exec( bash, "unset -v %s" % " ".join("%s%s" % (env_prefix, k) for k in env.keys()), ) if cwd: assert_bash_exec(bash, "cd - >/dev/null") return result
def slow_sendline(exp: spawn, string: str): """Send one character at a time and wait for echo. The expect session deadlocks if we don't do this.""" for i in range(len(string)): exp.send(string[i]) exp.expect_exact(string[i]) exp.send('\n')
def dump_input_buffer_on_ctrl_g(zsh: pexpect.spawn) -> None: zsh.send( b"""strager_echo_buffer() { printf '[%s[%s]%s]\\n' '[' "${BUFFER}" ']' }\n""" ) zsh.send(b"zle -N strager_echo_buffer\n") zsh.send(b"bindkey '^g' strager_echo_buffer\n")
def send_and_expect_byte_by_byte(zsh: pexpect.spawn, input: bytes) -> bytes: for byte in input: current_input = bytes([byte]) zsh.send(current_input) zsh.expect(string_ignoring_escape_sequences_re(current_input))
def spawnAction(self, sp: spawn): print("sending {}".format(self)) yield sp.send(self)
def assert_complete( bash: pexpect.spawn, cmd: str, **kwargs) -> CompletionResult: skipif = kwargs.get("skipif") if skipif: try: assert_bash_exec(bash, skipif) except AssertionError: pass else: pytest.skip(skipif) return CompletionResult("", []) cwd = kwargs.get("cwd") if cwd: assert_bash_exec(bash, "cd '%s'" % cwd) env_prefix = "_BASHCOMP_TEST_" env = kwargs.get("env", {}) if env: # Back up environment and apply new one assert_bash_exec(bash, " ".join( '%s%s="$%s"' % (env_prefix, k, k) for k in env.keys() )) assert_bash_exec(bash, "export %s" % " ".join( "%s=%s" % (k, v) for k, v in env.items() )) bash.send(cmd + "\t") bash.expect_exact(cmd) bash.send(MAGIC_MARK) got = bash.expect([ r"\r\n" + re.escape(PS1 + cmd), # 0: multiple lines, result in .before r"^" + MAGIC_MARK, # 1: no completion r"^[^\r]+", # 2: on same line, result in .after pexpect.EOF, pexpect.TIMEOUT, ]) if got == 0: line = bash.before if line.endswith(MAGIC_MARK): line = bash.before[:-len(MAGIC_MARK)] result = CompletionResult( line, sorted(x for x in re.split(r" {2,}|\r\n", line) if x), ) elif got == 2: line = bash.after if line.endswith(MAGIC_MARK): line = bash.after[:-len(MAGIC_MARK)] result = CompletionResult( line, [shlex.split(cmd + line)[-1]], ) else: # TODO: warn about EOF/TIMEOUT? result = CompletionResult("", []) bash.sendintr() bash.expect_exact(PS1) if env: # Restore environment, and clean up backup # TODO: Test with declare -p if a var was set, backup only if yes, and # similarly restore only backed up vars. Should remove some need # for ignore_env. assert_bash_exec(bash, "export %s" % " ".join( '%s="$%s%s"' % (k, env_prefix, k) for k in env.keys() )) assert_bash_exec(bash, "unset -v %s" % " ".join( "%s%s" % (env_prefix, k) for k in env.keys() )) if cwd: assert_bash_exec(bash, "cd - >/dev/null") return result