Skip to content

Commit

Permalink
scripts: enhance tests/testing.py
Browse files Browse the repository at this point in the history
This patch enhances the script in following ways:
- makes it work regardless which place on filesystem called from
- allows piping the standard input to the guest input to help
  automate testings interactive apps like cli
- adds couple of new methods to test appearance of text in the guest output

Signed-off-by: Waldemar Kozaczuk <[email protected]>
  • Loading branch information
wkozaczuk committed Oct 23, 2019
1 parent bf4c37a commit 9ba8142
Showing 1 changed file with 44 additions and 13 deletions.
57 changes: 44 additions & 13 deletions scripts/tests/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
tests = []
_verbose_output = False

osv_base = '.'
osv_base = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../..')

class TestFailed(Exception):
pass
Expand Down Expand Up @@ -93,8 +93,12 @@ def scan_errors(s,scan_for_failed_to_load_object_error=True):
return False

class SupervisedProcess:
def __init__(self, args, show_output=False, show_output_on_error=True, scan_for_failed_to_load_object_error=True):
self.process = subprocess.Popen(args, stdout=subprocess.PIPE)
def __init__(self, args, show_output=False, show_output_on_error=True, scan_for_failed_to_load_object_error=True, pipe_stdin=False):
if pipe_stdin:
self.process = subprocess.Popen(args, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
else:
self.process = subprocess.Popen(args, stdout=subprocess.PIPE)
self.pipe_stdin = pipe_stdin
self.cv = threading.Condition()
self.lines = []
self.output_collector_done = False
Expand All @@ -105,13 +109,15 @@ def __init__(self, args, show_output=False, show_output_on_error=True, scan_for_
self.output_collector_thread = threading.Thread(target=self._output_collector)
self.output_collector_thread.start()
self.scan_for_failed_to_load_object_error = scan_for_failed_to_load_object_error
self.line_with_err = ""

def _output_collector(self):
def append_line(line):
self.cv.acquire()

if not self.has_errors and scan_errors(line,self.scan_for_failed_to_load_object_error):
self.has_errors = True
self.line_with_err = line
if self.show_output_on_error and not self.show_output:
sys.stdout.write(self.output)
sys.stdout.flush()
Expand All @@ -126,14 +132,20 @@ def append_line(line):
self.cv.release()

line = ''
ch_bytes = ''
while True:
ch = self.process.stdout.read(1).decode()
if ch == '' and self.process.poll() != None:
break
line += ch
if ch == '\n':
append_line(line)
line = ''
ch_bytes = ch_bytes + self.process.stdout.read(1)
try:
ch = ch_bytes.decode('utf-8')
if ch == '' and self.process.poll() != None:
break
line += ch
if ch == '\n':
append_line(line)
line = ''
ch_bytes = ''
except UnicodeError:
continue

if line:
append_line(line)
Expand Down Expand Up @@ -165,6 +177,8 @@ def read_lines(self):

def join(self):
self.output_collector_thread.join()
if self.pipe_stdin:
self.process.stdin.close()
if self.process.returncode:
raise Exception('Guest failed (returncode=%d)' % self.proces.returncode)
if self.failed:
Expand All @@ -185,6 +199,13 @@ def failed(self):
assert not self.output_collector_thread.isAlive()
return self.has_errors or self.process.returncode

def write_line_to_input(self, line):
self.process.stdin.write(line + "\n")
self.process.stdin.flush()

def line_with_error(self):
return self.line_with_err

def run_command_in_guest(command, **kwargs):
common_parameters = ["-e", "--power-off-on-abort " + command]
if 'hypervisor' in kwargs.keys() and kwargs['hypervisor'] == 'firecracker':
Expand All @@ -194,7 +215,7 @@ def run_command_in_guest(command, **kwargs):

class Guest(SupervisedProcess):
def __init__(self, args, forward=[], hold_with_poweroff=False, show_output_on_error=True,
scan_for_failed_to_load_object_error=True, run_py_args=[], hypervisor='qemu'):
scan_for_failed_to_load_object_error=True, run_py_args=[], hypervisor='qemu', pipe_stdin=False):

if hypervisor == 'firecracker':
run_script = os.path.join(osv_base, "scripts/firecracker.py")
Expand All @@ -215,7 +236,8 @@ def __init__(self, args, forward=[], hold_with_poweroff=False, show_output_on_er
SupervisedProcess.__init__(self, [run_script] + run_py_args + args,
show_output=_verbose_output,
show_output_on_error=show_output_on_error,
scan_for_failed_to_load_object_error=scan_for_failed_to_load_object_error)
scan_for_failed_to_load_object_error=scan_for_failed_to_load_object_error,
pipe_stdin=pipe_stdin)

def kill(self):
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
Expand All @@ -225,8 +247,17 @@ def kill(self):
s.close()

def wait_for_line(guest, text):
return _wait_for_line(guest, lambda line: line == text, text)

def wait_for_line_starts(guest, text):
return _wait_for_line(guest, lambda line: line.startswith(text), text)

def wait_for_line_contains(guest, text):
return _wait_for_line(guest, lambda line: text in line, text)

def _wait_for_line(guest, predicate, text):
for line in guest.read_lines():
if line == text:
if predicate(line):
return
raise Exception('Text not found in output: ' + text)

Expand Down

0 comments on commit 9ba8142

Please sign in to comment.