test-in-vm: add --disk option
[ci.git] / test-in-vm.py
blobad8950dcd37451a97fe7233754b48b82cc283035
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('--disk',
86 metavar='FILENAME',
87 dest='disk_image',
88 required=False,
89 default=None,
90 help='Disk image (e.g. hdisk.img).'
92 args.add_argument('--pass',
93 metavar='OPTION',
94 dest='pass_thru_options',
95 default=[],
96 action='append',
97 help='Extra options to pass through to the emulator'
99 args.add_argument('--vterm-dump',
100 metavar='FILENAME.txt',
101 dest='vterm_dump',
102 default=None,
103 help='Where to store full vterm dump.'
105 args.add_argument('--last-screenshot',
106 metavar='FILENAME.png',
107 dest='last_screenshot',
108 default=None,
109 help='Where to store last screenshot.'
111 args.add_argument('--debug',
112 dest='debug',
113 default=False,
114 action='store_true',
115 help='Print debugging messages'
118 config = args.parse_args()
120 if config.debug:
121 config.logging_level = logging.DEBUG
122 else:
123 config.logging_level = logging.INFO
125 logging.basicConfig(
126 format='[%(asctime)s %(name)-16s %(levelname)7s] %(message)s',
127 level=config.logging_level
130 logger = logging.getLogger('main')
132 with open(config.scenario, 'r') as f:
133 try:
134 scenario = yaml.load(f)
135 except yaml.YAMLError as ex:
136 logger.error(ex)
137 sys.exit(1)
139 if config.memory < 8:
140 logger.error("Specify at least 8MB of memory.")
141 sys.exit(1)
143 controller = None
144 for ctl in [ QemuVMController ]:
145 if ctl.is_supported(config.architecture):
146 controller = ctl
148 if controller is None:
149 logger.error("Unsupported architecture {}.".format(config.architecture))
150 sys.exit(1)
152 vmm = VMManager(controller, config.architecture, config.boot_image, config.disk_image, config.memory, config.headless, config.pass_thru_options)
154 scenario_tasks = []
155 for t in scenario['tasks']:
156 task_name = None
157 if type(t) is dict:
158 k = list(set(t.keys()) - set(['name', 'machine']))
159 if len(k) != 1:
160 raise Exception("Unknown task ({})!".format(k))
161 task_name = k[0]
162 elif type(t) is str:
163 task_name = t
164 t = {
165 task_name: {}
167 else:
168 raise Exception("Unknown task!")
169 task_classname = 'ScenarioTask' + task_name.title().replace('-', '_')
170 task_class = globals()[task_classname]
171 task_inst = task_class(t[task_name])
172 if not ('machine' in t):
173 t['machine'] = None
174 machine = vmm.get(t['machine'])
175 if machine is None:
176 if t['machine'] is None:
177 t['machine'] = 'default'
178 logger.debug("Creating new machine {}.".format(t['machine']))
179 machine = vmm.create(t['machine'])
180 task_inst.set_machine(machine)
181 scenario_tasks.append(task_inst)
183 exit_code = 0
184 try:
185 for t in scenario_tasks:
186 t.run()
187 print("Scenario passed.")
188 except Exception as ex:
189 logger.exception("Scenario aborted: {}".format(ex))
190 print("Scenario aborted: {}".format(ex))
191 exit_code = 1
193 vmm.terminate(config.vterm_dump, config.last_screenshot)
194 sys.exit(exit_code)