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