Skip to content

Commit 5506289

Browse files
committed
vmrunner: more exit conditions + more method chaining
1 parent f86808d commit 5506289

2 files changed

Lines changed: 79 additions & 57 deletions

File tree

test/posix/integration/main/test.py

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,16 @@
1717
def check_exit(line, n = "0"):
1818
global T
1919
T += 1
20-
print "Python received: ", line
20+
print color.INFO("test.py"), "received: ", line
2121
status = line.split(" ")[-1].lstrip().rstrip()
2222
as_expected = status == n
2323

2424
if as_expected:
2525
print color.INFO("test.py"), "Exit status is ", status, "as expected"
26-
vm.exit(0, "Test " + str(T) + "/" + str(N) + " passed")
26+
vm.exit(0, "Test " + str(T) + "/" + str(N) + " passed", keep_running = True)
2727
return as_expected
2828
else:
29-
print color.WARNING("test.py"), "Exit status is", status, "expected", as_expected
30-
"expected " + n
29+
print color.WARNING("test.py"), "Exit status is", status, "expected", n
3130
return as_expected
3231

3332
def exit1(line):
@@ -36,28 +35,5 @@ def exit1(line):
3635
def exit2(line):
3736
return check_exit(line, "0")
3837

39-
def main_no_params():
40-
print "VM exited. Restarting."
41-
vm.clean()
42-
43-
# NOTE:
44-
# We can't add more output functions when reusing the same VM object
45-
# This will call python to complain about dictionary being resized while iterating
46-
# e.g. this would fail:
47-
# vm.on_output("Hello main", lambda(line): True)
48-
49-
# overwrite the main returned event
50-
vm.on_output("returned with status", exit2)
51-
52-
# Overwrite the on_exit event to avoid infinite loop
53-
vm.on_exit(lambda: 0)
54-
55-
# Build and run the second version of the service
56-
vm.cmake(["-DNORMAL=OFF"]).boot().clean()
57-
58-
# Default test (main with params) - check for exit value (printed by weak Service::start for now)
5938
vm.on_output("returned with status", exit1)
60-
61-
# After the default test (main with params) do the second test
62-
vm.on_exit(main_no_params)
63-
vm.cmake().boot(30)
39+
vm.cmake().boot(30).cmake(["-DNORMAL=OFF"]).on_output("returned with status", exit2).boot().clean()

vmrunner/vmrunner.py

Lines changed: 75 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ def __init__(self, config = None, hyper = qemu):
399399

400400
self._exit_status = None
401401
self._exit_msg = ""
402+
self._exit_complete = False
403+
402404
self._config = load_single_config(config)
403405
self._on_success = lambda(line) : self.exit(exit_codes["SUCCESS"], nametag + " All tests passed")
404406
self._on_panic = self.panic
@@ -432,23 +434,44 @@ def wait(self):
432434
def poll(self):
433435
return self._hyper.poll()
434436

435-
def exit(self, status, msg):
437+
# Stop the VM with exit status / msg.
438+
# set keep_running to indicate that the program should continue
439+
def exit(self, status, msg, keep_running = False):
440+
441+
# Exit may have been called allready
442+
if self._exit_complete:
443+
return
444+
436445
self._exit_status = status
446+
self._exit_msg = msg
437447
self.stop()
438-
info("Exit called with status", self._exit_status, "(",get_exit_code_name(self._exit_status),")")
439-
info("Calling on_exit")
448+
440449
# Change back to test source
441450
os.chdir(self._root)
442-
self._on_exit()
451+
452+
453+
info("Exit called with status", self._exit_status, "(",get_exit_code_name(self._exit_status),")")
454+
info("Message:", msg, "Keep running: ", keep_running)
455+
456+
if keep_running:
457+
return
458+
459+
if self._on_exit:
460+
info("Calling on_exit")
461+
self._on_exit()
462+
463+
443464
if status == 0:
444-
# Print success message and return to caller
465+
if self._on_exit_success:
466+
info("Calling on_exit_success")
467+
self._on_exit_success()
468+
445469
print color.SUCCESS(msg)
446-
info("Calling on_exit_success")
447-
return self._on_exit_success()
470+
self._exit_complete = True
471+
return
448472

449-
# Print fail message and exit with appropriate code
450-
print color.EXIT_ERROR(get_exit_code_name(status), msg)
451-
sys.exit(status)
473+
self._exit_complete = True
474+
program_exit(status, msg)
452475

453476
# Default timeout event
454477
def timeout(self):
@@ -474,23 +497,29 @@ def panic(self, panic_line):
474497
# Events - subscribable
475498
def on_output(self, output, callback):
476499
self._on_output[ output ] = callback
500+
return self
477501

478502
def on_success(self, callback, do_exit = True):
479503
if do_exit:
480504
self._on_output["SUCCESS"] = lambda(line) : [callback(line), self._on_success(line)]
481505
else: self._on_output["SUCCESS"] = callback
506+
return self
482507

483508
def on_panic(self, callback):
484509
self._on_output["PANIC"] = lambda(line) : [callback(line), self._on_panic(line)]
510+
return self
485511

486512
def on_timeout(self, callback):
487513
self._on_timeout = callback
514+
return self
488515

489516
def on_exit_success(self, callback):
490517
self._on_exit_success = callback
518+
return self
491519

492520
def on_exit(self, callback):
493521
self._on_exit = callback
522+
return self
494523

495524
# Read a line from the VM's standard out
496525
def readline(self):
@@ -542,20 +571,23 @@ def cmake(self, args = []):
542571
def clean(self):
543572
print INFO, "Cleaning cmake build folder"
544573
subprocess.call(["rm","-rf","build"])
574+
return self
545575

546576
def find_exit_trigger(self, line):
547577

548-
# Special case for end-of-transmission, e.g. on panic
549-
if line == EOT:
550-
if not self._exit_status: self._exit_status = exit_codes["VM_EOT"]
551-
return True
552-
553578
# Kernel reports service exit status
554-
if line.startswith(" [ Kernel ] service exited with status"):
579+
if (line.startswith(" [ Kernel ] service exited with status") or
580+
line.startswith(" [ main ] returned with status")):
581+
555582
self._exit_status = int(line.split(" ")[-1].rstrip())
556583
self._exit_msg = "Service exited with status " + str(self._exit_status)
557584
return True
558585

586+
# Special case for end-of-transmission, e.g. on panic
587+
if line == EOT:
588+
self._exit_status = exit_codes["VM_EOT"]
589+
return True
590+
559591
return False
560592

561593

@@ -583,6 +615,7 @@ def boot(self, timeout = 60, multiboot = True, kernel_args = "booted with vmrunn
583615

584616
# This might be a reboot
585617
self._exit_status = None
618+
self._exit_complete = False
586619
self._timeout_after = timeout
587620

588621
# Start the timeout thread
@@ -628,18 +661,23 @@ def boot(self, timeout = 60, multiboot = True, kernel_args = "booted with vmrunn
628661
# possibly normal vm shutdown
629662
if self.poll() != None:
630663

631-
info("No exit status, and no poll - getting final output")
632-
data, err = self._hyper.get_final_output()
664+
info("No poll - getting final output")
665+
try:
666+
data, err = self._hyper.get_final_output()
667+
668+
# Print stderr if exit status wasnt 0
669+
if err and self.poll() != 0:
670+
print color.WARNING("Stderr: \n" + err)
633671

634-
# Print stderr if exit status wasnt 0
635-
if err and self.poll() != 0:
636-
print color.WARNING("Stderr: \n" + err)
672+
# Parse the last output from vm
673+
lines = data.split("\n")
674+
for line in lines:
675+
print color.VM(line)
676+
self.find_exit_trigger(line)
677+
# Note: keep going. Might find panic after service exit
637678

638-
# Parse the last output from vm
639-
lines = data.split("\n")
640-
for line in lines:
641-
print color.VM(line)
642-
self.find_exit_trigger(line)
679+
except Exception as e:
680+
pass
643681

644682
# We should now have an exit status, either from a callback or VM EOT / exit msg.
645683
if self._exit_status != None:
@@ -700,11 +738,19 @@ def load_single_config(path = default_json):
700738

701739
def program_exit(status, msg):
702740
global vms
741+
742+
info("Program exit called with status", status, "(",get_exit_code_name(status),")")
743+
info("Stopping all vms")
744+
703745
for vm in vms:
704746
vm.stop().wait()
705-
info("Exit called with status", status, "(",get_exit_code_name(status),")")
706-
# Print fail message and exit with appropriate code
707-
print color.EXIT_ERROR(get_exit_code_name(status), msg)
747+
748+
# Print status message and exit with appropriate code
749+
if (status):
750+
print color.EXIT_ERROR(get_exit_code_name(status), msg)
751+
else:
752+
print color.SUCCESS(msg)
753+
708754
sys.exit(status)
709755

710756

0 commit comments

Comments
 (0)