Start work on unit tests of CI
[ci.git] / test-in-vm.py
blobb141fad1c96c6bc90ef7d430485ade733107abb7
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.vm.msim import MsimVMController
40 from htest.tasks import *
42 args = argparse.ArgumentParser(
43 description='Testing of HelenOS in VM',
44 formatter_class=argparse.RawDescriptionHelpFormatter,
45 epilog="""
46 Typical invocation will use the following arguments:
47 --image helenos.iso
48 --scenario scenario.yml
49 --arch amd64 # ia32, ppc32 etc.
50 --vterm-dump dump.txt # all text from main vterm
51 --last-screenshot shot.png # last VM screen
52 """
54 args.add_argument('--headless',
55 dest='headless',
56 default=False,
57 action='store_true',
58 help='Do not show any VM windows.'
60 args.add_argument('--scenario',
61 metavar='FILENAME.yml',
62 dest='scenario',
63 required=True,
64 help='Scenario file'
66 args.add_argument('--arch',
67 metavar='ARCHITECTURE',
68 dest='architecture',
69 required=True,
70 help='Emulated architecture identification.'
72 args.add_argument('--memory',
73 metavar='MB',
74 dest='memory',
75 type=int,
76 required=False,
77 default=256,
78 help='Amount of memory for the virtual machine.'
80 args.add_argument('--image',
81 metavar='FILENAME',
82 dest='boot_image',
83 required=True,
84 help='HelenOS boot image (e.g. ISO file).'
86 args.add_argument('--disk',
87 metavar='FILENAME',
88 dest='disk_image',
89 required=False,
90 default=None,
91 help='Disk image (e.g. hdisk.img).'
93 args.add_argument('--vm-config',
94 metavar='FILENAME',
95 dest='vm_config',
96 required=False,
97 default=None,
98 help='VM emulator configuration (e.g. msim.conf)'
100 args.add_argument('--pass',
101 metavar='OPTION',
102 dest='pass_thru_options',
103 default=[],
104 action='append',
105 help='Extra options to pass through to the emulator'
107 args.add_argument('--vterm-dump',
108 metavar='FILENAME.txt',
109 dest='vterm_dump',
110 default=None,
111 help='Where to store full vterm dump.'
113 args.add_argument('--last-screenshot',
114 metavar='FILENAME.png',
115 dest='last_screenshot',
116 default=None,
117 help='Where to store last screenshot.'
119 args.add_argument('--debug',
120 dest='debug',
121 default=False,
122 action='store_true',
123 help='Print debugging messages'
126 config = args.parse_args()
128 if config.debug:
129 config.logging_level = logging.DEBUG
130 else:
131 config.logging_level = logging.INFO
133 logging.basicConfig(
134 format='[%(asctime)s %(name)-16s %(levelname)7s] %(message)s',
135 level=config.logging_level
138 logger = logging.getLogger('main')
140 with open(config.scenario, 'r') as f:
141 try:
142 scenario = yaml.load(f)
143 except yaml.YAMLError as ex:
144 logger.error(ex)
145 sys.exit(1)
147 if config.memory < 8:
148 logger.error("Specify at least 8MB of memory.")
149 sys.exit(1)
151 controller = None
152 for ctl in [ QemuVMController, MsimVMController ]:
153 if ctl.is_supported(config.architecture):
154 controller = ctl
156 if controller is None:
157 logger.error("Unsupported architecture {}.".format(config.architecture))
158 sys.exit(1)
160 vmm = VMManager(controller, config.architecture, config.vm_config, config.boot_image, config.disk_image, config.memory, config.headless, config.pass_thru_options)
162 scenario_tasks = []
163 for t in scenario['tasks']:
164 task_name = None
165 if type(t) is dict:
166 k = list(set(t.keys()) - set(['name', 'machine']))
167 if len(k) != 1:
168 raise Exception("Unknown task ({})!".format(k))
169 task_name = k[0]
170 elif type(t) is str:
171 task_name = t
172 t = {
173 task_name: {}
175 else:
176 raise Exception("Unknown task!")
177 task_classname = 'ScenarioTask' + task_name.title().replace('-', '_')
178 task_class = globals()[task_classname]
179 task_inst = task_class(t[task_name])
180 if not ('machine' in t):
181 t['machine'] = None
182 machine = vmm.get(t['machine'])
183 if machine is None:
184 if t['machine'] is None:
185 t['machine'] = 'default'
186 logger.debug("Creating new machine {}.".format(t['machine']))
187 machine = vmm.create(t['machine'])
188 task_inst.set_machine(machine)
189 scenario_tasks.append(task_inst)
191 exit_code = 0
192 try:
193 for t in scenario_tasks:
194 t.run()
195 print("Scenario passed.")
196 except Exception as ex:
197 logger.exception("Scenario aborted: {}".format(ex))
198 print("Scenario aborted: {}".format(ex))
199 exit_code = 1
201 vmm.terminate(config.vterm_dump, config.last_screenshot)
202 sys.exit(exit_code)