123ea4f30SEduardo Habkost#!/usr/bin/env python2.7 223ea4f30SEduardo Habkost# 323ea4f30SEduardo Habkost# Copyright (c) 2017 Red Hat Inc 423ea4f30SEduardo Habkost# 523ea4f30SEduardo Habkost# Author: 623ea4f30SEduardo Habkost# Eduardo Habkost <ehabkost@redhat.com> 723ea4f30SEduardo Habkost# 823ea4f30SEduardo Habkost# This program is free software; you can redistribute it and/or modify 923ea4f30SEduardo Habkost# it under the terms of the GNU General Public License as published by 1023ea4f30SEduardo Habkost# the Free Software Foundation; either version 2 of the License, or 1123ea4f30SEduardo Habkost# (at your option) any later version. 1223ea4f30SEduardo Habkost# 1323ea4f30SEduardo Habkost# This program is distributed in the hope that it will be useful, 1423ea4f30SEduardo Habkost# but WITHOUT ANY WARRANTY; without even the implied warranty of 1523ea4f30SEduardo Habkost# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1623ea4f30SEduardo Habkost# GNU General Public License for more details. 1723ea4f30SEduardo Habkost# 1823ea4f30SEduardo Habkost# You should have received a copy of the GNU General Public License along 1923ea4f30SEduardo Habkost# with this program; if not, write to the Free Software Foundation, Inc., 2023ea4f30SEduardo Habkost# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 2123ea4f30SEduardo Habkost 2223ea4f30SEduardo Habkost""" 2323ea4f30SEduardo HabkostRun QEMU with all combinations of -machine and -device types, 2423ea4f30SEduardo Habkostcheck for crashes and unexpected errors. 2523ea4f30SEduardo Habkost""" 2623ea4f30SEduardo Habkost 2723ea4f30SEduardo Habkostimport sys 2823ea4f30SEduardo Habkostimport os 2923ea4f30SEduardo Habkostimport glob 3023ea4f30SEduardo Habkostimport logging 3123ea4f30SEduardo Habkostimport traceback 3223ea4f30SEduardo Habkostimport re 3323ea4f30SEduardo Habkostimport random 3423ea4f30SEduardo Habkostimport argparse 3523ea4f30SEduardo Habkostfrom itertools import chain 3623ea4f30SEduardo Habkost 3723ea4f30SEduardo Habkostsys.path.append(os.path.join(os.path.dirname(__file__), '..', 'scripts')) 3823ea4f30SEduardo Habkostfrom qemu import QEMUMachine 3923ea4f30SEduardo Habkost 4023ea4f30SEduardo Habkostlogger = logging.getLogger('device-crash-test') 4123ea4f30SEduardo Habkostdbg = logger.debug 4223ea4f30SEduardo Habkost 4323ea4f30SEduardo Habkost 4423ea4f30SEduardo Habkost# Purposes of the following whitelist: 4523ea4f30SEduardo Habkost# * Avoiding verbose log messages when we find known non-fatal 4623ea4f30SEduardo Habkost# (exitcode=1) errors 4723ea4f30SEduardo Habkost# * Avoiding fatal errors when we find known crashes 4823ea4f30SEduardo Habkost# * Skipping machines/devices that are known not to work out of 4923ea4f30SEduardo Habkost# the box, when running in --quick mode 5023ea4f30SEduardo Habkost# 5123ea4f30SEduardo Habkost# Keeping the whitelist updated is desirable, but not required, 5223ea4f30SEduardo Habkost# because unexpected cases where QEMU exits with exitcode=1 will 5323ea4f30SEduardo Habkost# just trigger a INFO message. 5423ea4f30SEduardo Habkost 5523ea4f30SEduardo Habkost# Valid whitelist entry keys: 5623ea4f30SEduardo Habkost# * accel: regexp, full match only 5723ea4f30SEduardo Habkost# * machine: regexp, full match only 5823ea4f30SEduardo Habkost# * device: regexp, full match only 5923ea4f30SEduardo Habkost# * log: regexp, partial match allowed 6023ea4f30SEduardo Habkost# * exitcode: if not present, defaults to 1. If None, matches any exitcode 6123ea4f30SEduardo Habkost# * warn: if True, matching failures will be logged as warnings 6223ea4f30SEduardo Habkost# * expected: if True, QEMU is expected to always fail every time 6323ea4f30SEduardo Habkost# when testing the corresponding test case 6423ea4f30SEduardo Habkost# * loglevel: log level of log output when there's a match. 6523ea4f30SEduardo HabkostERROR_WHITELIST = [ 6623ea4f30SEduardo Habkost # Machines that won't work out of the box: 6723ea4f30SEduardo Habkost # MACHINE | ERROR MESSAGE 6823ea4f30SEduardo Habkost {'machine':'niagara', 'expected':True}, # Unable to load a firmware for -M niagara 6923ea4f30SEduardo Habkost {'machine':'boston', 'expected':True}, # Please provide either a -kernel or -bios argument 7023ea4f30SEduardo Habkost {'machine':'leon3_generic', 'expected':True}, # Can't read bios image (null) 7123ea4f30SEduardo Habkost 7223ea4f30SEduardo Habkost # devices that don't work out of the box because they require extra options to "-device DEV": 7323ea4f30SEduardo Habkost # DEVICE | ERROR MESSAGE 7423ea4f30SEduardo Habkost {'device':'.*-(i386|x86_64)-cpu', 'expected':True}, # CPU socket-id is not set 7523ea4f30SEduardo Habkost {'device':'ARM,bitband-memory', 'expected':True}, # source-memory property not set 7623ea4f30SEduardo Habkost {'device':'arm.cortex-a9-global-timer', 'expected':True}, # a9_gtimer_realize: num-cpu must be between 1 and 4 7723ea4f30SEduardo Habkost {'device':'arm_mptimer', 'expected':True}, # num-cpu must be between 1 and 4 7823ea4f30SEduardo Habkost {'device':'armv7m', 'expected':True}, # memory property was not set 7923ea4f30SEduardo Habkost {'device':'aspeed.scu', 'expected':True}, # Unknown silicon revision: 0x0 8023ea4f30SEduardo Habkost {'device':'aspeed.sdmc', 'expected':True}, # Unknown silicon revision: 0x0 8123ea4f30SEduardo Habkost {'device':'bcm2835-dma', 'expected':True}, # bcm2835_dma_realize: required dma-mr link not found: Property '.dma-mr' not found 8223ea4f30SEduardo Habkost {'device':'bcm2835-fb', 'expected':True}, # bcm2835_fb_realize: required vcram-base property not set 8323ea4f30SEduardo Habkost {'device':'bcm2835-mbox', 'expected':True}, # bcm2835_mbox_realize: required mbox-mr link not found: Property '.mbox-mr' not found 8423ea4f30SEduardo Habkost {'device':'bcm2835-peripherals', 'expected':True}, # bcm2835_peripherals_realize: required ram link not found: Property '.ram' not found 8523ea4f30SEduardo Habkost {'device':'bcm2835-property', 'expected':True}, # bcm2835_property_realize: required fb link not found: Property '.fb' not found 8623ea4f30SEduardo Habkost {'device':'bcm2835_gpio', 'expected':True}, # bcm2835_gpio_realize: required sdhci link not found: Property '.sdbus-sdhci' not found 8723ea4f30SEduardo Habkost {'device':'bcm2836', 'expected':True}, # bcm2836_realize: required ram link not found: Property '.ram' not found 8823ea4f30SEduardo Habkost {'device':'cfi.pflash01', 'expected':True}, # attribute "sector-length" not specified or zero. 8923ea4f30SEduardo Habkost {'device':'cfi.pflash02', 'expected':True}, # attribute "sector-length" not specified or zero. 9023ea4f30SEduardo Habkost {'device':'icp', 'expected':True}, # icp_realize: required link 'xics' not found: Property '.xics' not found 9123ea4f30SEduardo Habkost {'device':'ics', 'expected':True}, # ics_base_realize: required link 'xics' not found: Property '.xics' not found 9223ea4f30SEduardo Habkost # "-device ide-cd" does work on more recent QEMU versions, so it doesn't have expected=True 9323ea4f30SEduardo Habkost {'device':'ide-cd'}, # No drive specified 9423ea4f30SEduardo Habkost {'device':'ide-drive', 'expected':True}, # No drive specified 9523ea4f30SEduardo Habkost {'device':'ide-hd', 'expected':True}, # No drive specified 9623ea4f30SEduardo Habkost {'device':'ipmi-bmc-extern', 'expected':True}, # IPMI external bmc requires chardev attribute 9723ea4f30SEduardo Habkost {'device':'isa-debugcon', 'expected':True}, # Can't create serial device, empty char device 9823ea4f30SEduardo Habkost {'device':'isa-ipmi-bt', 'expected':True}, # IPMI device requires a bmc attribute to be set 9923ea4f30SEduardo Habkost {'device':'isa-ipmi-kcs', 'expected':True}, # IPMI device requires a bmc attribute to be set 10023ea4f30SEduardo Habkost {'device':'isa-parallel', 'expected':True}, # Can't create serial device, empty char device 10123ea4f30SEduardo Habkost {'device':'isa-serial', 'expected':True}, # Can't create serial device, empty char device 10223ea4f30SEduardo Habkost {'device':'ivshmem', 'expected':True}, # You must specify either 'shm' or 'chardev' 10323ea4f30SEduardo Habkost {'device':'ivshmem-doorbell', 'expected':True}, # You must specify a 'chardev' 10423ea4f30SEduardo Habkost {'device':'ivshmem-plain', 'expected':True}, # You must specify a 'memdev' 10523ea4f30SEduardo Habkost {'device':'kvm-pci-assign', 'expected':True}, # no host device specified 10623ea4f30SEduardo Habkost {'device':'loader', 'expected':True}, # please include valid arguments 10723ea4f30SEduardo Habkost {'device':'nand', 'expected':True}, # Unsupported NAND block size 0x1 10823ea4f30SEduardo Habkost {'device':'nvdimm', 'expected':True}, # 'memdev' property is not set 10923ea4f30SEduardo Habkost {'device':'nvme', 'expected':True}, # Device initialization failed 11023ea4f30SEduardo Habkost {'device':'pc-dimm', 'expected':True}, # 'memdev' property is not set 11123ea4f30SEduardo Habkost {'device':'pci-bridge', 'expected':True}, # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0. 11223ea4f30SEduardo Habkost {'device':'pci-bridge-seat', 'expected':True}, # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0. 11323ea4f30SEduardo Habkost {'device':'pci-serial', 'expected':True}, # Can't create serial device, empty char device 11423ea4f30SEduardo Habkost {'device':'pci-serial-2x', 'expected':True}, # Can't create serial device, empty char device 11523ea4f30SEduardo Habkost {'device':'pci-serial-4x', 'expected':True}, # Can't create serial device, empty char device 11623ea4f30SEduardo Habkost {'device':'pxa2xx-dma', 'expected':True}, # channels value invalid 11723ea4f30SEduardo Habkost {'device':'pxb', 'expected':True}, # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0. 11823ea4f30SEduardo Habkost {'device':'scsi-block', 'expected':True}, # drive property not set 11923ea4f30SEduardo Habkost {'device':'scsi-disk', 'expected':True}, # drive property not set 12023ea4f30SEduardo Habkost {'device':'scsi-generic', 'expected':True}, # drive property not set 12123ea4f30SEduardo Habkost {'device':'scsi-hd', 'expected':True}, # drive property not set 12223ea4f30SEduardo Habkost {'device':'spapr-pci-host-bridge', 'expected':True}, # BUID not specified for PHB 12323ea4f30SEduardo Habkost {'device':'spapr-pci-vfio-host-bridge', 'expected':True}, # BUID not specified for PHB 12423ea4f30SEduardo Habkost {'device':'spapr-rng', 'expected':True}, # spapr-rng needs an RNG backend! 12523ea4f30SEduardo Habkost {'device':'spapr-vty', 'expected':True}, # chardev property not set 12623ea4f30SEduardo Habkost {'device':'tpm-tis', 'expected':True}, # tpm_tis: backend driver with id (null) could not be found 12723ea4f30SEduardo Habkost {'device':'unimplemented-device', 'expected':True}, # property 'size' not specified or zero 12823ea4f30SEduardo Habkost {'device':'usb-braille', 'expected':True}, # Property chardev is required 12923ea4f30SEduardo Habkost {'device':'usb-mtp', 'expected':True}, # x-root property must be configured 13023ea4f30SEduardo Habkost {'device':'usb-redir', 'expected':True}, # Parameter 'chardev' is missing 13123ea4f30SEduardo Habkost {'device':'usb-serial', 'expected':True}, # Property chardev is required 13223ea4f30SEduardo Habkost {'device':'usb-storage', 'expected':True}, # drive property not set 13323ea4f30SEduardo Habkost {'device':'vfio-amd-xgbe', 'expected':True}, # -device vfio-amd-xgbe: vfio error: wrong host device name 13423ea4f30SEduardo Habkost {'device':'vfio-calxeda-xgmac', 'expected':True}, # -device vfio-calxeda-xgmac: vfio error: wrong host device name 13523ea4f30SEduardo Habkost {'device':'vfio-pci', 'expected':True}, # No provided host device 13623ea4f30SEduardo Habkost {'device':'vfio-pci-igd-lpc-bridge', 'expected':True}, # VFIO dummy ISA/LPC bridge must have address 1f.0 13723ea4f30SEduardo Habkost {'device':'vhost-scsi.*', 'expected':True}, # vhost-scsi: missing wwpn 13823ea4f30SEduardo Habkost {'device':'vhost-vsock-device', 'expected':True}, # guest-cid property must be greater than 2 13923ea4f30SEduardo Habkost {'device':'vhost-vsock-pci', 'expected':True}, # guest-cid property must be greater than 2 14023ea4f30SEduardo Habkost {'device':'virtio-9p-ccw', 'expected':True}, # 9pfs device couldn't find fsdev with the id = NULL 14123ea4f30SEduardo Habkost {'device':'virtio-9p-device', 'expected':True}, # 9pfs device couldn't find fsdev with the id = NULL 14223ea4f30SEduardo Habkost {'device':'virtio-9p-pci', 'expected':True}, # 9pfs device couldn't find fsdev with the id = NULL 14323ea4f30SEduardo Habkost {'device':'virtio-blk-ccw', 'expected':True}, # drive property not set 14423ea4f30SEduardo Habkost {'device':'virtio-blk-device', 'expected':True}, # drive property not set 14523ea4f30SEduardo Habkost {'device':'virtio-blk-device', 'expected':True}, # drive property not set 14623ea4f30SEduardo Habkost {'device':'virtio-blk-pci', 'expected':True}, # drive property not set 14723ea4f30SEduardo Habkost {'device':'virtio-crypto-ccw', 'expected':True}, # 'cryptodev' parameter expects a valid object 14823ea4f30SEduardo Habkost {'device':'virtio-crypto-device', 'expected':True}, # 'cryptodev' parameter expects a valid object 14923ea4f30SEduardo Habkost {'device':'virtio-crypto-pci', 'expected':True}, # 'cryptodev' parameter expects a valid object 15023ea4f30SEduardo Habkost {'device':'virtio-input-host-device', 'expected':True}, # evdev property is required 15123ea4f30SEduardo Habkost {'device':'virtio-input-host-pci', 'expected':True}, # evdev property is required 15223ea4f30SEduardo Habkost {'device':'xen-pvdevice', 'expected':True}, # Device ID invalid, it must always be supplied 15323ea4f30SEduardo Habkost {'device':'vhost-vsock-ccw', 'expected':True}, # guest-cid property must be greater than 2 15423ea4f30SEduardo Habkost {'device':'ALTR.timer', 'expected':True}, # "clock-frequency" property must be provided 15523ea4f30SEduardo Habkost {'device':'zpci', 'expected':True}, # target must be defined 15623ea4f30SEduardo Habkost {'device':'pnv-(occ|icp|lpc)', 'expected':True}, # required link 'xics' not found: Property '.xics' not found 15723ea4f30SEduardo Habkost {'device':'powernv-cpu-.*', 'expected':True}, # pnv_core_realize: required link 'xics' not found: Property '.xics' not found 15823ea4f30SEduardo Habkost 15923ea4f30SEduardo Habkost # ioapic devices are already created by pc and will fail: 16023ea4f30SEduardo Habkost {'machine':'q35|pc.*', 'device':'kvm-ioapic', 'expected':True}, # Only 1 ioapics allowed 16123ea4f30SEduardo Habkost {'machine':'q35|pc.*', 'device':'ioapic', 'expected':True}, # Only 1 ioapics allowed 16223ea4f30SEduardo Habkost 163*2363d5eeSThomas Huth # "spapr-cpu-core needs a pseries machine" 164*2363d5eeSThomas Huth {'machine':'(?!pseries).*', 'device':'.*-spapr-cpu-core', 'expected':True}, 165*2363d5eeSThomas Huth 16623ea4f30SEduardo Habkost # KVM-specific devices shouldn't be tried without accel=kvm: 16723ea4f30SEduardo Habkost {'accel':'(?!kvm).*', 'device':'kvmclock', 'expected':True}, 16823ea4f30SEduardo Habkost {'accel':'(?!kvm).*', 'device':'kvm-pci-assign', 'expected':True}, 16923ea4f30SEduardo Habkost 17023ea4f30SEduardo Habkost # xen-specific machines and devices: 17123ea4f30SEduardo Habkost {'accel':'(?!xen).*', 'machine':'xen.*', 'expected':True}, 17223ea4f30SEduardo Habkost {'accel':'(?!xen).*', 'device':'xen-.*', 'expected':True}, 17323ea4f30SEduardo Habkost 17423ea4f30SEduardo Habkost # this fails on some machine-types, but not all, so they don't have expected=True: 17523ea4f30SEduardo Habkost {'device':'vmgenid'}, # vmgenid requires DMA write support in fw_cfg, which this machine type does not provide 17623ea4f30SEduardo Habkost 17723ea4f30SEduardo Habkost # Silence INFO messages for errors that are common on multiple 17823ea4f30SEduardo Habkost # devices/machines: 17923ea4f30SEduardo Habkost {'log':r"No '[\w-]+' bus found for device '[\w-]+'"}, 18023ea4f30SEduardo Habkost {'log':r"images* must be given with the 'pflash' parameter"}, 18123ea4f30SEduardo Habkost {'log':r"(Guest|ROM|Flash|Kernel) image must be specified"}, 18223ea4f30SEduardo Habkost {'log':r"[cC]ould not load [\w ]+ (BIOS|bios) '[\w-]+\.bin'"}, 18323ea4f30SEduardo Habkost {'log':r"Couldn't find rom image '[\w-]+\.bin'"}, 18423ea4f30SEduardo Habkost {'log':r"speed mismatch trying to attach usb device"}, 18523ea4f30SEduardo Habkost {'log':r"Can't create a second ISA bus"}, 18623ea4f30SEduardo Habkost {'log':r"duplicate fw_cfg file name"}, 18723ea4f30SEduardo Habkost # sysbus-related error messages: most machines reject most dynamic sysbus devices: 18823ea4f30SEduardo Habkost {'log':r"Option '-device [\w.,-]+' cannot be handled by this machine"}, 18923ea4f30SEduardo Habkost {'log':r"Device [\w.,-]+ is not supported by this machine yet"}, 19023ea4f30SEduardo Habkost {'log':r"Device [\w.,-]+ can not be dynamically instantiated"}, 19123ea4f30SEduardo Habkost {'log':r"Platform Bus: Can not fit MMIO region of size "}, 19223ea4f30SEduardo Habkost # other more specific errors we will ignore: 19323ea4f30SEduardo Habkost {'device':'.*-spapr-cpu-core', 'log':r"CPU core type should be"}, 19423ea4f30SEduardo Habkost {'log':r"MSI(-X)? is not supported by interrupt controller"}, 19523ea4f30SEduardo Habkost {'log':r"pxb-pcie? devices cannot reside on a PCIe? bus"}, 19623ea4f30SEduardo Habkost {'log':r"Ignoring smp_cpus value"}, 19723ea4f30SEduardo Habkost {'log':r"sd_init failed: Drive 'sd0' is already in use because it has been automatically connected to another device"}, 19823ea4f30SEduardo Habkost {'log':r"This CPU requires a smaller page size than the system is using"}, 19923ea4f30SEduardo Habkost {'log':r"MSI-X support is mandatory in the S390 architecture"}, 20023ea4f30SEduardo Habkost {'log':r"rom check and register reset failed"}, 20123ea4f30SEduardo Habkost {'log':r"Unable to initialize GIC, CPUState for CPU#0 not valid"}, 20223ea4f30SEduardo Habkost {'log':r"Multiple VT220 operator consoles are not supported"}, 20323ea4f30SEduardo Habkost {'log':r"core 0 already populated"}, 20423ea4f30SEduardo Habkost {'log':r"could not find stage1 bootloader"}, 20523ea4f30SEduardo Habkost 20623ea4f30SEduardo Habkost # other exitcode=1 failures not listed above will just generate INFO messages: 20723ea4f30SEduardo Habkost {'exitcode':1, 'loglevel':logging.INFO}, 20823ea4f30SEduardo Habkost 20923ea4f30SEduardo Habkost # KNOWN CRASHES: 21023ea4f30SEduardo Habkost # Known crashes will generate error messages, but won't be fatal. 21123ea4f30SEduardo Habkost # Those entries must be removed once we fix the crashes. 21223ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"Device 'serial0' is in use", 'loglevel':logging.ERROR}, 21323ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"spapr_rtas_register: Assertion .*rtas_table\[token\]\.name.* failed", 'loglevel':logging.ERROR}, 21423ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"qemu_net_client_setup: Assertion `!peer->peer' failed", 'loglevel':logging.ERROR}, 21523ea4f30SEduardo Habkost {'exitcode':-6, 'log':r'RAMBlock "[\w.-]+" already registered', 'loglevel':logging.ERROR}, 21623ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"find_ram_offset: Assertion `size != 0' failed.", 'loglevel':logging.ERROR}, 21723ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"puv3_load_kernel: Assertion `kernel_filename != NULL' failed", 'loglevel':logging.ERROR}, 21823ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"add_cpreg_to_hashtable: code should not be reached", 'loglevel':logging.ERROR}, 21923ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"qemu_alloc_display: Assertion `surface->image != NULL' failed", 'loglevel':logging.ERROR}, 22023ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"Unexpected error in error_set_from_qdev_prop_error", 'loglevel':logging.ERROR}, 22123ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"Object .* is not an instance of type spapr-machine", 'loglevel':logging.ERROR}, 22223ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"Object .* is not an instance of type generic-pc-machine", 'loglevel':logging.ERROR}, 22323ea4f30SEduardo Habkost {'exitcode':-6, 'log':r"Object .* is not an instance of type e500-ccsr", 'loglevel':logging.ERROR}, 2242a6f395bSEduardo Habkost {'exitcode':-6, 'log':r"vmstate_register_with_alias_id: Assertion `!se->compat \|\| se->instance_id == 0' failed", 'loglevel':logging.ERROR}, 22523ea4f30SEduardo Habkost {'exitcode':-11, 'device':'stm32f205-soc', 'loglevel':logging.ERROR, 'expected':True}, 22623ea4f30SEduardo Habkost {'exitcode':-11, 'device':'xlnx,zynqmp', 'loglevel':logging.ERROR, 'expected':True}, 22723ea4f30SEduardo Habkost {'exitcode':-11, 'device':'mips-cps', 'loglevel':logging.ERROR, 'expected':True}, 22823ea4f30SEduardo Habkost {'exitcode':-11, 'device':'gus', 'loglevel':logging.ERROR, 'expected':True}, 22923ea4f30SEduardo Habkost {'exitcode':-11, 'device':'a9mpcore_priv', 'loglevel':logging.ERROR, 'expected':True}, 23023ea4f30SEduardo Habkost {'exitcode':-11, 'device':'a15mpcore_priv', 'loglevel':logging.ERROR, 'expected':True}, 23123ea4f30SEduardo Habkost {'exitcode':-11, 'device':'isa-serial', 'loglevel':logging.ERROR, 'expected':True}, 23223ea4f30SEduardo Habkost {'exitcode':-11, 'device':'sb16', 'loglevel':logging.ERROR, 'expected':True}, 23323ea4f30SEduardo Habkost {'exitcode':-11, 'device':'cs4231a', 'loglevel':logging.ERROR, 'expected':True}, 23423ea4f30SEduardo Habkost {'exitcode':-11, 'device':'arm-gicv3', 'loglevel':logging.ERROR, 'expected':True}, 23523ea4f30SEduardo Habkost {'exitcode':-11, 'machine':'isapc', 'device':'.*-iommu', 'loglevel':logging.ERROR, 'expected':True}, 23623ea4f30SEduardo Habkost 23723ea4f30SEduardo Habkost # everything else (including SIGABRT and SIGSEGV) will be a fatal error: 23823ea4f30SEduardo Habkost {'exitcode':None, 'fatal':True, 'loglevel':logging.FATAL}, 23923ea4f30SEduardo Habkost] 24023ea4f30SEduardo Habkost 24123ea4f30SEduardo Habkost 24223ea4f30SEduardo Habkostdef whitelistTestCaseMatch(wl, t): 24323ea4f30SEduardo Habkost """Check if a test case specification can match a whitelist entry 24423ea4f30SEduardo Habkost 24523ea4f30SEduardo Habkost This only checks if a whitelist entry is a candidate match 24623ea4f30SEduardo Habkost for a given test case, it won't check if the test case 24723ea4f30SEduardo Habkost results/output match the entry. See whitelistResultMatch(). 24823ea4f30SEduardo Habkost """ 24923ea4f30SEduardo Habkost return (('machine' not in wl or 25023ea4f30SEduardo Habkost 'machine' not in t or 25123ea4f30SEduardo Habkost re.match(wl['machine'] + '$', t['machine'])) and 25223ea4f30SEduardo Habkost ('accel' not in wl or 25323ea4f30SEduardo Habkost 'accel' not in t or 25423ea4f30SEduardo Habkost re.match(wl['accel'] + '$', t['accel'])) and 25523ea4f30SEduardo Habkost ('device' not in wl or 25623ea4f30SEduardo Habkost 'device' not in t or 25723ea4f30SEduardo Habkost re.match(wl['device'] + '$', t['device']))) 25823ea4f30SEduardo Habkost 25923ea4f30SEduardo Habkost 26023ea4f30SEduardo Habkostdef whitelistCandidates(t): 26123ea4f30SEduardo Habkost """Generate the list of candidates that can match a test case""" 26223ea4f30SEduardo Habkost for i, wl in enumerate(ERROR_WHITELIST): 26323ea4f30SEduardo Habkost if whitelistTestCaseMatch(wl, t): 26423ea4f30SEduardo Habkost yield (i, wl) 26523ea4f30SEduardo Habkost 26623ea4f30SEduardo Habkost 26723ea4f30SEduardo Habkostdef findExpectedResult(t): 26823ea4f30SEduardo Habkost """Check if there's an expected=True whitelist entry for a test case 26923ea4f30SEduardo Habkost 27023ea4f30SEduardo Habkost Returns (i, wl) tuple, where i is the index in 27123ea4f30SEduardo Habkost ERROR_WHITELIST and wl is the whitelist entry itself. 27223ea4f30SEduardo Habkost """ 27323ea4f30SEduardo Habkost for i, wl in whitelistCandidates(t): 27423ea4f30SEduardo Habkost if wl.get('expected'): 27523ea4f30SEduardo Habkost return (i, wl) 27623ea4f30SEduardo Habkost 27723ea4f30SEduardo Habkost 27823ea4f30SEduardo Habkostdef whitelistResultMatch(wl, r): 27923ea4f30SEduardo Habkost """Check if test case results/output match a whitelist entry 28023ea4f30SEduardo Habkost 28123ea4f30SEduardo Habkost It is valid to call this function only if 28223ea4f30SEduardo Habkost whitelistTestCaseMatch() is True for the entry (e.g. on 28323ea4f30SEduardo Habkost entries returned by whitelistCandidates()) 28423ea4f30SEduardo Habkost """ 28523ea4f30SEduardo Habkost assert whitelistTestCaseMatch(wl, r['testcase']) 28623ea4f30SEduardo Habkost return ((wl.get('exitcode', 1) is None or 28723ea4f30SEduardo Habkost r['exitcode'] == wl.get('exitcode', 1)) and 28823ea4f30SEduardo Habkost ('log' not in wl or 28923ea4f30SEduardo Habkost re.search(wl['log'], r['log'], re.MULTILINE))) 29023ea4f30SEduardo Habkost 29123ea4f30SEduardo Habkost 29223ea4f30SEduardo Habkostdef checkResultWhitelist(r): 29323ea4f30SEduardo Habkost """Look up whitelist entry for a given test case result 29423ea4f30SEduardo Habkost 29523ea4f30SEduardo Habkost Returns (i, wl) tuple, where i is the index in 29623ea4f30SEduardo Habkost ERROR_WHITELIST and wl is the whitelist entry itself. 29723ea4f30SEduardo Habkost """ 29823ea4f30SEduardo Habkost for i, wl in whitelistCandidates(r['testcase']): 29923ea4f30SEduardo Habkost if whitelistResultMatch(wl, r): 30023ea4f30SEduardo Habkost return i, wl 30123ea4f30SEduardo Habkost 30223ea4f30SEduardo Habkost raise Exception("this should never happen") 30323ea4f30SEduardo Habkost 30423ea4f30SEduardo Habkost 30523ea4f30SEduardo Habkostdef qemuOptsEscape(s): 30623ea4f30SEduardo Habkost """Escape option value QemuOpts""" 30723ea4f30SEduardo Habkost return s.replace(",", ",,") 30823ea4f30SEduardo Habkost 30923ea4f30SEduardo Habkost 31023ea4f30SEduardo Habkostdef formatTestCase(t): 31123ea4f30SEduardo Habkost """Format test case info as "key=value key=value" for prettier logging output""" 31223ea4f30SEduardo Habkost return ' '.join('%s=%s' % (k, v) for k, v in t.items()) 31323ea4f30SEduardo Habkost 31423ea4f30SEduardo Habkost 31523ea4f30SEduardo Habkostdef qomListTypeNames(vm, **kwargs): 31623ea4f30SEduardo Habkost """Run qom-list-types QMP command, return type names""" 31723ea4f30SEduardo Habkost types = vm.command('qom-list-types', **kwargs) 31823ea4f30SEduardo Habkost return [t['name'] for t in types] 31923ea4f30SEduardo Habkost 32023ea4f30SEduardo Habkost 32123ea4f30SEduardo Habkostdef infoQDM(vm): 32223ea4f30SEduardo Habkost """Parse 'info qdm' output""" 32323ea4f30SEduardo Habkost args = {'command-line': 'info qdm'} 32423ea4f30SEduardo Habkost devhelp = vm.command('human-monitor-command', **args) 32523ea4f30SEduardo Habkost for l in devhelp.split('\n'): 32623ea4f30SEduardo Habkost l = l.strip() 32723ea4f30SEduardo Habkost if l == '' or l.endswith(':'): 32823ea4f30SEduardo Habkost continue 32923ea4f30SEduardo Habkost d = {'name': re.search(r'name "([^"]+)"', l).group(1), 33023ea4f30SEduardo Habkost 'no-user': (re.search(', no-user', l) is not None)} 33123ea4f30SEduardo Habkost yield d 33223ea4f30SEduardo Habkost 33323ea4f30SEduardo Habkost 33423ea4f30SEduardo Habkostclass QemuBinaryInfo(object): 33523ea4f30SEduardo Habkost def __init__(self, binary, devtype): 33623ea4f30SEduardo Habkost if devtype is None: 33723ea4f30SEduardo Habkost devtype = 'device' 33823ea4f30SEduardo Habkost 33923ea4f30SEduardo Habkost self.binary = binary 34023ea4f30SEduardo Habkost self._machine_info = {} 34123ea4f30SEduardo Habkost 34223ea4f30SEduardo Habkost dbg("devtype: %r", devtype) 34323ea4f30SEduardo Habkost args = ['-S', '-machine', 'none,accel=kvm:tcg'] 34423ea4f30SEduardo Habkost dbg("querying info for QEMU binary: %s", binary) 34523ea4f30SEduardo Habkost vm = QEMUMachine(binary=binary, args=args) 34623ea4f30SEduardo Habkost vm.launch() 34723ea4f30SEduardo Habkost try: 34823ea4f30SEduardo Habkost self.alldevs = set(qomListTypeNames(vm, implements=devtype, abstract=False)) 34923ea4f30SEduardo Habkost # there's no way to query DeviceClass::user_creatable using QMP, 35023ea4f30SEduardo Habkost # so use 'info qdm': 35123ea4f30SEduardo Habkost self.no_user_devs = set([d['name'] for d in infoQDM(vm, ) if d['no-user']]) 35223ea4f30SEduardo Habkost self.machines = list(m['name'] for m in vm.command('query-machines')) 35323ea4f30SEduardo Habkost self.user_devs = self.alldevs.difference(self.no_user_devs) 35423ea4f30SEduardo Habkost self.kvm_available = vm.command('query-kvm')['enabled'] 35523ea4f30SEduardo Habkost finally: 35623ea4f30SEduardo Habkost vm.shutdown() 35723ea4f30SEduardo Habkost 35823ea4f30SEduardo Habkost def machineInfo(self, machine): 35923ea4f30SEduardo Habkost """Query for information on a specific machine-type 36023ea4f30SEduardo Habkost 36123ea4f30SEduardo Habkost Results are cached internally, in case the same machine- 36223ea4f30SEduardo Habkost type is queried multiple times. 36323ea4f30SEduardo Habkost """ 36423ea4f30SEduardo Habkost if machine in self._machine_info: 36523ea4f30SEduardo Habkost return self._machine_info[machine] 36623ea4f30SEduardo Habkost 36723ea4f30SEduardo Habkost mi = {} 36823ea4f30SEduardo Habkost args = ['-S', '-machine', '%s' % (machine)] 36923ea4f30SEduardo Habkost dbg("querying machine info for binary=%s machine=%s", self.binary, machine) 37023ea4f30SEduardo Habkost vm = QEMUMachine(binary=self.binary, args=args) 37123ea4f30SEduardo Habkost try: 37223ea4f30SEduardo Habkost vm.launch() 37323ea4f30SEduardo Habkost mi['runnable'] = True 37423ea4f30SEduardo Habkost except KeyboardInterrupt: 37523ea4f30SEduardo Habkost raise 37623ea4f30SEduardo Habkost except: 37723ea4f30SEduardo Habkost dbg("exception trying to run binary=%s machine=%s", self.binary, machine, exc_info=sys.exc_info()) 37823ea4f30SEduardo Habkost dbg("log: %r", vm.get_log()) 37923ea4f30SEduardo Habkost mi['runnable'] = False 38023ea4f30SEduardo Habkost 38123ea4f30SEduardo Habkost vm.shutdown() 38223ea4f30SEduardo Habkost self._machine_info[machine] = mi 38323ea4f30SEduardo Habkost return mi 38423ea4f30SEduardo Habkost 38523ea4f30SEduardo Habkost 38623ea4f30SEduardo HabkostBINARY_INFO = {} 38723ea4f30SEduardo Habkost 38823ea4f30SEduardo Habkost 38923ea4f30SEduardo Habkostdef getBinaryInfo(args, binary): 39023ea4f30SEduardo Habkost if binary not in BINARY_INFO: 39123ea4f30SEduardo Habkost BINARY_INFO[binary] = QemuBinaryInfo(binary, args.devtype) 39223ea4f30SEduardo Habkost return BINARY_INFO[binary] 39323ea4f30SEduardo Habkost 39423ea4f30SEduardo Habkost 39523ea4f30SEduardo Habkostdef checkOneCase(args, testcase): 39623ea4f30SEduardo Habkost """Check one specific case 39723ea4f30SEduardo Habkost 39823ea4f30SEduardo Habkost Returns a dictionary containing failure information on error, 39923ea4f30SEduardo Habkost or None on success 40023ea4f30SEduardo Habkost """ 40123ea4f30SEduardo Habkost binary = testcase['binary'] 40223ea4f30SEduardo Habkost accel = testcase['accel'] 40323ea4f30SEduardo Habkost machine = testcase['machine'] 40423ea4f30SEduardo Habkost device = testcase['device'] 40523ea4f30SEduardo Habkost 40623ea4f30SEduardo Habkost dbg("will test: %r", testcase) 40723ea4f30SEduardo Habkost 40823ea4f30SEduardo Habkost args = ['-S', '-machine', '%s,accel=%s' % (machine, accel), 40923ea4f30SEduardo Habkost '-device', qemuOptsEscape(device)] 41023ea4f30SEduardo Habkost cmdline = ' '.join([binary] + args) 41123ea4f30SEduardo Habkost dbg("will launch QEMU: %s", cmdline) 41223ea4f30SEduardo Habkost vm = QEMUMachine(binary=binary, args=args) 41323ea4f30SEduardo Habkost 41423ea4f30SEduardo Habkost exc_traceback = None 41523ea4f30SEduardo Habkost try: 41623ea4f30SEduardo Habkost vm.launch() 41723ea4f30SEduardo Habkost except KeyboardInterrupt: 41823ea4f30SEduardo Habkost raise 41923ea4f30SEduardo Habkost except: 42023ea4f30SEduardo Habkost exc_traceback = traceback.format_exc() 42123ea4f30SEduardo Habkost dbg("Exception while running test case") 42223ea4f30SEduardo Habkost finally: 42323ea4f30SEduardo Habkost vm.shutdown() 42423ea4f30SEduardo Habkost ec = vm.exitcode() 42523ea4f30SEduardo Habkost log = vm.get_log() 42623ea4f30SEduardo Habkost 42723ea4f30SEduardo Habkost if exc_traceback is not None or ec != 0: 42823ea4f30SEduardo Habkost return {'exc_traceback':exc_traceback, 42923ea4f30SEduardo Habkost 'exitcode':ec, 43023ea4f30SEduardo Habkost 'log':log, 43123ea4f30SEduardo Habkost 'testcase':testcase, 43223ea4f30SEduardo Habkost 'cmdline':cmdline} 43323ea4f30SEduardo Habkost 43423ea4f30SEduardo Habkost 43523ea4f30SEduardo Habkostdef binariesToTest(args, testcase): 43623ea4f30SEduardo Habkost if args.qemu: 43723ea4f30SEduardo Habkost r = args.qemu 43823ea4f30SEduardo Habkost else: 43923ea4f30SEduardo Habkost r = glob.glob('./*-softmmu/qemu-system-*') 44023ea4f30SEduardo Habkost return r 44123ea4f30SEduardo Habkost 44223ea4f30SEduardo Habkost 44323ea4f30SEduardo Habkostdef accelsToTest(args, testcase): 44423ea4f30SEduardo Habkost if getBinaryInfo(args, testcase['binary']).kvm_available: 44523ea4f30SEduardo Habkost yield 'kvm' 44623ea4f30SEduardo Habkost yield 'tcg' 44723ea4f30SEduardo Habkost 44823ea4f30SEduardo Habkost 44923ea4f30SEduardo Habkostdef machinesToTest(args, testcase): 45023ea4f30SEduardo Habkost return getBinaryInfo(args, testcase['binary']).machines 45123ea4f30SEduardo Habkost 45223ea4f30SEduardo Habkost 45323ea4f30SEduardo Habkostdef devicesToTest(args, testcase): 45423ea4f30SEduardo Habkost return getBinaryInfo(args, testcase['binary']).user_devs 45523ea4f30SEduardo Habkost 45623ea4f30SEduardo Habkost 45723ea4f30SEduardo HabkostTESTCASE_VARIABLES = [ 45823ea4f30SEduardo Habkost ('binary', binariesToTest), 45923ea4f30SEduardo Habkost ('accel', accelsToTest), 46023ea4f30SEduardo Habkost ('machine', machinesToTest), 46123ea4f30SEduardo Habkost ('device', devicesToTest), 46223ea4f30SEduardo Habkost] 46323ea4f30SEduardo Habkost 46423ea4f30SEduardo Habkost 46523ea4f30SEduardo Habkostdef genCases1(args, testcases, var, fn): 46623ea4f30SEduardo Habkost """Generate new testcases for one variable 46723ea4f30SEduardo Habkost 46823ea4f30SEduardo Habkost If an existing item already has a variable set, don't 46923ea4f30SEduardo Habkost generate new items and just return it directly. This 47023ea4f30SEduardo Habkost allows the "-t" command-line option to be used to choose 47123ea4f30SEduardo Habkost a specific test case. 47223ea4f30SEduardo Habkost """ 47323ea4f30SEduardo Habkost for testcase in testcases: 47423ea4f30SEduardo Habkost if var in testcase: 47523ea4f30SEduardo Habkost yield testcase.copy() 47623ea4f30SEduardo Habkost else: 47723ea4f30SEduardo Habkost for i in fn(args, testcase): 47823ea4f30SEduardo Habkost t = testcase.copy() 47923ea4f30SEduardo Habkost t[var] = i 48023ea4f30SEduardo Habkost yield t 48123ea4f30SEduardo Habkost 48223ea4f30SEduardo Habkost 48323ea4f30SEduardo Habkostdef genCases(args, testcase): 48423ea4f30SEduardo Habkost """Generate test cases for all variables 48523ea4f30SEduardo Habkost """ 48623ea4f30SEduardo Habkost cases = [testcase.copy()] 48723ea4f30SEduardo Habkost for var, fn in TESTCASE_VARIABLES: 48823ea4f30SEduardo Habkost dbg("var: %r, fn: %r", var, fn) 48923ea4f30SEduardo Habkost cases = genCases1(args, cases, var, fn) 49023ea4f30SEduardo Habkost return cases 49123ea4f30SEduardo Habkost 49223ea4f30SEduardo Habkost 49323ea4f30SEduardo Habkostdef casesToTest(args, testcase): 49423ea4f30SEduardo Habkost cases = genCases(args, testcase) 49523ea4f30SEduardo Habkost if args.random: 49623ea4f30SEduardo Habkost cases = list(cases) 49723ea4f30SEduardo Habkost cases = random.sample(cases, min(args.random, len(cases))) 49823ea4f30SEduardo Habkost if args.debug: 49923ea4f30SEduardo Habkost cases = list(cases) 50023ea4f30SEduardo Habkost dbg("%d test cases to test", len(cases)) 50123ea4f30SEduardo Habkost if args.shuffle: 50223ea4f30SEduardo Habkost cases = list(cases) 50323ea4f30SEduardo Habkost random.shuffle(cases) 50423ea4f30SEduardo Habkost return cases 50523ea4f30SEduardo Habkost 50623ea4f30SEduardo Habkost 50723ea4f30SEduardo Habkostdef logFailure(f, level): 50823ea4f30SEduardo Habkost t = f['testcase'] 50923ea4f30SEduardo Habkost logger.log(level, "failed: %s", formatTestCase(t)) 51023ea4f30SEduardo Habkost logger.log(level, "cmdline: %s", f['cmdline']) 51123ea4f30SEduardo Habkost for l in f['log'].strip().split('\n'): 51223ea4f30SEduardo Habkost logger.log(level, "log: %s", l) 51323ea4f30SEduardo Habkost logger.log(level, "exit code: %r", f['exitcode']) 51423ea4f30SEduardo Habkost if f['exc_traceback']: 51523ea4f30SEduardo Habkost logger.log(level, "exception:") 51623ea4f30SEduardo Habkost for l in f['exc_traceback'].split('\n'): 51723ea4f30SEduardo Habkost logger.log(level, " %s", l.rstrip('\n')) 51823ea4f30SEduardo Habkost 51923ea4f30SEduardo Habkost 52023ea4f30SEduardo Habkostdef main(): 52123ea4f30SEduardo Habkost parser = argparse.ArgumentParser(description="QEMU -device crash test") 52223ea4f30SEduardo Habkost parser.add_argument('-t', metavar='KEY=VALUE', nargs='*', 52323ea4f30SEduardo Habkost help="Limit test cases to KEY=VALUE", 52423ea4f30SEduardo Habkost action='append', dest='testcases', default=[]) 52523ea4f30SEduardo Habkost parser.add_argument('-d', '--debug', action='store_true', 52623ea4f30SEduardo Habkost help='debug output') 52723ea4f30SEduardo Habkost parser.add_argument('-v', '--verbose', action='store_true', default=True, 52823ea4f30SEduardo Habkost help='verbose output') 52923ea4f30SEduardo Habkost parser.add_argument('-q', '--quiet', dest='verbose', action='store_false', 53023ea4f30SEduardo Habkost help='non-verbose output') 53123ea4f30SEduardo Habkost parser.add_argument('-r', '--random', type=int, metavar='COUNT', 53223ea4f30SEduardo Habkost help='run a random sample of COUNT test cases', 53323ea4f30SEduardo Habkost default=0) 53423ea4f30SEduardo Habkost parser.add_argument('--shuffle', action='store_true', 53523ea4f30SEduardo Habkost help='Run test cases in random order') 53623ea4f30SEduardo Habkost parser.add_argument('--dry-run', action='store_true', 53723ea4f30SEduardo Habkost help="Don't run any tests, just generate list") 53823ea4f30SEduardo Habkost parser.add_argument('-D', '--devtype', metavar='TYPE', 53923ea4f30SEduardo Habkost help="Test only device types that implement TYPE") 54023ea4f30SEduardo Habkost parser.add_argument('-Q', '--quick', action='store_true', default=True, 54123ea4f30SEduardo Habkost help="Quick mode: skip test cases that are expected to fail") 54223ea4f30SEduardo Habkost parser.add_argument('-F', '--full', action='store_false', dest='quick', 54323ea4f30SEduardo Habkost help="Full mode: test cases that are expected to fail") 54423ea4f30SEduardo Habkost parser.add_argument('--strict', action='store_true', dest='strict', 54523ea4f30SEduardo Habkost help="Treat all warnings as fatal") 54623ea4f30SEduardo Habkost parser.add_argument('qemu', nargs='*', metavar='QEMU', 54723ea4f30SEduardo Habkost help='QEMU binary to run') 54823ea4f30SEduardo Habkost args = parser.parse_args() 54923ea4f30SEduardo Habkost 55023ea4f30SEduardo Habkost if args.debug: 55123ea4f30SEduardo Habkost lvl = logging.DEBUG 55223ea4f30SEduardo Habkost elif args.verbose: 55323ea4f30SEduardo Habkost lvl = logging.INFO 55423ea4f30SEduardo Habkost else: 55523ea4f30SEduardo Habkost lvl = logging.WARN 55623ea4f30SEduardo Habkost logging.basicConfig(stream=sys.stdout, level=lvl, format='%(levelname)s: %(message)s') 55723ea4f30SEduardo Habkost 55823ea4f30SEduardo Habkost fatal_failures = [] 55923ea4f30SEduardo Habkost wl_stats = {} 56023ea4f30SEduardo Habkost skipped = 0 56123ea4f30SEduardo Habkost total = 0 56223ea4f30SEduardo Habkost 56323ea4f30SEduardo Habkost tc = {} 56423ea4f30SEduardo Habkost dbg("testcases: %r", args.testcases) 56523ea4f30SEduardo Habkost if args.testcases: 56623ea4f30SEduardo Habkost for t in chain(*args.testcases): 56723ea4f30SEduardo Habkost for kv in t.split(): 56823ea4f30SEduardo Habkost k, v = kv.split('=', 1) 56923ea4f30SEduardo Habkost tc[k] = v 57023ea4f30SEduardo Habkost 57123ea4f30SEduardo Habkost if len(binariesToTest(args, tc)) == 0: 57223ea4f30SEduardo Habkost print >>sys.stderr, "No QEMU binary found" 57323ea4f30SEduardo Habkost parser.print_usage(sys.stderr) 57423ea4f30SEduardo Habkost return 1 57523ea4f30SEduardo Habkost 57623ea4f30SEduardo Habkost for t in casesToTest(args, tc): 57723ea4f30SEduardo Habkost logger.info("running test case: %s", formatTestCase(t)) 57823ea4f30SEduardo Habkost total += 1 57923ea4f30SEduardo Habkost 58023ea4f30SEduardo Habkost expected_match = findExpectedResult(t) 58123ea4f30SEduardo Habkost if (args.quick and 58223ea4f30SEduardo Habkost (expected_match or 58323ea4f30SEduardo Habkost not getBinaryInfo(args, t['binary']).machineInfo(t['machine'])['runnable'])): 58423ea4f30SEduardo Habkost dbg("skipped: %s", formatTestCase(t)) 58523ea4f30SEduardo Habkost skipped += 1 58623ea4f30SEduardo Habkost continue 58723ea4f30SEduardo Habkost 58823ea4f30SEduardo Habkost if args.dry_run: 58923ea4f30SEduardo Habkost continue 59023ea4f30SEduardo Habkost 59123ea4f30SEduardo Habkost try: 59223ea4f30SEduardo Habkost f = checkOneCase(args, t) 59323ea4f30SEduardo Habkost except KeyboardInterrupt: 59423ea4f30SEduardo Habkost break 59523ea4f30SEduardo Habkost 59623ea4f30SEduardo Habkost if f: 59723ea4f30SEduardo Habkost i, wl = checkResultWhitelist(f) 59823ea4f30SEduardo Habkost dbg("testcase: %r, whitelist match: %r", t, wl) 59923ea4f30SEduardo Habkost wl_stats.setdefault(i, []).append(f) 60023ea4f30SEduardo Habkost level = wl.get('loglevel', logging.DEBUG) 60123ea4f30SEduardo Habkost logFailure(f, level) 60223ea4f30SEduardo Habkost if wl.get('fatal') or (args.strict and level >= logging.WARN): 60323ea4f30SEduardo Habkost fatal_failures.append(f) 60423ea4f30SEduardo Habkost else: 60523ea4f30SEduardo Habkost dbg("success: %s", formatTestCase(t)) 60623ea4f30SEduardo Habkost if expected_match: 60723ea4f30SEduardo Habkost logger.warn("Didn't fail as expected: %s", formatTestCase(t)) 60823ea4f30SEduardo Habkost 60923ea4f30SEduardo Habkost logger.info("Total: %d test cases", total) 61023ea4f30SEduardo Habkost if skipped: 61123ea4f30SEduardo Habkost logger.info("Skipped %d test cases", skipped) 61223ea4f30SEduardo Habkost 61323ea4f30SEduardo Habkost if args.debug: 61423ea4f30SEduardo Habkost stats = sorted([(len(wl_stats.get(i, [])), wl) for i, wl in enumerate(ERROR_WHITELIST)]) 61523ea4f30SEduardo Habkost for count, wl in stats: 61623ea4f30SEduardo Habkost dbg("whitelist entry stats: %d: %r", count, wl) 61723ea4f30SEduardo Habkost 61823ea4f30SEduardo Habkost if fatal_failures: 61923ea4f30SEduardo Habkost for f in fatal_failures: 62023ea4f30SEduardo Habkost t = f['testcase'] 62123ea4f30SEduardo Habkost logger.error("Fatal failure: %s", formatTestCase(t)) 62223ea4f30SEduardo Habkost logger.error("Fatal failures on some machine/device combinations") 62323ea4f30SEduardo Habkost return 1 62423ea4f30SEduardo Habkost 62523ea4f30SEduardo Habkostif __name__ == '__main__': 62623ea4f30SEduardo Habkost sys.exit(main()) 627