xref: /openbmc/qemu/scripts/device-crash-test (revision 23ea4f30320bbd36a5d202ee469374ec3c747286)
1*23ea4f30SEduardo Habkost#!/usr/bin/env python2.7
2*23ea4f30SEduardo Habkost#
3*23ea4f30SEduardo Habkost#  Copyright (c) 2017 Red Hat Inc
4*23ea4f30SEduardo Habkost#
5*23ea4f30SEduardo Habkost# Author:
6*23ea4f30SEduardo Habkost#  Eduardo Habkost <ehabkost@redhat.com>
7*23ea4f30SEduardo Habkost#
8*23ea4f30SEduardo Habkost# This program is free software; you can redistribute it and/or modify
9*23ea4f30SEduardo Habkost# it under the terms of the GNU General Public License as published by
10*23ea4f30SEduardo Habkost# the Free Software Foundation; either version 2 of the License, or
11*23ea4f30SEduardo Habkost# (at your option) any later version.
12*23ea4f30SEduardo Habkost#
13*23ea4f30SEduardo Habkost# This program is distributed in the hope that it will be useful,
14*23ea4f30SEduardo Habkost# but WITHOUT ANY WARRANTY; without even the implied warranty of
15*23ea4f30SEduardo Habkost# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*23ea4f30SEduardo Habkost# GNU General Public License for more details.
17*23ea4f30SEduardo Habkost#
18*23ea4f30SEduardo Habkost# You should have received a copy of the GNU General Public License along
19*23ea4f30SEduardo Habkost# with this program; if not, write to the Free Software Foundation, Inc.,
20*23ea4f30SEduardo Habkost# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21*23ea4f30SEduardo Habkost
22*23ea4f30SEduardo Habkost"""
23*23ea4f30SEduardo HabkostRun QEMU with all combinations of -machine and -device types,
24*23ea4f30SEduardo Habkostcheck for crashes and unexpected errors.
25*23ea4f30SEduardo Habkost"""
26*23ea4f30SEduardo Habkost
27*23ea4f30SEduardo Habkostimport sys
28*23ea4f30SEduardo Habkostimport os
29*23ea4f30SEduardo Habkostimport glob
30*23ea4f30SEduardo Habkostimport logging
31*23ea4f30SEduardo Habkostimport traceback
32*23ea4f30SEduardo Habkostimport re
33*23ea4f30SEduardo Habkostimport random
34*23ea4f30SEduardo Habkostimport argparse
35*23ea4f30SEduardo Habkostfrom itertools import chain
36*23ea4f30SEduardo Habkost
37*23ea4f30SEduardo Habkostsys.path.append(os.path.join(os.path.dirname(__file__), '..', 'scripts'))
38*23ea4f30SEduardo Habkostfrom qemu import QEMUMachine
39*23ea4f30SEduardo Habkost
40*23ea4f30SEduardo Habkostlogger = logging.getLogger('device-crash-test')
41*23ea4f30SEduardo Habkostdbg = logger.debug
42*23ea4f30SEduardo Habkost
43*23ea4f30SEduardo Habkost
44*23ea4f30SEduardo Habkost# Purposes of the following whitelist:
45*23ea4f30SEduardo Habkost# * Avoiding verbose log messages when we find known non-fatal
46*23ea4f30SEduardo Habkost#   (exitcode=1) errors
47*23ea4f30SEduardo Habkost# * Avoiding fatal errors when we find known crashes
48*23ea4f30SEduardo Habkost# * Skipping machines/devices that are known not to work out of
49*23ea4f30SEduardo Habkost#   the box, when running in --quick mode
50*23ea4f30SEduardo Habkost#
51*23ea4f30SEduardo Habkost# Keeping the whitelist updated is desirable, but not required,
52*23ea4f30SEduardo Habkost# because unexpected cases where QEMU exits with exitcode=1 will
53*23ea4f30SEduardo Habkost# just trigger a INFO message.
54*23ea4f30SEduardo Habkost
55*23ea4f30SEduardo Habkost# Valid whitelist entry keys:
56*23ea4f30SEduardo Habkost# * accel: regexp, full match only
57*23ea4f30SEduardo Habkost# * machine: regexp, full match only
58*23ea4f30SEduardo Habkost# * device: regexp, full match only
59*23ea4f30SEduardo Habkost# * log: regexp, partial match allowed
60*23ea4f30SEduardo Habkost# * exitcode: if not present, defaults to 1. If None, matches any exitcode
61*23ea4f30SEduardo Habkost# * warn: if True, matching failures will be logged as warnings
62*23ea4f30SEduardo Habkost# * expected: if True, QEMU is expected to always fail every time
63*23ea4f30SEduardo Habkost#   when testing the corresponding test case
64*23ea4f30SEduardo Habkost# * loglevel: log level of log output when there's a match.
65*23ea4f30SEduardo HabkostERROR_WHITELIST = [
66*23ea4f30SEduardo Habkost    # Machines that won't work out of the box:
67*23ea4f30SEduardo Habkost    #             MACHINE                         | ERROR MESSAGE
68*23ea4f30SEduardo Habkost    {'machine':'niagara', 'expected':True},       # Unable to load a firmware for -M niagara
69*23ea4f30SEduardo Habkost    {'machine':'boston', 'expected':True},        # Please provide either a -kernel or -bios argument
70*23ea4f30SEduardo Habkost    {'machine':'leon3_generic', 'expected':True}, # Can't read bios image (null)
71*23ea4f30SEduardo Habkost
72*23ea4f30SEduardo Habkost    # devices that don't work out of the box because they require extra options to "-device DEV":
73*23ea4f30SEduardo Habkost    #            DEVICE                                    | ERROR MESSAGE
74*23ea4f30SEduardo Habkost    {'device':'.*-(i386|x86_64)-cpu', 'expected':True},    # CPU socket-id is not set
75*23ea4f30SEduardo Habkost    {'device':'ARM,bitband-memory', 'expected':True},      # source-memory property not set
76*23ea4f30SEduardo Habkost    {'device':'arm.cortex-a9-global-timer', 'expected':True}, # a9_gtimer_realize: num-cpu must be between 1 and 4
77*23ea4f30SEduardo Habkost    {'device':'arm_mptimer', 'expected':True},             # num-cpu must be between 1 and 4
78*23ea4f30SEduardo Habkost    {'device':'armv7m', 'expected':True},                  # memory property was not set
79*23ea4f30SEduardo Habkost    {'device':'aspeed.scu', 'expected':True},              # Unknown silicon revision: 0x0
80*23ea4f30SEduardo Habkost    {'device':'aspeed.sdmc', 'expected':True},             # Unknown silicon revision: 0x0
81*23ea4f30SEduardo Habkost    {'device':'bcm2835-dma', 'expected':True},             # bcm2835_dma_realize: required dma-mr link not found: Property '.dma-mr' not found
82*23ea4f30SEduardo Habkost    {'device':'bcm2835-fb', 'expected':True},              # bcm2835_fb_realize: required vcram-base property not set
83*23ea4f30SEduardo Habkost    {'device':'bcm2835-mbox', 'expected':True},            # bcm2835_mbox_realize: required mbox-mr link not found: Property '.mbox-mr' not found
84*23ea4f30SEduardo Habkost    {'device':'bcm2835-peripherals', 'expected':True},     # bcm2835_peripherals_realize: required ram link not found: Property '.ram' not found
85*23ea4f30SEduardo Habkost    {'device':'bcm2835-property', 'expected':True},        # bcm2835_property_realize: required fb link not found: Property '.fb' not found
86*23ea4f30SEduardo Habkost    {'device':'bcm2835_gpio', 'expected':True},            # bcm2835_gpio_realize: required sdhci link not found: Property '.sdbus-sdhci' not found
87*23ea4f30SEduardo Habkost    {'device':'bcm2836', 'expected':True},                 # bcm2836_realize: required ram link not found: Property '.ram' not found
88*23ea4f30SEduardo Habkost    {'device':'cfi.pflash01', 'expected':True},            # attribute "sector-length" not specified or zero.
89*23ea4f30SEduardo Habkost    {'device':'cfi.pflash02', 'expected':True},            # attribute "sector-length" not specified or zero.
90*23ea4f30SEduardo Habkost    {'device':'icp', 'expected':True},                     # icp_realize: required link 'xics' not found: Property '.xics' not found
91*23ea4f30SEduardo Habkost    {'device':'ics', 'expected':True},                     # ics_base_realize: required link 'xics' not found: Property '.xics' not found
92*23ea4f30SEduardo Habkost    # "-device ide-cd" does work on more recent QEMU versions, so it doesn't have expected=True
93*23ea4f30SEduardo Habkost    {'device':'ide-cd'},                                 # No drive specified
94*23ea4f30SEduardo Habkost    {'device':'ide-drive', 'expected':True},               # No drive specified
95*23ea4f30SEduardo Habkost    {'device':'ide-hd', 'expected':True},                  # No drive specified
96*23ea4f30SEduardo Habkost    {'device':'ipmi-bmc-extern', 'expected':True},         # IPMI external bmc requires chardev attribute
97*23ea4f30SEduardo Habkost    {'device':'isa-debugcon', 'expected':True},            # Can't create serial device, empty char device
98*23ea4f30SEduardo Habkost    {'device':'isa-ipmi-bt', 'expected':True},             # IPMI device requires a bmc attribute to be set
99*23ea4f30SEduardo Habkost    {'device':'isa-ipmi-kcs', 'expected':True},            # IPMI device requires a bmc attribute to be set
100*23ea4f30SEduardo Habkost    {'device':'isa-parallel', 'expected':True},            # Can't create serial device, empty char device
101*23ea4f30SEduardo Habkost    {'device':'isa-serial', 'expected':True},              # Can't create serial device, empty char device
102*23ea4f30SEduardo Habkost    {'device':'ivshmem', 'expected':True},                 # You must specify either 'shm' or 'chardev'
103*23ea4f30SEduardo Habkost    {'device':'ivshmem-doorbell', 'expected':True},        # You must specify a 'chardev'
104*23ea4f30SEduardo Habkost    {'device':'ivshmem-plain', 'expected':True},           # You must specify a 'memdev'
105*23ea4f30SEduardo Habkost    {'device':'kvm-pci-assign', 'expected':True},          # no host device specified
106*23ea4f30SEduardo Habkost    {'device':'loader', 'expected':True},                  # please include valid arguments
107*23ea4f30SEduardo Habkost    {'device':'nand', 'expected':True},                    # Unsupported NAND block size 0x1
108*23ea4f30SEduardo Habkost    {'device':'nvdimm', 'expected':True},                  # 'memdev' property is not set
109*23ea4f30SEduardo Habkost    {'device':'nvme', 'expected':True},                    # Device initialization failed
110*23ea4f30SEduardo Habkost    {'device':'pc-dimm', 'expected':True},                 # 'memdev' property is not set
111*23ea4f30SEduardo Habkost    {'device':'pci-bridge', 'expected':True},              # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0.
112*23ea4f30SEduardo Habkost    {'device':'pci-bridge-seat', 'expected':True},         # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0.
113*23ea4f30SEduardo Habkost    {'device':'pci-serial', 'expected':True},              # Can't create serial device, empty char device
114*23ea4f30SEduardo Habkost    {'device':'pci-serial-2x', 'expected':True},           # Can't create serial device, empty char device
115*23ea4f30SEduardo Habkost    {'device':'pci-serial-4x', 'expected':True},           # Can't create serial device, empty char device
116*23ea4f30SEduardo Habkost    {'device':'pxa2xx-dma', 'expected':True},              # channels value invalid
117*23ea4f30SEduardo Habkost    {'device':'pxb', 'expected':True},                     # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0.
118*23ea4f30SEduardo Habkost    {'device':'scsi-block', 'expected':True},              # drive property not set
119*23ea4f30SEduardo Habkost    {'device':'scsi-disk', 'expected':True},               # drive property not set
120*23ea4f30SEduardo Habkost    {'device':'scsi-generic', 'expected':True},            # drive property not set
121*23ea4f30SEduardo Habkost    {'device':'scsi-hd', 'expected':True},                 # drive property not set
122*23ea4f30SEduardo Habkost    {'device':'spapr-pci-host-bridge', 'expected':True},   # BUID not specified for PHB
123*23ea4f30SEduardo Habkost    {'device':'spapr-pci-vfio-host-bridge', 'expected':True}, # BUID not specified for PHB
124*23ea4f30SEduardo Habkost    {'device':'spapr-rng', 'expected':True},               # spapr-rng needs an RNG backend!
125*23ea4f30SEduardo Habkost    {'device':'spapr-vty', 'expected':True},               # chardev property not set
126*23ea4f30SEduardo Habkost    {'device':'tpm-tis', 'expected':True},                 # tpm_tis: backend driver with id (null) could not be found
127*23ea4f30SEduardo Habkost    {'device':'unimplemented-device', 'expected':True},    # property 'size' not specified or zero
128*23ea4f30SEduardo Habkost    {'device':'usb-braille', 'expected':True},             # Property chardev is required
129*23ea4f30SEduardo Habkost    {'device':'usb-mtp', 'expected':True},                 # x-root property must be configured
130*23ea4f30SEduardo Habkost    {'device':'usb-redir', 'expected':True},               # Parameter 'chardev' is missing
131*23ea4f30SEduardo Habkost    {'device':'usb-serial', 'expected':True},              # Property chardev is required
132*23ea4f30SEduardo Habkost    {'device':'usb-storage', 'expected':True},             # drive property not set
133*23ea4f30SEduardo Habkost    {'device':'vfio-amd-xgbe', 'expected':True},           # -device vfio-amd-xgbe: vfio error: wrong host device name
134*23ea4f30SEduardo Habkost    {'device':'vfio-calxeda-xgmac', 'expected':True},      # -device vfio-calxeda-xgmac: vfio error: wrong host device name
135*23ea4f30SEduardo Habkost    {'device':'vfio-pci', 'expected':True},                # No provided host device
136*23ea4f30SEduardo Habkost    {'device':'vfio-pci-igd-lpc-bridge', 'expected':True}, # VFIO dummy ISA/LPC bridge must have address 1f.0
137*23ea4f30SEduardo Habkost    {'device':'vhost-scsi.*', 'expected':True},            # vhost-scsi: missing wwpn
138*23ea4f30SEduardo Habkost    {'device':'vhost-vsock-device', 'expected':True},      # guest-cid property must be greater than 2
139*23ea4f30SEduardo Habkost    {'device':'vhost-vsock-pci', 'expected':True},         # guest-cid property must be greater than 2
140*23ea4f30SEduardo Habkost    {'device':'virtio-9p-ccw', 'expected':True},           # 9pfs device couldn't find fsdev with the id = NULL
141*23ea4f30SEduardo Habkost    {'device':'virtio-9p-device', 'expected':True},        # 9pfs device couldn't find fsdev with the id = NULL
142*23ea4f30SEduardo Habkost    {'device':'virtio-9p-pci', 'expected':True},           # 9pfs device couldn't find fsdev with the id = NULL
143*23ea4f30SEduardo Habkost    {'device':'virtio-blk-ccw', 'expected':True},          # drive property not set
144*23ea4f30SEduardo Habkost    {'device':'virtio-blk-device', 'expected':True},       # drive property not set
145*23ea4f30SEduardo Habkost    {'device':'virtio-blk-device', 'expected':True},       # drive property not set
146*23ea4f30SEduardo Habkost    {'device':'virtio-blk-pci', 'expected':True},          # drive property not set
147*23ea4f30SEduardo Habkost    {'device':'virtio-crypto-ccw', 'expected':True},       # 'cryptodev' parameter expects a valid object
148*23ea4f30SEduardo Habkost    {'device':'virtio-crypto-device', 'expected':True},    # 'cryptodev' parameter expects a valid object
149*23ea4f30SEduardo Habkost    {'device':'virtio-crypto-pci', 'expected':True},       # 'cryptodev' parameter expects a valid object
150*23ea4f30SEduardo Habkost    {'device':'virtio-input-host-device', 'expected':True}, # evdev property is required
151*23ea4f30SEduardo Habkost    {'device':'virtio-input-host-pci', 'expected':True},   # evdev property is required
152*23ea4f30SEduardo Habkost    {'device':'xen-pvdevice', 'expected':True},            # Device ID invalid, it must always be supplied
153*23ea4f30SEduardo Habkost    {'device':'vhost-vsock-ccw', 'expected':True},         # guest-cid property must be greater than 2
154*23ea4f30SEduardo Habkost    {'device':'ALTR.timer', 'expected':True},              # "clock-frequency" property must be provided
155*23ea4f30SEduardo Habkost    {'device':'zpci', 'expected':True},                    # target must be defined
156*23ea4f30SEduardo Habkost    {'device':'pnv-(occ|icp|lpc)', 'expected':True},       # required link 'xics' not found: Property '.xics' not found
157*23ea4f30SEduardo Habkost    {'device':'powernv-cpu-.*', 'expected':True},          # pnv_core_realize: required link 'xics' not found: Property '.xics' not found
158*23ea4f30SEduardo Habkost
159*23ea4f30SEduardo Habkost    # ioapic devices are already created by pc and will fail:
160*23ea4f30SEduardo Habkost    {'machine':'q35|pc.*', 'device':'kvm-ioapic', 'expected':True}, # Only 1 ioapics allowed
161*23ea4f30SEduardo Habkost    {'machine':'q35|pc.*', 'device':'ioapic', 'expected':True},     # Only 1 ioapics allowed
162*23ea4f30SEduardo Habkost
163*23ea4f30SEduardo Habkost    # KVM-specific devices shouldn't be tried without accel=kvm:
164*23ea4f30SEduardo Habkost    {'accel':'(?!kvm).*', 'device':'kvmclock', 'expected':True},
165*23ea4f30SEduardo Habkost    {'accel':'(?!kvm).*', 'device':'kvm-pci-assign', 'expected':True},
166*23ea4f30SEduardo Habkost
167*23ea4f30SEduardo Habkost    # xen-specific machines and devices:
168*23ea4f30SEduardo Habkost    {'accel':'(?!xen).*', 'machine':'xen.*', 'expected':True},
169*23ea4f30SEduardo Habkost    {'accel':'(?!xen).*', 'device':'xen-.*', 'expected':True},
170*23ea4f30SEduardo Habkost
171*23ea4f30SEduardo Habkost    # this fails on some machine-types, but not all, so they don't have expected=True:
172*23ea4f30SEduardo Habkost    {'device':'vmgenid'}, # vmgenid requires DMA write support in fw_cfg, which this machine type does not provide
173*23ea4f30SEduardo Habkost
174*23ea4f30SEduardo Habkost    # Silence INFO messages for errors that are common on multiple
175*23ea4f30SEduardo Habkost    # devices/machines:
176*23ea4f30SEduardo Habkost    {'log':r"No '[\w-]+' bus found for device '[\w-]+'"},
177*23ea4f30SEduardo Habkost    {'log':r"images* must be given with the 'pflash' parameter"},
178*23ea4f30SEduardo Habkost    {'log':r"(Guest|ROM|Flash|Kernel) image must be specified"},
179*23ea4f30SEduardo Habkost    {'log':r"[cC]ould not load [\w ]+ (BIOS|bios) '[\w-]+\.bin'"},
180*23ea4f30SEduardo Habkost    {'log':r"Couldn't find rom image '[\w-]+\.bin'"},
181*23ea4f30SEduardo Habkost    {'log':r"speed mismatch trying to attach usb device"},
182*23ea4f30SEduardo Habkost    {'log':r"Can't create a second ISA bus"},
183*23ea4f30SEduardo Habkost    {'log':r"duplicate fw_cfg file name"},
184*23ea4f30SEduardo Habkost    # sysbus-related error messages: most machines reject most dynamic sysbus devices:
185*23ea4f30SEduardo Habkost    {'log':r"Option '-device [\w.,-]+' cannot be handled by this machine"},
186*23ea4f30SEduardo Habkost    {'log':r"Device [\w.,-]+ is not supported by this machine yet"},
187*23ea4f30SEduardo Habkost    {'log':r"Device [\w.,-]+ can not be dynamically instantiated"},
188*23ea4f30SEduardo Habkost    {'log':r"Platform Bus: Can not fit MMIO region of size "},
189*23ea4f30SEduardo Habkost    # other more specific errors we will ignore:
190*23ea4f30SEduardo Habkost    {'device':'allwinner-a10', 'log':"Unsupported NIC model:"},
191*23ea4f30SEduardo Habkost    {'device':'.*-spapr-cpu-core', 'log':r"CPU core type should be"},
192*23ea4f30SEduardo Habkost    {'log':r"MSI(-X)? is not supported by interrupt controller"},
193*23ea4f30SEduardo Habkost    {'log':r"pxb-pcie? devices cannot reside on a PCIe? bus"},
194*23ea4f30SEduardo Habkost    {'log':r"Ignoring smp_cpus value"},
195*23ea4f30SEduardo Habkost    {'log':r"sd_init failed: Drive 'sd0' is already in use because it has been automatically connected to another device"},
196*23ea4f30SEduardo Habkost    {'log':r"This CPU requires a smaller page size than the system is using"},
197*23ea4f30SEduardo Habkost    {'log':r"MSI-X support is mandatory in the S390 architecture"},
198*23ea4f30SEduardo Habkost    {'log':r"rom check and register reset failed"},
199*23ea4f30SEduardo Habkost    {'log':r"Unable to initialize GIC, CPUState for CPU#0 not valid"},
200*23ea4f30SEduardo Habkost    {'log':r"Multiple VT220 operator consoles are not supported"},
201*23ea4f30SEduardo Habkost    {'log':r"core 0 already populated"},
202*23ea4f30SEduardo Habkost    {'log':r"could not find stage1 bootloader"},
203*23ea4f30SEduardo Habkost
204*23ea4f30SEduardo Habkost    # other exitcode=1 failures not listed above will just generate INFO messages:
205*23ea4f30SEduardo Habkost    {'exitcode':1, 'loglevel':logging.INFO},
206*23ea4f30SEduardo Habkost
207*23ea4f30SEduardo Habkost    # KNOWN CRASHES:
208*23ea4f30SEduardo Habkost    # Known crashes will generate error messages, but won't be fatal.
209*23ea4f30SEduardo Habkost    # Those entries must be removed once we fix the crashes.
210*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"Device 'serial0' is in use", 'loglevel':logging.ERROR},
211*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"spapr_rtas_register: Assertion .*rtas_table\[token\]\.name.* failed", 'loglevel':logging.ERROR},
212*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"qemu_net_client_setup: Assertion `!peer->peer' failed", 'loglevel':logging.ERROR},
213*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r'RAMBlock "[\w.-]+" already registered', 'loglevel':logging.ERROR},
214*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"find_ram_offset: Assertion `size != 0' failed.", 'loglevel':logging.ERROR},
215*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"puv3_load_kernel: Assertion `kernel_filename != NULL' failed", 'loglevel':logging.ERROR},
216*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"add_cpreg_to_hashtable: code should not be reached", 'loglevel':logging.ERROR},
217*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"qemu_alloc_display: Assertion `surface->image != NULL' failed", 'loglevel':logging.ERROR},
218*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"Unexpected error in error_set_from_qdev_prop_error", 'loglevel':logging.ERROR},
219*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"Object .* is not an instance of type spapr-machine", 'loglevel':logging.ERROR},
220*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"Object .* is not an instance of type generic-pc-machine", 'loglevel':logging.ERROR},
221*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"Object .* is not an instance of type e500-ccsr", 'loglevel':logging.ERROR},
222*23ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"vmstate_register_with_alias_id: Assertion `!se->compat || se->instance_id == 0' failed", 'loglevel':logging.ERROR},
223*23ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'stm32f205-soc', 'loglevel':logging.ERROR, 'expected':True},
224*23ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'xlnx,zynqmp', 'loglevel':logging.ERROR, 'expected':True},
225*23ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'mips-cps', 'loglevel':logging.ERROR, 'expected':True},
226*23ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'gus', 'loglevel':logging.ERROR, 'expected':True},
227*23ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'a9mpcore_priv', 'loglevel':logging.ERROR, 'expected':True},
228*23ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'a15mpcore_priv', 'loglevel':logging.ERROR, 'expected':True},
229*23ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'isa-serial', 'loglevel':logging.ERROR, 'expected':True},
230*23ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'sb16', 'loglevel':logging.ERROR, 'expected':True},
231*23ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'cs4231a', 'loglevel':logging.ERROR, 'expected':True},
232*23ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'arm-gicv3', 'loglevel':logging.ERROR, 'expected':True},
233*23ea4f30SEduardo Habkost    {'exitcode':-11, 'machine':'isapc', 'device':'.*-iommu', 'loglevel':logging.ERROR, 'expected':True},
234*23ea4f30SEduardo Habkost
235*23ea4f30SEduardo Habkost    # everything else (including SIGABRT and SIGSEGV) will be a fatal error:
236*23ea4f30SEduardo Habkost    {'exitcode':None, 'fatal':True, 'loglevel':logging.FATAL},
237*23ea4f30SEduardo Habkost]
238*23ea4f30SEduardo Habkost
239*23ea4f30SEduardo Habkost
240*23ea4f30SEduardo Habkostdef whitelistTestCaseMatch(wl, t):
241*23ea4f30SEduardo Habkost    """Check if a test case specification can match a whitelist entry
242*23ea4f30SEduardo Habkost
243*23ea4f30SEduardo Habkost    This only checks if a whitelist entry is a candidate match
244*23ea4f30SEduardo Habkost    for a given test case, it won't check if the test case
245*23ea4f30SEduardo Habkost    results/output match the entry.  See whitelistResultMatch().
246*23ea4f30SEduardo Habkost    """
247*23ea4f30SEduardo Habkost    return (('machine' not in wl or
248*23ea4f30SEduardo Habkost             'machine' not in t or
249*23ea4f30SEduardo Habkost             re.match(wl['machine'] + '$', t['machine'])) and
250*23ea4f30SEduardo Habkost            ('accel' not in wl or
251*23ea4f30SEduardo Habkost             'accel' not in t or
252*23ea4f30SEduardo Habkost             re.match(wl['accel'] + '$', t['accel'])) and
253*23ea4f30SEduardo Habkost            ('device' not in wl or
254*23ea4f30SEduardo Habkost             'device' not in t or
255*23ea4f30SEduardo Habkost             re.match(wl['device'] + '$', t['device'])))
256*23ea4f30SEduardo Habkost
257*23ea4f30SEduardo Habkost
258*23ea4f30SEduardo Habkostdef whitelistCandidates(t):
259*23ea4f30SEduardo Habkost    """Generate the list of candidates that can match a test case"""
260*23ea4f30SEduardo Habkost    for i, wl in enumerate(ERROR_WHITELIST):
261*23ea4f30SEduardo Habkost        if whitelistTestCaseMatch(wl, t):
262*23ea4f30SEduardo Habkost            yield (i, wl)
263*23ea4f30SEduardo Habkost
264*23ea4f30SEduardo Habkost
265*23ea4f30SEduardo Habkostdef findExpectedResult(t):
266*23ea4f30SEduardo Habkost    """Check if there's an expected=True whitelist entry for a test case
267*23ea4f30SEduardo Habkost
268*23ea4f30SEduardo Habkost    Returns (i, wl) tuple, where i is the index in
269*23ea4f30SEduardo Habkost    ERROR_WHITELIST and wl is the whitelist entry itself.
270*23ea4f30SEduardo Habkost    """
271*23ea4f30SEduardo Habkost    for i, wl in whitelistCandidates(t):
272*23ea4f30SEduardo Habkost        if wl.get('expected'):
273*23ea4f30SEduardo Habkost            return (i, wl)
274*23ea4f30SEduardo Habkost
275*23ea4f30SEduardo Habkost
276*23ea4f30SEduardo Habkostdef whitelistResultMatch(wl, r):
277*23ea4f30SEduardo Habkost    """Check if test case results/output match a whitelist entry
278*23ea4f30SEduardo Habkost
279*23ea4f30SEduardo Habkost    It is valid to call this function only if
280*23ea4f30SEduardo Habkost    whitelistTestCaseMatch() is True for the entry (e.g. on
281*23ea4f30SEduardo Habkost    entries returned by whitelistCandidates())
282*23ea4f30SEduardo Habkost    """
283*23ea4f30SEduardo Habkost    assert whitelistTestCaseMatch(wl, r['testcase'])
284*23ea4f30SEduardo Habkost    return ((wl.get('exitcode', 1) is None or
285*23ea4f30SEduardo Habkost             r['exitcode'] == wl.get('exitcode', 1)) and
286*23ea4f30SEduardo Habkost            ('log' not in wl or
287*23ea4f30SEduardo Habkost             re.search(wl['log'], r['log'], re.MULTILINE)))
288*23ea4f30SEduardo Habkost
289*23ea4f30SEduardo Habkost
290*23ea4f30SEduardo Habkostdef checkResultWhitelist(r):
291*23ea4f30SEduardo Habkost    """Look up whitelist entry for a given test case result
292*23ea4f30SEduardo Habkost
293*23ea4f30SEduardo Habkost    Returns (i, wl) tuple, where i is the index in
294*23ea4f30SEduardo Habkost    ERROR_WHITELIST and wl is the whitelist entry itself.
295*23ea4f30SEduardo Habkost    """
296*23ea4f30SEduardo Habkost    for i, wl in whitelistCandidates(r['testcase']):
297*23ea4f30SEduardo Habkost        if whitelistResultMatch(wl, r):
298*23ea4f30SEduardo Habkost            return i, wl
299*23ea4f30SEduardo Habkost
300*23ea4f30SEduardo Habkost    raise Exception("this should never happen")
301*23ea4f30SEduardo Habkost
302*23ea4f30SEduardo Habkost
303*23ea4f30SEduardo Habkostdef qemuOptsEscape(s):
304*23ea4f30SEduardo Habkost    """Escape option value QemuOpts"""
305*23ea4f30SEduardo Habkost    return s.replace(",", ",,")
306*23ea4f30SEduardo Habkost
307*23ea4f30SEduardo Habkost
308*23ea4f30SEduardo Habkostdef formatTestCase(t):
309*23ea4f30SEduardo Habkost    """Format test case info as "key=value key=value" for prettier logging output"""
310*23ea4f30SEduardo Habkost    return ' '.join('%s=%s' % (k, v) for k, v in t.items())
311*23ea4f30SEduardo Habkost
312*23ea4f30SEduardo Habkost
313*23ea4f30SEduardo Habkostdef qomListTypeNames(vm, **kwargs):
314*23ea4f30SEduardo Habkost    """Run qom-list-types QMP command, return type names"""
315*23ea4f30SEduardo Habkost    types = vm.command('qom-list-types', **kwargs)
316*23ea4f30SEduardo Habkost    return [t['name'] for t in types]
317*23ea4f30SEduardo Habkost
318*23ea4f30SEduardo Habkost
319*23ea4f30SEduardo Habkostdef infoQDM(vm):
320*23ea4f30SEduardo Habkost    """Parse 'info qdm' output"""
321*23ea4f30SEduardo Habkost    args = {'command-line': 'info qdm'}
322*23ea4f30SEduardo Habkost    devhelp = vm.command('human-monitor-command', **args)
323*23ea4f30SEduardo Habkost    for l in devhelp.split('\n'):
324*23ea4f30SEduardo Habkost        l = l.strip()
325*23ea4f30SEduardo Habkost        if l == '' or l.endswith(':'):
326*23ea4f30SEduardo Habkost            continue
327*23ea4f30SEduardo Habkost        d = {'name': re.search(r'name "([^"]+)"', l).group(1),
328*23ea4f30SEduardo Habkost             'no-user': (re.search(', no-user', l) is not None)}
329*23ea4f30SEduardo Habkost        yield d
330*23ea4f30SEduardo Habkost
331*23ea4f30SEduardo Habkost
332*23ea4f30SEduardo Habkostclass QemuBinaryInfo(object):
333*23ea4f30SEduardo Habkost    def __init__(self, binary, devtype):
334*23ea4f30SEduardo Habkost        if devtype is None:
335*23ea4f30SEduardo Habkost            devtype = 'device'
336*23ea4f30SEduardo Habkost
337*23ea4f30SEduardo Habkost        self.binary = binary
338*23ea4f30SEduardo Habkost        self._machine_info = {}
339*23ea4f30SEduardo Habkost
340*23ea4f30SEduardo Habkost        dbg("devtype: %r", devtype)
341*23ea4f30SEduardo Habkost        args = ['-S', '-machine', 'none,accel=kvm:tcg']
342*23ea4f30SEduardo Habkost        dbg("querying info for QEMU binary: %s", binary)
343*23ea4f30SEduardo Habkost        vm = QEMUMachine(binary=binary, args=args)
344*23ea4f30SEduardo Habkost        vm.launch()
345*23ea4f30SEduardo Habkost        try:
346*23ea4f30SEduardo Habkost            self.alldevs = set(qomListTypeNames(vm, implements=devtype, abstract=False))
347*23ea4f30SEduardo Habkost            # there's no way to query DeviceClass::user_creatable using QMP,
348*23ea4f30SEduardo Habkost            # so use 'info qdm':
349*23ea4f30SEduardo Habkost            self.no_user_devs = set([d['name'] for d in infoQDM(vm, ) if d['no-user']])
350*23ea4f30SEduardo Habkost            self.machines = list(m['name'] for m in vm.command('query-machines'))
351*23ea4f30SEduardo Habkost            self.user_devs = self.alldevs.difference(self.no_user_devs)
352*23ea4f30SEduardo Habkost            self.kvm_available = vm.command('query-kvm')['enabled']
353*23ea4f30SEduardo Habkost        finally:
354*23ea4f30SEduardo Habkost            vm.shutdown()
355*23ea4f30SEduardo Habkost
356*23ea4f30SEduardo Habkost    def machineInfo(self, machine):
357*23ea4f30SEduardo Habkost        """Query for information on a specific machine-type
358*23ea4f30SEduardo Habkost
359*23ea4f30SEduardo Habkost        Results are cached internally, in case the same machine-
360*23ea4f30SEduardo Habkost        type is queried multiple times.
361*23ea4f30SEduardo Habkost        """
362*23ea4f30SEduardo Habkost        if machine in self._machine_info:
363*23ea4f30SEduardo Habkost            return self._machine_info[machine]
364*23ea4f30SEduardo Habkost
365*23ea4f30SEduardo Habkost        mi = {}
366*23ea4f30SEduardo Habkost        args = ['-S', '-machine', '%s' % (machine)]
367*23ea4f30SEduardo Habkost        dbg("querying machine info for binary=%s machine=%s", self.binary, machine)
368*23ea4f30SEduardo Habkost        vm = QEMUMachine(binary=self.binary, args=args)
369*23ea4f30SEduardo Habkost        try:
370*23ea4f30SEduardo Habkost            vm.launch()
371*23ea4f30SEduardo Habkost            mi['runnable'] = True
372*23ea4f30SEduardo Habkost        except KeyboardInterrupt:
373*23ea4f30SEduardo Habkost            raise
374*23ea4f30SEduardo Habkost        except:
375*23ea4f30SEduardo Habkost            dbg("exception trying to run binary=%s machine=%s", self.binary, machine, exc_info=sys.exc_info())
376*23ea4f30SEduardo Habkost            dbg("log: %r", vm.get_log())
377*23ea4f30SEduardo Habkost            mi['runnable'] = False
378*23ea4f30SEduardo Habkost
379*23ea4f30SEduardo Habkost        vm.shutdown()
380*23ea4f30SEduardo Habkost        self._machine_info[machine] = mi
381*23ea4f30SEduardo Habkost        return mi
382*23ea4f30SEduardo Habkost
383*23ea4f30SEduardo Habkost
384*23ea4f30SEduardo HabkostBINARY_INFO = {}
385*23ea4f30SEduardo Habkost
386*23ea4f30SEduardo Habkost
387*23ea4f30SEduardo Habkostdef getBinaryInfo(args, binary):
388*23ea4f30SEduardo Habkost    if binary not in BINARY_INFO:
389*23ea4f30SEduardo Habkost        BINARY_INFO[binary] = QemuBinaryInfo(binary, args.devtype)
390*23ea4f30SEduardo Habkost    return BINARY_INFO[binary]
391*23ea4f30SEduardo Habkost
392*23ea4f30SEduardo Habkost
393*23ea4f30SEduardo Habkostdef checkOneCase(args, testcase):
394*23ea4f30SEduardo Habkost    """Check one specific case
395*23ea4f30SEduardo Habkost
396*23ea4f30SEduardo Habkost    Returns a dictionary containing failure information on error,
397*23ea4f30SEduardo Habkost    or None on success
398*23ea4f30SEduardo Habkost    """
399*23ea4f30SEduardo Habkost    binary = testcase['binary']
400*23ea4f30SEduardo Habkost    accel = testcase['accel']
401*23ea4f30SEduardo Habkost    machine = testcase['machine']
402*23ea4f30SEduardo Habkost    device = testcase['device']
403*23ea4f30SEduardo Habkost
404*23ea4f30SEduardo Habkost    dbg("will test: %r", testcase)
405*23ea4f30SEduardo Habkost
406*23ea4f30SEduardo Habkost    args = ['-S', '-machine', '%s,accel=%s' % (machine, accel),
407*23ea4f30SEduardo Habkost            '-device', qemuOptsEscape(device)]
408*23ea4f30SEduardo Habkost    cmdline = ' '.join([binary] + args)
409*23ea4f30SEduardo Habkost    dbg("will launch QEMU: %s", cmdline)
410*23ea4f30SEduardo Habkost    vm = QEMUMachine(binary=binary, args=args)
411*23ea4f30SEduardo Habkost
412*23ea4f30SEduardo Habkost    exc_traceback = None
413*23ea4f30SEduardo Habkost    try:
414*23ea4f30SEduardo Habkost        vm.launch()
415*23ea4f30SEduardo Habkost    except KeyboardInterrupt:
416*23ea4f30SEduardo Habkost        raise
417*23ea4f30SEduardo Habkost    except:
418*23ea4f30SEduardo Habkost        exc_traceback = traceback.format_exc()
419*23ea4f30SEduardo Habkost        dbg("Exception while running test case")
420*23ea4f30SEduardo Habkost    finally:
421*23ea4f30SEduardo Habkost        vm.shutdown()
422*23ea4f30SEduardo Habkost        ec = vm.exitcode()
423*23ea4f30SEduardo Habkost        log = vm.get_log()
424*23ea4f30SEduardo Habkost
425*23ea4f30SEduardo Habkost    if exc_traceback is not None or ec != 0:
426*23ea4f30SEduardo Habkost        return {'exc_traceback':exc_traceback,
427*23ea4f30SEduardo Habkost                'exitcode':ec,
428*23ea4f30SEduardo Habkost                'log':log,
429*23ea4f30SEduardo Habkost                'testcase':testcase,
430*23ea4f30SEduardo Habkost                'cmdline':cmdline}
431*23ea4f30SEduardo Habkost
432*23ea4f30SEduardo Habkost
433*23ea4f30SEduardo Habkostdef binariesToTest(args, testcase):
434*23ea4f30SEduardo Habkost    if args.qemu:
435*23ea4f30SEduardo Habkost        r = args.qemu
436*23ea4f30SEduardo Habkost    else:
437*23ea4f30SEduardo Habkost        r = glob.glob('./*-softmmu/qemu-system-*')
438*23ea4f30SEduardo Habkost    return r
439*23ea4f30SEduardo Habkost
440*23ea4f30SEduardo Habkost
441*23ea4f30SEduardo Habkostdef accelsToTest(args, testcase):
442*23ea4f30SEduardo Habkost    if getBinaryInfo(args, testcase['binary']).kvm_available:
443*23ea4f30SEduardo Habkost        yield 'kvm'
444*23ea4f30SEduardo Habkost    yield 'tcg'
445*23ea4f30SEduardo Habkost
446*23ea4f30SEduardo Habkost
447*23ea4f30SEduardo Habkostdef machinesToTest(args, testcase):
448*23ea4f30SEduardo Habkost    return getBinaryInfo(args, testcase['binary']).machines
449*23ea4f30SEduardo Habkost
450*23ea4f30SEduardo Habkost
451*23ea4f30SEduardo Habkostdef devicesToTest(args, testcase):
452*23ea4f30SEduardo Habkost    return getBinaryInfo(args, testcase['binary']).user_devs
453*23ea4f30SEduardo Habkost
454*23ea4f30SEduardo Habkost
455*23ea4f30SEduardo HabkostTESTCASE_VARIABLES = [
456*23ea4f30SEduardo Habkost    ('binary', binariesToTest),
457*23ea4f30SEduardo Habkost    ('accel', accelsToTest),
458*23ea4f30SEduardo Habkost    ('machine', machinesToTest),
459*23ea4f30SEduardo Habkost    ('device', devicesToTest),
460*23ea4f30SEduardo Habkost]
461*23ea4f30SEduardo Habkost
462*23ea4f30SEduardo Habkost
463*23ea4f30SEduardo Habkostdef genCases1(args, testcases, var, fn):
464*23ea4f30SEduardo Habkost    """Generate new testcases for one variable
465*23ea4f30SEduardo Habkost
466*23ea4f30SEduardo Habkost    If an existing item already has a variable set, don't
467*23ea4f30SEduardo Habkost    generate new items and just return it directly. This
468*23ea4f30SEduardo Habkost    allows the "-t" command-line option to be used to choose
469*23ea4f30SEduardo Habkost    a specific test case.
470*23ea4f30SEduardo Habkost    """
471*23ea4f30SEduardo Habkost    for testcase in testcases:
472*23ea4f30SEduardo Habkost        if var in testcase:
473*23ea4f30SEduardo Habkost            yield testcase.copy()
474*23ea4f30SEduardo Habkost        else:
475*23ea4f30SEduardo Habkost            for i in fn(args, testcase):
476*23ea4f30SEduardo Habkost                t = testcase.copy()
477*23ea4f30SEduardo Habkost                t[var] = i
478*23ea4f30SEduardo Habkost                yield t
479*23ea4f30SEduardo Habkost
480*23ea4f30SEduardo Habkost
481*23ea4f30SEduardo Habkostdef genCases(args, testcase):
482*23ea4f30SEduardo Habkost    """Generate test cases for all variables
483*23ea4f30SEduardo Habkost    """
484*23ea4f30SEduardo Habkost    cases = [testcase.copy()]
485*23ea4f30SEduardo Habkost    for var, fn in TESTCASE_VARIABLES:
486*23ea4f30SEduardo Habkost        dbg("var: %r, fn: %r", var, fn)
487*23ea4f30SEduardo Habkost        cases = genCases1(args, cases, var, fn)
488*23ea4f30SEduardo Habkost    return cases
489*23ea4f30SEduardo Habkost
490*23ea4f30SEduardo Habkost
491*23ea4f30SEduardo Habkostdef casesToTest(args, testcase):
492*23ea4f30SEduardo Habkost    cases = genCases(args, testcase)
493*23ea4f30SEduardo Habkost    if args.random:
494*23ea4f30SEduardo Habkost        cases = list(cases)
495*23ea4f30SEduardo Habkost        cases = random.sample(cases, min(args.random, len(cases)))
496*23ea4f30SEduardo Habkost    if args.debug:
497*23ea4f30SEduardo Habkost        cases = list(cases)
498*23ea4f30SEduardo Habkost        dbg("%d test cases to test", len(cases))
499*23ea4f30SEduardo Habkost    if args.shuffle:
500*23ea4f30SEduardo Habkost        cases = list(cases)
501*23ea4f30SEduardo Habkost        random.shuffle(cases)
502*23ea4f30SEduardo Habkost    return cases
503*23ea4f30SEduardo Habkost
504*23ea4f30SEduardo Habkost
505*23ea4f30SEduardo Habkostdef logFailure(f, level):
506*23ea4f30SEduardo Habkost    t = f['testcase']
507*23ea4f30SEduardo Habkost    logger.log(level, "failed: %s", formatTestCase(t))
508*23ea4f30SEduardo Habkost    logger.log(level, "cmdline: %s", f['cmdline'])
509*23ea4f30SEduardo Habkost    for l in f['log'].strip().split('\n'):
510*23ea4f30SEduardo Habkost        logger.log(level, "log: %s", l)
511*23ea4f30SEduardo Habkost    logger.log(level, "exit code: %r", f['exitcode'])
512*23ea4f30SEduardo Habkost    if f['exc_traceback']:
513*23ea4f30SEduardo Habkost        logger.log(level, "exception:")
514*23ea4f30SEduardo Habkost        for l in f['exc_traceback'].split('\n'):
515*23ea4f30SEduardo Habkost            logger.log(level, "  %s", l.rstrip('\n'))
516*23ea4f30SEduardo Habkost
517*23ea4f30SEduardo Habkost
518*23ea4f30SEduardo Habkostdef main():
519*23ea4f30SEduardo Habkost    parser = argparse.ArgumentParser(description="QEMU -device crash test")
520*23ea4f30SEduardo Habkost    parser.add_argument('-t', metavar='KEY=VALUE', nargs='*',
521*23ea4f30SEduardo Habkost                        help="Limit test cases to KEY=VALUE",
522*23ea4f30SEduardo Habkost                        action='append', dest='testcases', default=[])
523*23ea4f30SEduardo Habkost    parser.add_argument('-d', '--debug', action='store_true',
524*23ea4f30SEduardo Habkost                        help='debug output')
525*23ea4f30SEduardo Habkost    parser.add_argument('-v', '--verbose', action='store_true', default=True,
526*23ea4f30SEduardo Habkost                        help='verbose output')
527*23ea4f30SEduardo Habkost    parser.add_argument('-q', '--quiet', dest='verbose', action='store_false',
528*23ea4f30SEduardo Habkost                        help='non-verbose output')
529*23ea4f30SEduardo Habkost    parser.add_argument('-r', '--random', type=int, metavar='COUNT',
530*23ea4f30SEduardo Habkost                        help='run a random sample of COUNT test cases',
531*23ea4f30SEduardo Habkost                        default=0)
532*23ea4f30SEduardo Habkost    parser.add_argument('--shuffle', action='store_true',
533*23ea4f30SEduardo Habkost                        help='Run test cases in random order')
534*23ea4f30SEduardo Habkost    parser.add_argument('--dry-run', action='store_true',
535*23ea4f30SEduardo Habkost                        help="Don't run any tests, just generate list")
536*23ea4f30SEduardo Habkost    parser.add_argument('-D', '--devtype', metavar='TYPE',
537*23ea4f30SEduardo Habkost                        help="Test only device types that implement TYPE")
538*23ea4f30SEduardo Habkost    parser.add_argument('-Q', '--quick', action='store_true', default=True,
539*23ea4f30SEduardo Habkost                        help="Quick mode: skip test cases that are expected to fail")
540*23ea4f30SEduardo Habkost    parser.add_argument('-F', '--full', action='store_false', dest='quick',
541*23ea4f30SEduardo Habkost                        help="Full mode: test cases that are expected to fail")
542*23ea4f30SEduardo Habkost    parser.add_argument('--strict', action='store_true', dest='strict',
543*23ea4f30SEduardo Habkost                        help="Treat all warnings as fatal")
544*23ea4f30SEduardo Habkost    parser.add_argument('qemu', nargs='*', metavar='QEMU',
545*23ea4f30SEduardo Habkost                        help='QEMU binary to run')
546*23ea4f30SEduardo Habkost    args = parser.parse_args()
547*23ea4f30SEduardo Habkost
548*23ea4f30SEduardo Habkost    if args.debug:
549*23ea4f30SEduardo Habkost        lvl = logging.DEBUG
550*23ea4f30SEduardo Habkost    elif args.verbose:
551*23ea4f30SEduardo Habkost        lvl = logging.INFO
552*23ea4f30SEduardo Habkost    else:
553*23ea4f30SEduardo Habkost        lvl = logging.WARN
554*23ea4f30SEduardo Habkost    logging.basicConfig(stream=sys.stdout, level=lvl, format='%(levelname)s: %(message)s')
555*23ea4f30SEduardo Habkost
556*23ea4f30SEduardo Habkost    fatal_failures = []
557*23ea4f30SEduardo Habkost    wl_stats = {}
558*23ea4f30SEduardo Habkost    skipped = 0
559*23ea4f30SEduardo Habkost    total = 0
560*23ea4f30SEduardo Habkost
561*23ea4f30SEduardo Habkost    tc = {}
562*23ea4f30SEduardo Habkost    dbg("testcases: %r", args.testcases)
563*23ea4f30SEduardo Habkost    if args.testcases:
564*23ea4f30SEduardo Habkost        for t in chain(*args.testcases):
565*23ea4f30SEduardo Habkost            for kv in t.split():
566*23ea4f30SEduardo Habkost                k, v = kv.split('=', 1)
567*23ea4f30SEduardo Habkost                tc[k] = v
568*23ea4f30SEduardo Habkost
569*23ea4f30SEduardo Habkost    if len(binariesToTest(args, tc)) == 0:
570*23ea4f30SEduardo Habkost        print >>sys.stderr, "No QEMU binary found"
571*23ea4f30SEduardo Habkost        parser.print_usage(sys.stderr)
572*23ea4f30SEduardo Habkost        return 1
573*23ea4f30SEduardo Habkost
574*23ea4f30SEduardo Habkost    for t in casesToTest(args, tc):
575*23ea4f30SEduardo Habkost        logger.info("running test case: %s", formatTestCase(t))
576*23ea4f30SEduardo Habkost        total += 1
577*23ea4f30SEduardo Habkost
578*23ea4f30SEduardo Habkost        expected_match = findExpectedResult(t)
579*23ea4f30SEduardo Habkost        if (args.quick and
580*23ea4f30SEduardo Habkost                (expected_match or
581*23ea4f30SEduardo Habkost                 not getBinaryInfo(args, t['binary']).machineInfo(t['machine'])['runnable'])):
582*23ea4f30SEduardo Habkost            dbg("skipped: %s", formatTestCase(t))
583*23ea4f30SEduardo Habkost            skipped += 1
584*23ea4f30SEduardo Habkost            continue
585*23ea4f30SEduardo Habkost
586*23ea4f30SEduardo Habkost        if args.dry_run:
587*23ea4f30SEduardo Habkost            continue
588*23ea4f30SEduardo Habkost
589*23ea4f30SEduardo Habkost        try:
590*23ea4f30SEduardo Habkost            f = checkOneCase(args, t)
591*23ea4f30SEduardo Habkost        except KeyboardInterrupt:
592*23ea4f30SEduardo Habkost            break
593*23ea4f30SEduardo Habkost
594*23ea4f30SEduardo Habkost        if f:
595*23ea4f30SEduardo Habkost            i, wl = checkResultWhitelist(f)
596*23ea4f30SEduardo Habkost            dbg("testcase: %r, whitelist match: %r", t, wl)
597*23ea4f30SEduardo Habkost            wl_stats.setdefault(i, []).append(f)
598*23ea4f30SEduardo Habkost            level = wl.get('loglevel', logging.DEBUG)
599*23ea4f30SEduardo Habkost            logFailure(f, level)
600*23ea4f30SEduardo Habkost            if wl.get('fatal') or (args.strict and level >= logging.WARN):
601*23ea4f30SEduardo Habkost                fatal_failures.append(f)
602*23ea4f30SEduardo Habkost        else:
603*23ea4f30SEduardo Habkost            dbg("success: %s", formatTestCase(t))
604*23ea4f30SEduardo Habkost            if expected_match:
605*23ea4f30SEduardo Habkost                logger.warn("Didn't fail as expected: %s", formatTestCase(t))
606*23ea4f30SEduardo Habkost
607*23ea4f30SEduardo Habkost    logger.info("Total: %d test cases", total)
608*23ea4f30SEduardo Habkost    if skipped:
609*23ea4f30SEduardo Habkost        logger.info("Skipped %d test cases", skipped)
610*23ea4f30SEduardo Habkost
611*23ea4f30SEduardo Habkost    if args.debug:
612*23ea4f30SEduardo Habkost        stats = sorted([(len(wl_stats.get(i, [])), wl) for i, wl in enumerate(ERROR_WHITELIST)])
613*23ea4f30SEduardo Habkost        for count, wl in stats:
614*23ea4f30SEduardo Habkost            dbg("whitelist entry stats: %d: %r", count, wl)
615*23ea4f30SEduardo Habkost
616*23ea4f30SEduardo Habkost    if fatal_failures:
617*23ea4f30SEduardo Habkost        for f in fatal_failures:
618*23ea4f30SEduardo Habkost            t = f['testcase']
619*23ea4f30SEduardo Habkost            logger.error("Fatal failure: %s", formatTestCase(t))
620*23ea4f30SEduardo Habkost        logger.error("Fatal failures on some machine/device combinations")
621*23ea4f30SEduardo Habkost        return 1
622*23ea4f30SEduardo Habkost
623*23ea4f30SEduardo Habkostif __name__ == '__main__':
624*23ea4f30SEduardo Habkost    sys.exit(main())
625