test-in-vm: better farewell message
[ci.git] / test-in-vm.py
blob95ed1e66568e98d081d0e55830f33f6463b19320
1 #!/usr/bin/env python3
4 # Copyright (c) 2018 Vojtech Horky
5 # All rights reserved.
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
11 # - Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
13 # - Redistributions in binary form must reproduce the above copyright
14 # notice, this list of conditions and the following disclaimer in the
15 # documentation and/or other materials provided with the distribution.
16 # - The name of the author may not be used to endorse or promote products
17 # derived from this software without specific prior written permission.
19 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 import argparse
33 import yaml
34 import logging
35 import sys
37 from htest.vm.controller import VMManager
38 from htest.vm.qemu import QemuVMController
39 from htest.tasks import *
41 args = argparse.ArgumentParser(
42 description='Testing of HelenOS in VM',
43 formatter_class=argparse.RawDescriptionHelpFormatter,
44 epilog="""
45 Typical invocation will use the following arguments:
46 --image helenos.iso
47 --scenario scenario.yml
48 --arch amd64 # ia32, ppc32 etc.
49 --vterm-dump dump.txt # all text from main vterm
50 --last-screenshot shot.png # last VM screen
51 """
53 args.add_argument('--headless',
54 dest='headless',
55 default=False,
56 action='store_true',
57 help='Do not show any VM windows.'
59 args.add_argument('--scenario',
60 metavar='FILENAME.yml',
61 dest='scenario',
62 required=True,
63 help='Scenario file'
65 args.add_argument('--arch',
66 metavar='ARCHITECTURE',
67 dest='architecture',
68 required=True,
69 help='Emulated architecture identification.'
71 args.add_argument('--memory',
72 metavar='MB',
73 dest='memory',
74 type=int,
75 required=False,
76 default=256,
77 help='Amount of memory for the virtual machine.'
79 args.add_argument('--image',
80 metavar='FILENAME',
81 dest='boot_image',
82 required=True,
83 help='HelenOS boot image (e.g. ISO file).'
85 args.add_argument('--pass',
86 metavar='OPTION',
87 dest='pass_thru_options',
88 default=[],
89 action='append',
90 help='Extra options to pass through to the emulator'
92 args.add_argument('--vterm-dump',
93 metavar='FILENAME.txt',
94 dest='vterm_dump',
95 default=None,
96 help='Where to store full vterm dump.'
98 args.add_argument('--last-screenshot',
99 metavar='FILENAME.png',
100 dest='last_screenshot',
101 default=None,
102 help='Where to store last screenshot.'
104 args.add_argument('--debug',
105 dest='debug',
106 default=False,
107 action='store_true',
108 help='Print debugging messages'
111 config = args.parse_args()
113 if config.debug:
114 config.logging_level = logging.DEBUG
115 else:
116 config.logging_level = logging.INFO
118 logging.basicConfig(
119 format='[%(asctime)s %(name)-16s %(levelname)7s] %(message)s',
120 level=config.logging_level
123 logger = logging.getLogger('main')
125 with open(config.scenario, 'r') as f:
126 try:
127 scenario = yaml.load(f)
128 except yaml.YAMLError as ex:
129 logger.error(ex)
130 sys.exit(1)
132 if config.memory < 8:
133 logger.error("Specify at least 8MB of memory.")
134 sys.exit(1)
136 controller = None
137 for ctl in [ QemuVMController ]:
138 if ctl.is_supported(config.architecture):
139 controller = ctl
141 if controller is None:
142 logger.error("Unsupported architecture {}.".format(config.architecture))
143 sys.exit(1)
145 vmm = VMManager(controller, config.architecture, config.boot_image, config.memory, config.headless, config.pass_thru_options)
147 scenario_tasks = []
148 for t in scenario['tasks']:
149 task_name = None
150 if type(t) is dict:
151 k = list(set(t.keys()) - set(['name', 'machine']))
152 if len(k) != 1:
153 raise Exception("Unknown task ({})!".format(k))
154 task_name = k[0]
155 elif type(t) is str:
156 task_name = t
157 t = {
158 task_name: {}
160 else:
161 raise Exception("Unknown task!")
162 task_classname = 'ScenarioTask' + task_name.title().replace('-', '_')
163 task_class = globals()[task_classname]
164 task_inst = task_class(t[task_name])
165 if not ('machine' in t):
166 t['machine'] = None
167 machine = vmm.get(t['machine'])
168 if machine is None:
169 if t['machine'] is None:
170 t['machine'] = 'default'
171 logger.debug("Creating new machine {}.".format(t['machine']))
172 machine = vmm.create(t['machine'])
173 task_inst.set_machine(machine)
174 scenario_tasks.append(task_inst)
176 exit_code = 0
177 try:
178 for t in scenario_tasks:
179 t.run()
180 print("Scenario passed.")
181 except Exception as ex:
182 logger.exception("Scenario aborted: {}".format(ex))
183 print("Scenario aborted: {}".format(ex))
184 exit_code = 1
186 vmm.terminate(config.vterm_dump, config.last_screenshot)
187 sys.exit(exit_code)