def run(self): self.logger.info("Typing '{}' into {}.".format(self.command, self.machine.name)) # Capture the screen before typing the command. self.machine.capture_vterm() self.machine.type(self.command) # Wait until the command is fully displayed on the screen. # That is needed to properly detect the newly displayed lines. # FIXME: this will not work for long commands spanning multiple lines for xxx in retries(timeout=60, interval=2, name="vterm-type", message="Failed to type command"): self.machine.vterm = [] self.machine.capture_vterm() lines = self.machine.vterm if len(lines) > 0: line = lines[0].strip() if line.endswith("_"): line = line[0:-1] if line.endswith(self.command.strip()): break self.machine.vterm = [] self.machine.type('\n') # Read output of the command. # We wait until prompt reappears or we find some text that is not # supposed to be there. for xxx in retries(timeout=60, interval=2, name="vterm-run", message="Failed to run command"): self.logger.debug("self.vterm = {}".format(self.machine.vterm)) self.machine.capture_vterm() lines = self.machine.vterm self.logger.debug("Read lines {}".format(lines)) self.machine.vterm = [] if not self.ignore_abort: if self._grep('Cannot spawn', lines) or self._grep( 'Command failed', lines): raise Exception('Failed to run command') if 'negassert' in self.args: if self._grep(self.args['negassert'], lines): raise Exception('Found forbidden text {} ...'.format( self.args['negassert'])) if 'assert' in self.args: if self._grep(self.args['assert'], lines): break if self._grep('# _', lines): if 'assert' in self.args: raise Exception('Missing expected text {} ...'.format( self.args['assert'])) break self.logger.info("Command '{}' done.".format(self.command))
def boot(self, **kwargs): self.monitor_file = self.get_temp('monitor') cmd = [] for opt in QemuVMController.config[self.arch]: if opt == '{BOOT}': opt = self.boot_image elif opt == '{MEMORY}': opt = '{}'.format(self.memory) cmd.append(opt) if self.disk_image is not None: cmd.append('-drive') cmd.append('file={},index=0,media=disk,format=raw'.format(self.disk_image)) if self.is_headless: cmd.append('-display') cmd.append('none') cmd.append('-monitor') cmd.append('unix:{},server,nowait'.format(self.monitor_file)) for opt in self.extra_options: cmd.append(opt) self.logger.debug("Starting QEMU: {}".format(format_command(cmd))) self.proc = subprocess.Popen(cmd) self.monitor = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) for xxx in retries(timeout=30, interval=2, name="ctl-socket", message="Failed to connect to QEMU control socket."): try: self.monitor.connect(self.monitor_file) break except FileNotFoundError: pass except ConnectionRefusedError: pass if self.proc.poll(): raise Exception("QEMU not started, aborting.") self.booted = True self.logger.info("Machine started.") # Skip past GRUB self.type('\n') uspace_booted = False for xxx in retries(timeout=3*60, interval=5, name="vterm", message="Failed to boot into userspace"): self.vterm = [] self.capture_vterm() for l in self.vterm: if l.find('to see a few survival tips') != -1: uspace_booted = True break if uspace_booted: break assert uspace_booted self.full_vterm = self.vterm self.logger.info("Machine booted into userspace.") return
def capture_vterm_impl(self): try: os.remove(self.screendump_file) except IOError as e: pass try: os.remove(self.screenshot_filename) except IOError as e: pass self._xdotool_key('alt+s') screenshooter = subprocess.Popen([ 'import', '-display', self.x11_display, '-window', 'root', self.screenshot_filename ]) screenshooter.wait() for xxx in retries(timeout=5, interval=1, name="xterm-dump", message="Failed to read XTerm screendump"): try: with open(self.screendump_file, 'r') as f: lines = [l.strip('\n') for l in f.readlines()] if len(lines) != 24: continue self.logger.debug("Captured text:") for l in lines: self.logger.debug("| " + l) return lines except IOError as e: pass
def boot(self, **kwargs): self.screenshot_filename = self.get_temp('screenshot.png') self.screendump_file = self.get_temp('xterm.screendump') config_file = self.get_temp('rewr.msim.conf') with open(config_file, 'w') as f: config_lines = self._rewrite_configuration() for l in config_lines: print(l, file=f) self._start_xserver() self.booted = True xterm_env = os.environ.copy() xterm_env['DISPLAY'] = self.x11_display self.xterm = subprocess.Popen([ 'xterm', '-xrm', 'XTerm*printAttributes: 0', '-xrm', 'XTerm*printerCommand: cat - > "{}"'.format( self.screendump_file), '-xrm', 'XTerm.VT100.translations: #override Meta <KeyPress> S: print() \n', '-e', 'msim -c ' + config_file ], env=xterm_env) time.sleep(2) if self.xterm.poll() is not None: self.screendump_file = None self.screenshot_filename = None raise Exception("Failed to start MSIM") self.logger.info("Machine started.") uspace_booted = False for xxx in retries(timeout=10 * 60, interval=5, name="vterm", message="Failed to boot into userspace"): self.vterm = [] self.full_vterm = [] self.capture_vterm() for l in self.vterm: if l.find('to see a few survival tips') != -1: uspace_booted = True break if uspace_booted: break assert uspace_booted self.full_vterm = self.vterm self.logger.info("Machine booted into userspace.") return
def capture_vterm_impl(self): screenshot_full = self.get_temp('screen-full.ppm') screenshot_term = self.get_temp('screen-term.png') screenshot_text = self.get_temp('screen-term.txt') try: os.remove(screenshot_full) except IOError as e: pass self._send_command('screendump ' + screenshot_full) for xxx in retries(timeout=10, interval=1, name="scrdump", message="Failed to capture screen"): try: self._run_command([ 'convert', screenshot_full, '-crop', '640x480+4+24', '+repage', '-colors', '2', '-monochrome', screenshot_term ]) break except: pass width, height = self._get_image_dimensions(screenshot_term) cols = width // 8 rows = height // 16 self._run_pipe([ [ 'convert', screenshot_term, '-crop', '{}x{}'.format(cols * 8, rows * 16), '+repage', '-crop', '8x16', '+repage', '+adjoin', 'txt:-', ], [ 'sed', '-e', 's|[0-9]*,[0-9]*: ([^)]*)[ ]*#\\([0-9A-Fa-f]\\{6\\}\\).*|\\1|', '-e', 's:^#.*:@:', '-e', 's#000000#0#g', '-e', 's#FFFFFF#F#', ], [ 'tee', self.get_temp('1.txt') ], [ 'sed', '-e', ':a', '-e', 'N;s#\\n##;s#^@##;/@$/{s#@$##p;d}', '-e', 't a', ], [ 'tee', self.get_temp('2.txt') ], [ 'sed', '-f', QemuVMController.ocr_sed, ], [ 'sed', '/../s#.*#?#', ], [ 'tee', self.get_temp('3.txt') ], [ 'paste', '-sd', '', ], [ 'fold', '-w', '{}'.format(cols), ], [ 'tee', self.get_temp('4.txt') ], [ 'head', '-n', '{}'.format(rows), ], [ 'tee', screenshot_text, ] ]) self.screenshot_filename = screenshot_full with open(screenshot_text, 'r') as f: lines = [ l.strip('\n') for l in f.readlines() ] self.logger.debug("Captured text:") for l in lines: self.logger.debug("| " + l) return lines
def run(self): self.logger.info("Typing '{}' into {}.".format(self.command, self.machine.name)) cursor_symbol = self.machine.get_vterm_cursor_symbol() cursor_symbol_spaced = '' if cursor_symbol == '' else ' ' + cursor_symbol prompt_re = re.compile('^/[^ ]* #' + re.escape(cursor_symbol_spaced) + '[\t ]*$') self.logger.debug("RE for prompt matching: {}".format(prompt_re)) # Capture the screen before typing the command. self.machine.capture_vterm() self.machine.type(self.command) # Wait until the command is fully displayed on the screen. # That is needed to properly detect the newly displayed lines. # FIXME: this will not work for long commands spanning multiple lines for xxx in retries(timeout=60, interval=2, name="vterm-type", message="Failed to type command"): self.machine.vterm = [] self.machine.capture_vterm() lines = self.machine.vterm if len(lines) > 0: line = lines[0].strip() if (cursor_symbol != '') and line.endswith(cursor_symbol): line = line[0:-(len(cursor_symbol))] if line.endswith(self.command.strip()): break self.machine.vterm = [] self.machine.type('\n') # Read output of the command. # We wait until prompt reappears or we find some text that is not # supposed to be there. Meanwhile we check that the text that is # supposed to be there appears. asserted_text_found = not 'assert' in self.args for xxx in retries(timeout=60, interval=2, name="vterm-run", message="Failed to run command"): self.logger.debug("self.vterm = {}".format(self.machine.vterm)) self.machine.capture_vterm() lines = self.machine.vterm self.logger.debug("Read lines {}".format(lines)) self.machine.vterm = [] if not self.ignore_abort: if self._find_in_lines('Cannot spawn', lines) or self._find_in_lines( 'Command failed', lines): raise Exception('Failed to run command') if 'negassert' in self.args: if self._find_in_lines(self.args['negassert'], lines): raise Exception('Found forbidden text {} ...'.format( self.args['negassert'])) if ('assert' in self.args) and (not asserted_text_found): asserted_text_found = self._find_in_lines( self.args['assert'], lines) if self._grep_in_lines(prompt_re, lines): if not asserted_text_found: raise Exception('Missing expected text {} ...'.format( self.args['assert'])) break self.logger.info("Command '{}' done.".format(self.command))