xref: /openbmc/qemu/scripts/device-crash-test (revision 44d815e83a1e898dec90f3093d09c015975178c6)
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':'loader', 'expected':True},                  # please include valid arguments
10623ea4f30SEduardo Habkost    {'device':'nand', 'expected':True},                    # Unsupported NAND block size 0x1
10723ea4f30SEduardo Habkost    {'device':'nvdimm', 'expected':True},                  # 'memdev' property is not set
10823ea4f30SEduardo Habkost    {'device':'nvme', 'expected':True},                    # Device initialization failed
10923ea4f30SEduardo Habkost    {'device':'pc-dimm', 'expected':True},                 # 'memdev' property is not set
11023ea4f30SEduardo Habkost    {'device':'pci-bridge', 'expected':True},              # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0.
11123ea4f30SEduardo Habkost    {'device':'pci-bridge-seat', 'expected':True},         # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0.
11223ea4f30SEduardo Habkost    {'device':'pci-serial', 'expected':True},              # Can't create serial device, empty char device
11323ea4f30SEduardo Habkost    {'device':'pci-serial-2x', 'expected':True},           # Can't create serial device, empty char device
11423ea4f30SEduardo Habkost    {'device':'pci-serial-4x', 'expected':True},           # Can't create serial device, empty char device
11523ea4f30SEduardo Habkost    {'device':'pxa2xx-dma', 'expected':True},              # channels value invalid
11623ea4f30SEduardo Habkost    {'device':'pxb', 'expected':True},                     # Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0.
11723ea4f30SEduardo Habkost    {'device':'scsi-block', 'expected':True},              # drive property not set
11823ea4f30SEduardo Habkost    {'device':'scsi-disk', 'expected':True},               # drive property not set
11923ea4f30SEduardo Habkost    {'device':'scsi-generic', 'expected':True},            # drive property not set
12023ea4f30SEduardo Habkost    {'device':'scsi-hd', 'expected':True},                 # drive property not set
12123ea4f30SEduardo Habkost    {'device':'spapr-pci-host-bridge', 'expected':True},   # BUID not specified for PHB
12223ea4f30SEduardo Habkost    {'device':'spapr-rng', 'expected':True},               # spapr-rng needs an RNG backend!
12323ea4f30SEduardo Habkost    {'device':'spapr-vty', 'expected':True},               # chardev property not set
12423ea4f30SEduardo Habkost    {'device':'tpm-tis', 'expected':True},                 # tpm_tis: backend driver with id (null) could not be found
12523ea4f30SEduardo Habkost    {'device':'unimplemented-device', 'expected':True},    # property 'size' not specified or zero
12623ea4f30SEduardo Habkost    {'device':'usb-braille', 'expected':True},             # Property chardev is required
12723ea4f30SEduardo Habkost    {'device':'usb-mtp', 'expected':True},                 # x-root property must be configured
12823ea4f30SEduardo Habkost    {'device':'usb-redir', 'expected':True},               # Parameter 'chardev' is missing
12923ea4f30SEduardo Habkost    {'device':'usb-serial', 'expected':True},              # Property chardev is required
13023ea4f30SEduardo Habkost    {'device':'usb-storage', 'expected':True},             # drive property not set
13123ea4f30SEduardo Habkost    {'device':'vfio-amd-xgbe', 'expected':True},           # -device vfio-amd-xgbe: vfio error: wrong host device name
13223ea4f30SEduardo Habkost    {'device':'vfio-calxeda-xgmac', 'expected':True},      # -device vfio-calxeda-xgmac: vfio error: wrong host device name
13323ea4f30SEduardo Habkost    {'device':'vfio-pci', 'expected':True},                # No provided host device
13423ea4f30SEduardo Habkost    {'device':'vfio-pci-igd-lpc-bridge', 'expected':True}, # VFIO dummy ISA/LPC bridge must have address 1f.0
13523ea4f30SEduardo Habkost    {'device':'vhost-scsi.*', 'expected':True},            # vhost-scsi: missing wwpn
13623ea4f30SEduardo Habkost    {'device':'vhost-vsock-device', 'expected':True},      # guest-cid property must be greater than 2
13723ea4f30SEduardo Habkost    {'device':'vhost-vsock-pci', 'expected':True},         # guest-cid property must be greater than 2
13823ea4f30SEduardo Habkost    {'device':'virtio-9p-ccw', 'expected':True},           # 9pfs device couldn't find fsdev with the id = NULL
13923ea4f30SEduardo Habkost    {'device':'virtio-9p-device', 'expected':True},        # 9pfs device couldn't find fsdev with the id = NULL
14023ea4f30SEduardo Habkost    {'device':'virtio-9p-pci', 'expected':True},           # 9pfs device couldn't find fsdev with the id = NULL
14123ea4f30SEduardo Habkost    {'device':'virtio-blk-ccw', 'expected':True},          # drive property not set
14223ea4f30SEduardo Habkost    {'device':'virtio-blk-device', 'expected':True},       # drive property not set
14323ea4f30SEduardo Habkost    {'device':'virtio-blk-device', 'expected':True},       # drive property not set
14423ea4f30SEduardo Habkost    {'device':'virtio-blk-pci', 'expected':True},          # drive property not set
14523ea4f30SEduardo Habkost    {'device':'virtio-crypto-ccw', 'expected':True},       # 'cryptodev' parameter expects a valid object
14623ea4f30SEduardo Habkost    {'device':'virtio-crypto-device', 'expected':True},    # 'cryptodev' parameter expects a valid object
14723ea4f30SEduardo Habkost    {'device':'virtio-crypto-pci', 'expected':True},       # 'cryptodev' parameter expects a valid object
14823ea4f30SEduardo Habkost    {'device':'virtio-input-host-device', 'expected':True}, # evdev property is required
14923ea4f30SEduardo Habkost    {'device':'virtio-input-host-pci', 'expected':True},   # evdev property is required
15023ea4f30SEduardo Habkost    {'device':'xen-pvdevice', 'expected':True},            # Device ID invalid, it must always be supplied
15123ea4f30SEduardo Habkost    {'device':'vhost-vsock-ccw', 'expected':True},         # guest-cid property must be greater than 2
15223ea4f30SEduardo Habkost    {'device':'ALTR.timer', 'expected':True},              # "clock-frequency" property must be provided
15323ea4f30SEduardo Habkost    {'device':'zpci', 'expected':True},                    # target must be defined
15423ea4f30SEduardo Habkost    {'device':'pnv-(occ|icp|lpc)', 'expected':True},       # required link 'xics' not found: Property '.xics' not found
15523ea4f30SEduardo Habkost    {'device':'powernv-cpu-.*', 'expected':True},          # pnv_core_realize: required link 'xics' not found: Property '.xics' not found
15623ea4f30SEduardo Habkost
15723ea4f30SEduardo Habkost    # ioapic devices are already created by pc and will fail:
15823ea4f30SEduardo Habkost    {'machine':'q35|pc.*', 'device':'kvm-ioapic', 'expected':True}, # Only 1 ioapics allowed
15923ea4f30SEduardo Habkost    {'machine':'q35|pc.*', 'device':'ioapic', 'expected':True},     # Only 1 ioapics allowed
16023ea4f30SEduardo Habkost
1612363d5eeSThomas Huth    # "spapr-cpu-core needs a pseries machine"
1622363d5eeSThomas Huth    {'machine':'(?!pseries).*', 'device':'.*-spapr-cpu-core', 'expected':True},
1632363d5eeSThomas Huth
16423ea4f30SEduardo Habkost    # KVM-specific devices shouldn't be tried without accel=kvm:
16523ea4f30SEduardo Habkost    {'accel':'(?!kvm).*', 'device':'kvmclock', 'expected':True},
16623ea4f30SEduardo Habkost
16723ea4f30SEduardo Habkost    # xen-specific machines and devices:
16823ea4f30SEduardo Habkost    {'accel':'(?!xen).*', 'machine':'xen.*', 'expected':True},
16923ea4f30SEduardo Habkost    {'accel':'(?!xen).*', 'device':'xen-.*', 'expected':True},
17023ea4f30SEduardo Habkost
17123ea4f30SEduardo Habkost    # this fails on some machine-types, but not all, so they don't have expected=True:
17223ea4f30SEduardo Habkost    {'device':'vmgenid'}, # vmgenid requires DMA write support in fw_cfg, which this machine type does not provide
17323ea4f30SEduardo Habkost
17423ea4f30SEduardo Habkost    # Silence INFO messages for errors that are common on multiple
17523ea4f30SEduardo Habkost    # devices/machines:
17623ea4f30SEduardo Habkost    {'log':r"No '[\w-]+' bus found for device '[\w-]+'"},
17723ea4f30SEduardo Habkost    {'log':r"images* must be given with the 'pflash' parameter"},
17823ea4f30SEduardo Habkost    {'log':r"(Guest|ROM|Flash|Kernel) image must be specified"},
17923ea4f30SEduardo Habkost    {'log':r"[cC]ould not load [\w ]+ (BIOS|bios) '[\w-]+\.bin'"},
18023ea4f30SEduardo Habkost    {'log':r"Couldn't find rom image '[\w-]+\.bin'"},
18123ea4f30SEduardo Habkost    {'log':r"speed mismatch trying to attach usb device"},
18223ea4f30SEduardo Habkost    {'log':r"Can't create a second ISA bus"},
18323ea4f30SEduardo Habkost    {'log':r"duplicate fw_cfg file name"},
18423ea4f30SEduardo Habkost    # sysbus-related error messages: most machines reject most dynamic sysbus devices:
18523ea4f30SEduardo Habkost    {'log':r"Option '-device [\w.,-]+' cannot be handled by this machine"},
18623ea4f30SEduardo Habkost    {'log':r"Device [\w.,-]+ is not supported by this machine yet"},
18723ea4f30SEduardo Habkost    {'log':r"Device [\w.,-]+ can not be dynamically instantiated"},
18823ea4f30SEduardo Habkost    {'log':r"Platform Bus: Can not fit MMIO region of size "},
18923ea4f30SEduardo Habkost    # other more specific errors we will ignore:
19023ea4f30SEduardo Habkost    {'device':'.*-spapr-cpu-core', 'log':r"CPU core type should be"},
19123ea4f30SEduardo Habkost    {'log':r"MSI(-X)? is not supported by interrupt controller"},
19223ea4f30SEduardo Habkost    {'log':r"pxb-pcie? devices cannot reside on a PCIe? bus"},
19323ea4f30SEduardo Habkost    {'log':r"Ignoring smp_cpus value"},
19423ea4f30SEduardo Habkost    {'log':r"sd_init failed: Drive 'sd0' is already in use because it has been automatically connected to another device"},
19523ea4f30SEduardo Habkost    {'log':r"This CPU requires a smaller page size than the system is using"},
19623ea4f30SEduardo Habkost    {'log':r"MSI-X support is mandatory in the S390 architecture"},
19723ea4f30SEduardo Habkost    {'log':r"rom check and register reset failed"},
19823ea4f30SEduardo Habkost    {'log':r"Unable to initialize GIC, CPUState for CPU#0 not valid"},
19923ea4f30SEduardo Habkost    {'log':r"Multiple VT220 operator consoles are not supported"},
20023ea4f30SEduardo Habkost    {'log':r"core 0 already populated"},
20123ea4f30SEduardo Habkost    {'log':r"could not find stage1 bootloader"},
20223ea4f30SEduardo Habkost
20323ea4f30SEduardo Habkost    # other exitcode=1 failures not listed above will just generate INFO messages:
20423ea4f30SEduardo Habkost    {'exitcode':1, 'loglevel':logging.INFO},
20523ea4f30SEduardo Habkost
20623ea4f30SEduardo Habkost    # KNOWN CRASHES:
20723ea4f30SEduardo Habkost    # Known crashes will generate error messages, but won't be fatal.
20823ea4f30SEduardo Habkost    # Those entries must be removed once we fix the crashes.
20923ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"Device 'serial0' is in use", 'loglevel':logging.ERROR},
21023ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"qemu_net_client_setup: Assertion `!peer->peer' failed", 'loglevel':logging.ERROR},
21123ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r'RAMBlock "[\w.-]+" already registered', 'loglevel':logging.ERROR},
21223ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"find_ram_offset: Assertion `size != 0' failed.", 'loglevel':logging.ERROR},
21323ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"add_cpreg_to_hashtable: code should not be reached", 'loglevel':logging.ERROR},
21423ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"qemu_alloc_display: Assertion `surface->image != NULL' failed", 'loglevel':logging.ERROR},
21523ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"Unexpected error in error_set_from_qdev_prop_error", 'loglevel':logging.ERROR},
21623ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"Object .* is not an instance of type spapr-machine", 'loglevel':logging.ERROR},
21723ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"Object .* is not an instance of type generic-pc-machine", 'loglevel':logging.ERROR},
21823ea4f30SEduardo Habkost    {'exitcode':-6, 'log':r"Object .* is not an instance of type e500-ccsr", 'loglevel':logging.ERROR},
2192a6f395bSEduardo Habkost    {'exitcode':-6, 'log':r"vmstate_register_with_alias_id: Assertion `!se->compat \|\| se->instance_id == 0' failed", 'loglevel':logging.ERROR},
220*44d815e8SEduardo Habkost    {'exitcode':-6, 'device':'isa-fdc', 'loglevel':logging.ERROR, 'expected':True},
22123ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'gus', 'loglevel':logging.ERROR, 'expected':True},
22223ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'isa-serial', 'loglevel':logging.ERROR, 'expected':True},
22323ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'sb16', 'loglevel':logging.ERROR, 'expected':True},
22423ea4f30SEduardo Habkost    {'exitcode':-11, 'device':'cs4231a', 'loglevel':logging.ERROR, 'expected':True},
22523ea4f30SEduardo Habkost    {'exitcode':-11, 'machine':'isapc', 'device':'.*-iommu', 'loglevel':logging.ERROR, 'expected':True},
226*44d815e8SEduardo Habkost    {'exitcode':-11, 'device':'mioe3680_pci', 'loglevel':logging.ERROR, 'expected':True},
227*44d815e8SEduardo Habkost    {'exitcode':-11, 'device':'pcm3680_pci', 'loglevel':logging.ERROR, 'expected':True},
228*44d815e8SEduardo Habkost    {'exitcode':-11, 'device':'kvaser_pci', 'loglevel':logging.ERROR, 'expected':True},
22923ea4f30SEduardo Habkost
23023ea4f30SEduardo Habkost    # everything else (including SIGABRT and SIGSEGV) will be a fatal error:
23123ea4f30SEduardo Habkost    {'exitcode':None, 'fatal':True, 'loglevel':logging.FATAL},
23223ea4f30SEduardo Habkost]
23323ea4f30SEduardo Habkost
23423ea4f30SEduardo Habkost
23523ea4f30SEduardo Habkostdef whitelistTestCaseMatch(wl, t):
23623ea4f30SEduardo Habkost    """Check if a test case specification can match a whitelist entry
23723ea4f30SEduardo Habkost
23823ea4f30SEduardo Habkost    This only checks if a whitelist entry is a candidate match
23923ea4f30SEduardo Habkost    for a given test case, it won't check if the test case
24023ea4f30SEduardo Habkost    results/output match the entry.  See whitelistResultMatch().
24123ea4f30SEduardo Habkost    """
24223ea4f30SEduardo Habkost    return (('machine' not in wl or
24323ea4f30SEduardo Habkost             'machine' not in t or
24423ea4f30SEduardo Habkost             re.match(wl['machine'] + '$', t['machine'])) and
24523ea4f30SEduardo Habkost            ('accel' not in wl or
24623ea4f30SEduardo Habkost             'accel' not in t or
24723ea4f30SEduardo Habkost             re.match(wl['accel'] + '$', t['accel'])) and
24823ea4f30SEduardo Habkost            ('device' not in wl or
24923ea4f30SEduardo Habkost             'device' not in t or
25023ea4f30SEduardo Habkost             re.match(wl['device'] + '$', t['device'])))
25123ea4f30SEduardo Habkost
25223ea4f30SEduardo Habkost
25323ea4f30SEduardo Habkostdef whitelistCandidates(t):
25423ea4f30SEduardo Habkost    """Generate the list of candidates that can match a test case"""
25523ea4f30SEduardo Habkost    for i, wl in enumerate(ERROR_WHITELIST):
25623ea4f30SEduardo Habkost        if whitelistTestCaseMatch(wl, t):
25723ea4f30SEduardo Habkost            yield (i, wl)
25823ea4f30SEduardo Habkost
25923ea4f30SEduardo Habkost
26023ea4f30SEduardo Habkostdef findExpectedResult(t):
26123ea4f30SEduardo Habkost    """Check if there's an expected=True whitelist entry for a test case
26223ea4f30SEduardo Habkost
26323ea4f30SEduardo Habkost    Returns (i, wl) tuple, where i is the index in
26423ea4f30SEduardo Habkost    ERROR_WHITELIST and wl is the whitelist entry itself.
26523ea4f30SEduardo Habkost    """
26623ea4f30SEduardo Habkost    for i, wl in whitelistCandidates(t):
26723ea4f30SEduardo Habkost        if wl.get('expected'):
26823ea4f30SEduardo Habkost            return (i, wl)
26923ea4f30SEduardo Habkost
27023ea4f30SEduardo Habkost
27123ea4f30SEduardo Habkostdef whitelistResultMatch(wl, r):
27223ea4f30SEduardo Habkost    """Check if test case results/output match a whitelist entry
27323ea4f30SEduardo Habkost
27423ea4f30SEduardo Habkost    It is valid to call this function only if
27523ea4f30SEduardo Habkost    whitelistTestCaseMatch() is True for the entry (e.g. on
27623ea4f30SEduardo Habkost    entries returned by whitelistCandidates())
27723ea4f30SEduardo Habkost    """
27823ea4f30SEduardo Habkost    assert whitelistTestCaseMatch(wl, r['testcase'])
27923ea4f30SEduardo Habkost    return ((wl.get('exitcode', 1) is None or
28023ea4f30SEduardo Habkost             r['exitcode'] == wl.get('exitcode', 1)) and
28123ea4f30SEduardo Habkost            ('log' not in wl or
28223ea4f30SEduardo Habkost             re.search(wl['log'], r['log'], re.MULTILINE)))
28323ea4f30SEduardo Habkost
28423ea4f30SEduardo Habkost
28523ea4f30SEduardo Habkostdef checkResultWhitelist(r):
28623ea4f30SEduardo Habkost    """Look up whitelist entry for a given test case result
28723ea4f30SEduardo Habkost
28823ea4f30SEduardo Habkost    Returns (i, wl) tuple, where i is the index in
28923ea4f30SEduardo Habkost    ERROR_WHITELIST and wl is the whitelist entry itself.
29023ea4f30SEduardo Habkost    """
29123ea4f30SEduardo Habkost    for i, wl in whitelistCandidates(r['testcase']):
29223ea4f30SEduardo Habkost        if whitelistResultMatch(wl, r):
29323ea4f30SEduardo Habkost            return i, wl
29423ea4f30SEduardo Habkost
29523ea4f30SEduardo Habkost    raise Exception("this should never happen")
29623ea4f30SEduardo Habkost
29723ea4f30SEduardo Habkost
29823ea4f30SEduardo Habkostdef qemuOptsEscape(s):
29923ea4f30SEduardo Habkost    """Escape option value QemuOpts"""
30023ea4f30SEduardo Habkost    return s.replace(",", ",,")
30123ea4f30SEduardo Habkost
30223ea4f30SEduardo Habkost
30323ea4f30SEduardo Habkostdef formatTestCase(t):
30423ea4f30SEduardo Habkost    """Format test case info as "key=value key=value" for prettier logging output"""
30523ea4f30SEduardo Habkost    return ' '.join('%s=%s' % (k, v) for k, v in t.items())
30623ea4f30SEduardo Habkost
30723ea4f30SEduardo Habkost
30823ea4f30SEduardo Habkostdef qomListTypeNames(vm, **kwargs):
30923ea4f30SEduardo Habkost    """Run qom-list-types QMP command, return type names"""
31023ea4f30SEduardo Habkost    types = vm.command('qom-list-types', **kwargs)
31123ea4f30SEduardo Habkost    return [t['name'] for t in types]
31223ea4f30SEduardo Habkost
31323ea4f30SEduardo Habkost
31423ea4f30SEduardo Habkostdef infoQDM(vm):
31523ea4f30SEduardo Habkost    """Parse 'info qdm' output"""
31623ea4f30SEduardo Habkost    args = {'command-line': 'info qdm'}
31723ea4f30SEduardo Habkost    devhelp = vm.command('human-monitor-command', **args)
31823ea4f30SEduardo Habkost    for l in devhelp.split('\n'):
31923ea4f30SEduardo Habkost        l = l.strip()
32023ea4f30SEduardo Habkost        if l == '' or l.endswith(':'):
32123ea4f30SEduardo Habkost            continue
32223ea4f30SEduardo Habkost        d = {'name': re.search(r'name "([^"]+)"', l).group(1),
32323ea4f30SEduardo Habkost             'no-user': (re.search(', no-user', l) is not None)}
32423ea4f30SEduardo Habkost        yield d
32523ea4f30SEduardo Habkost
32623ea4f30SEduardo Habkost
32723ea4f30SEduardo Habkostclass QemuBinaryInfo(object):
32823ea4f30SEduardo Habkost    def __init__(self, binary, devtype):
32923ea4f30SEduardo Habkost        if devtype is None:
33023ea4f30SEduardo Habkost            devtype = 'device'
33123ea4f30SEduardo Habkost
33223ea4f30SEduardo Habkost        self.binary = binary
33323ea4f30SEduardo Habkost        self._machine_info = {}
33423ea4f30SEduardo Habkost
33523ea4f30SEduardo Habkost        dbg("devtype: %r", devtype)
33623ea4f30SEduardo Habkost        args = ['-S', '-machine', 'none,accel=kvm:tcg']
33723ea4f30SEduardo Habkost        dbg("querying info for QEMU binary: %s", binary)
33823ea4f30SEduardo Habkost        vm = QEMUMachine(binary=binary, args=args)
33923ea4f30SEduardo Habkost        vm.launch()
34023ea4f30SEduardo Habkost        try:
34123ea4f30SEduardo Habkost            self.alldevs = set(qomListTypeNames(vm, implements=devtype, abstract=False))
34223ea4f30SEduardo Habkost            # there's no way to query DeviceClass::user_creatable using QMP,
34323ea4f30SEduardo Habkost            # so use 'info qdm':
34423ea4f30SEduardo Habkost            self.no_user_devs = set([d['name'] for d in infoQDM(vm, ) if d['no-user']])
34523ea4f30SEduardo Habkost            self.machines = list(m['name'] for m in vm.command('query-machines'))
34623ea4f30SEduardo Habkost            self.user_devs = self.alldevs.difference(self.no_user_devs)
34723ea4f30SEduardo Habkost            self.kvm_available = vm.command('query-kvm')['enabled']
34823ea4f30SEduardo Habkost        finally:
34923ea4f30SEduardo Habkost            vm.shutdown()
35023ea4f30SEduardo Habkost
35123ea4f30SEduardo Habkost    def machineInfo(self, machine):
35223ea4f30SEduardo Habkost        """Query for information on a specific machine-type
35323ea4f30SEduardo Habkost
35423ea4f30SEduardo Habkost        Results are cached internally, in case the same machine-
35523ea4f30SEduardo Habkost        type is queried multiple times.
35623ea4f30SEduardo Habkost        """
35723ea4f30SEduardo Habkost        if machine in self._machine_info:
35823ea4f30SEduardo Habkost            return self._machine_info[machine]
35923ea4f30SEduardo Habkost
36023ea4f30SEduardo Habkost        mi = {}
36123ea4f30SEduardo Habkost        args = ['-S', '-machine', '%s' % (machine)]
36223ea4f30SEduardo Habkost        dbg("querying machine info for binary=%s machine=%s", self.binary, machine)
36323ea4f30SEduardo Habkost        vm = QEMUMachine(binary=self.binary, args=args)
36423ea4f30SEduardo Habkost        try:
36523ea4f30SEduardo Habkost            vm.launch()
36623ea4f30SEduardo Habkost            mi['runnable'] = True
36723ea4f30SEduardo Habkost        except KeyboardInterrupt:
36823ea4f30SEduardo Habkost            raise
36923ea4f30SEduardo Habkost        except:
37023ea4f30SEduardo Habkost            dbg("exception trying to run binary=%s machine=%s", self.binary, machine, exc_info=sys.exc_info())
37123ea4f30SEduardo Habkost            dbg("log: %r", vm.get_log())
37223ea4f30SEduardo Habkost            mi['runnable'] = False
37323ea4f30SEduardo Habkost
37423ea4f30SEduardo Habkost        vm.shutdown()
37523ea4f30SEduardo Habkost        self._machine_info[machine] = mi
37623ea4f30SEduardo Habkost        return mi
37723ea4f30SEduardo Habkost
37823ea4f30SEduardo Habkost
37923ea4f30SEduardo HabkostBINARY_INFO = {}
38023ea4f30SEduardo Habkost
38123ea4f30SEduardo Habkost
38223ea4f30SEduardo Habkostdef getBinaryInfo(args, binary):
38323ea4f30SEduardo Habkost    if binary not in BINARY_INFO:
38423ea4f30SEduardo Habkost        BINARY_INFO[binary] = QemuBinaryInfo(binary, args.devtype)
38523ea4f30SEduardo Habkost    return BINARY_INFO[binary]
38623ea4f30SEduardo Habkost
38723ea4f30SEduardo Habkost
38823ea4f30SEduardo Habkostdef checkOneCase(args, testcase):
38923ea4f30SEduardo Habkost    """Check one specific case
39023ea4f30SEduardo Habkost
39123ea4f30SEduardo Habkost    Returns a dictionary containing failure information on error,
39223ea4f30SEduardo Habkost    or None on success
39323ea4f30SEduardo Habkost    """
39423ea4f30SEduardo Habkost    binary = testcase['binary']
39523ea4f30SEduardo Habkost    accel = testcase['accel']
39623ea4f30SEduardo Habkost    machine = testcase['machine']
39723ea4f30SEduardo Habkost    device = testcase['device']
39823ea4f30SEduardo Habkost
39923ea4f30SEduardo Habkost    dbg("will test: %r", testcase)
40023ea4f30SEduardo Habkost
40123ea4f30SEduardo Habkost    args = ['-S', '-machine', '%s,accel=%s' % (machine, accel),
40223ea4f30SEduardo Habkost            '-device', qemuOptsEscape(device)]
40323ea4f30SEduardo Habkost    cmdline = ' '.join([binary] + args)
40423ea4f30SEduardo Habkost    dbg("will launch QEMU: %s", cmdline)
40523ea4f30SEduardo Habkost    vm = QEMUMachine(binary=binary, args=args)
40623ea4f30SEduardo Habkost
40723ea4f30SEduardo Habkost    exc_traceback = None
40823ea4f30SEduardo Habkost    try:
40923ea4f30SEduardo Habkost        vm.launch()
41023ea4f30SEduardo Habkost    except KeyboardInterrupt:
41123ea4f30SEduardo Habkost        raise
41223ea4f30SEduardo Habkost    except:
41323ea4f30SEduardo Habkost        exc_traceback = traceback.format_exc()
41423ea4f30SEduardo Habkost        dbg("Exception while running test case")
41523ea4f30SEduardo Habkost    finally:
41623ea4f30SEduardo Habkost        vm.shutdown()
41723ea4f30SEduardo Habkost        ec = vm.exitcode()
41823ea4f30SEduardo Habkost        log = vm.get_log()
41923ea4f30SEduardo Habkost
42023ea4f30SEduardo Habkost    if exc_traceback is not None or ec != 0:
42123ea4f30SEduardo Habkost        return {'exc_traceback':exc_traceback,
42223ea4f30SEduardo Habkost                'exitcode':ec,
42323ea4f30SEduardo Habkost                'log':log,
42423ea4f30SEduardo Habkost                'testcase':testcase,
42523ea4f30SEduardo Habkost                'cmdline':cmdline}
42623ea4f30SEduardo Habkost
42723ea4f30SEduardo Habkost
42823ea4f30SEduardo Habkostdef binariesToTest(args, testcase):
42923ea4f30SEduardo Habkost    if args.qemu:
43023ea4f30SEduardo Habkost        r = args.qemu
43123ea4f30SEduardo Habkost    else:
43223ea4f30SEduardo Habkost        r = glob.glob('./*-softmmu/qemu-system-*')
43323ea4f30SEduardo Habkost    return r
43423ea4f30SEduardo Habkost
43523ea4f30SEduardo Habkost
43623ea4f30SEduardo Habkostdef accelsToTest(args, testcase):
43723ea4f30SEduardo Habkost    if getBinaryInfo(args, testcase['binary']).kvm_available:
43823ea4f30SEduardo Habkost        yield 'kvm'
43923ea4f30SEduardo Habkost    yield 'tcg'
44023ea4f30SEduardo Habkost
44123ea4f30SEduardo Habkost
44223ea4f30SEduardo Habkostdef machinesToTest(args, testcase):
44323ea4f30SEduardo Habkost    return getBinaryInfo(args, testcase['binary']).machines
44423ea4f30SEduardo Habkost
44523ea4f30SEduardo Habkost
44623ea4f30SEduardo Habkostdef devicesToTest(args, testcase):
44723ea4f30SEduardo Habkost    return getBinaryInfo(args, testcase['binary']).user_devs
44823ea4f30SEduardo Habkost
44923ea4f30SEduardo Habkost
45023ea4f30SEduardo HabkostTESTCASE_VARIABLES = [
45123ea4f30SEduardo Habkost    ('binary', binariesToTest),
45223ea4f30SEduardo Habkost    ('accel', accelsToTest),
45323ea4f30SEduardo Habkost    ('machine', machinesToTest),
45423ea4f30SEduardo Habkost    ('device', devicesToTest),
45523ea4f30SEduardo Habkost]
45623ea4f30SEduardo Habkost
45723ea4f30SEduardo Habkost
45823ea4f30SEduardo Habkostdef genCases1(args, testcases, var, fn):
45923ea4f30SEduardo Habkost    """Generate new testcases for one variable
46023ea4f30SEduardo Habkost
46123ea4f30SEduardo Habkost    If an existing item already has a variable set, don't
46223ea4f30SEduardo Habkost    generate new items and just return it directly. This
46323ea4f30SEduardo Habkost    allows the "-t" command-line option to be used to choose
46423ea4f30SEduardo Habkost    a specific test case.
46523ea4f30SEduardo Habkost    """
46623ea4f30SEduardo Habkost    for testcase in testcases:
46723ea4f30SEduardo Habkost        if var in testcase:
46823ea4f30SEduardo Habkost            yield testcase.copy()
46923ea4f30SEduardo Habkost        else:
47023ea4f30SEduardo Habkost            for i in fn(args, testcase):
47123ea4f30SEduardo Habkost                t = testcase.copy()
47223ea4f30SEduardo Habkost                t[var] = i
47323ea4f30SEduardo Habkost                yield t
47423ea4f30SEduardo Habkost
47523ea4f30SEduardo Habkost
47623ea4f30SEduardo Habkostdef genCases(args, testcase):
47723ea4f30SEduardo Habkost    """Generate test cases for all variables
47823ea4f30SEduardo Habkost    """
47923ea4f30SEduardo Habkost    cases = [testcase.copy()]
48023ea4f30SEduardo Habkost    for var, fn in TESTCASE_VARIABLES:
48123ea4f30SEduardo Habkost        dbg("var: %r, fn: %r", var, fn)
48223ea4f30SEduardo Habkost        cases = genCases1(args, cases, var, fn)
48323ea4f30SEduardo Habkost    return cases
48423ea4f30SEduardo Habkost
48523ea4f30SEduardo Habkost
48623ea4f30SEduardo Habkostdef casesToTest(args, testcase):
48723ea4f30SEduardo Habkost    cases = genCases(args, testcase)
48823ea4f30SEduardo Habkost    if args.random:
48923ea4f30SEduardo Habkost        cases = list(cases)
49023ea4f30SEduardo Habkost        cases = random.sample(cases, min(args.random, len(cases)))
49123ea4f30SEduardo Habkost    if args.debug:
49223ea4f30SEduardo Habkost        cases = list(cases)
49323ea4f30SEduardo Habkost        dbg("%d test cases to test", len(cases))
49423ea4f30SEduardo Habkost    if args.shuffle:
49523ea4f30SEduardo Habkost        cases = list(cases)
49623ea4f30SEduardo Habkost        random.shuffle(cases)
49723ea4f30SEduardo Habkost    return cases
49823ea4f30SEduardo Habkost
49923ea4f30SEduardo Habkost
50023ea4f30SEduardo Habkostdef logFailure(f, level):
50123ea4f30SEduardo Habkost    t = f['testcase']
50223ea4f30SEduardo Habkost    logger.log(level, "failed: %s", formatTestCase(t))
50323ea4f30SEduardo Habkost    logger.log(level, "cmdline: %s", f['cmdline'])
50423ea4f30SEduardo Habkost    for l in f['log'].strip().split('\n'):
50523ea4f30SEduardo Habkost        logger.log(level, "log: %s", l)
50623ea4f30SEduardo Habkost    logger.log(level, "exit code: %r", f['exitcode'])
50723ea4f30SEduardo Habkost    if f['exc_traceback']:
50823ea4f30SEduardo Habkost        logger.log(level, "exception:")
50923ea4f30SEduardo Habkost        for l in f['exc_traceback'].split('\n'):
51023ea4f30SEduardo Habkost            logger.log(level, "  %s", l.rstrip('\n'))
51123ea4f30SEduardo Habkost
51223ea4f30SEduardo Habkost
51323ea4f30SEduardo Habkostdef main():
51423ea4f30SEduardo Habkost    parser = argparse.ArgumentParser(description="QEMU -device crash test")
51523ea4f30SEduardo Habkost    parser.add_argument('-t', metavar='KEY=VALUE', nargs='*',
51623ea4f30SEduardo Habkost                        help="Limit test cases to KEY=VALUE",
51723ea4f30SEduardo Habkost                        action='append', dest='testcases', default=[])
51823ea4f30SEduardo Habkost    parser.add_argument('-d', '--debug', action='store_true',
51923ea4f30SEduardo Habkost                        help='debug output')
52023ea4f30SEduardo Habkost    parser.add_argument('-v', '--verbose', action='store_true', default=True,
52123ea4f30SEduardo Habkost                        help='verbose output')
52223ea4f30SEduardo Habkost    parser.add_argument('-q', '--quiet', dest='verbose', action='store_false',
52323ea4f30SEduardo Habkost                        help='non-verbose output')
52423ea4f30SEduardo Habkost    parser.add_argument('-r', '--random', type=int, metavar='COUNT',
52523ea4f30SEduardo Habkost                        help='run a random sample of COUNT test cases',
52623ea4f30SEduardo Habkost                        default=0)
52723ea4f30SEduardo Habkost    parser.add_argument('--shuffle', action='store_true',
52823ea4f30SEduardo Habkost                        help='Run test cases in random order')
52923ea4f30SEduardo Habkost    parser.add_argument('--dry-run', action='store_true',
53023ea4f30SEduardo Habkost                        help="Don't run any tests, just generate list")
53123ea4f30SEduardo Habkost    parser.add_argument('-D', '--devtype', metavar='TYPE',
53223ea4f30SEduardo Habkost                        help="Test only device types that implement TYPE")
53323ea4f30SEduardo Habkost    parser.add_argument('-Q', '--quick', action='store_true', default=True,
53423ea4f30SEduardo Habkost                        help="Quick mode: skip test cases that are expected to fail")
53523ea4f30SEduardo Habkost    parser.add_argument('-F', '--full', action='store_false', dest='quick',
53623ea4f30SEduardo Habkost                        help="Full mode: test cases that are expected to fail")
53723ea4f30SEduardo Habkost    parser.add_argument('--strict', action='store_true', dest='strict',
53823ea4f30SEduardo Habkost                        help="Treat all warnings as fatal")
53923ea4f30SEduardo Habkost    parser.add_argument('qemu', nargs='*', metavar='QEMU',
54023ea4f30SEduardo Habkost                        help='QEMU binary to run')
54123ea4f30SEduardo Habkost    args = parser.parse_args()
54223ea4f30SEduardo Habkost
54323ea4f30SEduardo Habkost    if args.debug:
54423ea4f30SEduardo Habkost        lvl = logging.DEBUG
54523ea4f30SEduardo Habkost    elif args.verbose:
54623ea4f30SEduardo Habkost        lvl = logging.INFO
54723ea4f30SEduardo Habkost    else:
54823ea4f30SEduardo Habkost        lvl = logging.WARN
54923ea4f30SEduardo Habkost    logging.basicConfig(stream=sys.stdout, level=lvl, format='%(levelname)s: %(message)s')
55023ea4f30SEduardo Habkost
55123ea4f30SEduardo Habkost    fatal_failures = []
55223ea4f30SEduardo Habkost    wl_stats = {}
55323ea4f30SEduardo Habkost    skipped = 0
55423ea4f30SEduardo Habkost    total = 0
55523ea4f30SEduardo Habkost
55623ea4f30SEduardo Habkost    tc = {}
55723ea4f30SEduardo Habkost    dbg("testcases: %r", args.testcases)
55823ea4f30SEduardo Habkost    if args.testcases:
55923ea4f30SEduardo Habkost        for t in chain(*args.testcases):
56023ea4f30SEduardo Habkost            for kv in t.split():
56123ea4f30SEduardo Habkost                k, v = kv.split('=', 1)
56223ea4f30SEduardo Habkost                tc[k] = v
56323ea4f30SEduardo Habkost
56423ea4f30SEduardo Habkost    if len(binariesToTest(args, tc)) == 0:
56523ea4f30SEduardo Habkost        print >>sys.stderr, "No QEMU binary found"
56623ea4f30SEduardo Habkost        parser.print_usage(sys.stderr)
56723ea4f30SEduardo Habkost        return 1
56823ea4f30SEduardo Habkost
56923ea4f30SEduardo Habkost    for t in casesToTest(args, tc):
57023ea4f30SEduardo Habkost        logger.info("running test case: %s", formatTestCase(t))
57123ea4f30SEduardo Habkost        total += 1
57223ea4f30SEduardo Habkost
57323ea4f30SEduardo Habkost        expected_match = findExpectedResult(t)
57423ea4f30SEduardo Habkost        if (args.quick and
57523ea4f30SEduardo Habkost                (expected_match or
57623ea4f30SEduardo Habkost                 not getBinaryInfo(args, t['binary']).machineInfo(t['machine'])['runnable'])):
57723ea4f30SEduardo Habkost            dbg("skipped: %s", formatTestCase(t))
57823ea4f30SEduardo Habkost            skipped += 1
57923ea4f30SEduardo Habkost            continue
58023ea4f30SEduardo Habkost
58123ea4f30SEduardo Habkost        if args.dry_run:
58223ea4f30SEduardo Habkost            continue
58323ea4f30SEduardo Habkost
58423ea4f30SEduardo Habkost        try:
58523ea4f30SEduardo Habkost            f = checkOneCase(args, t)
58623ea4f30SEduardo Habkost        except KeyboardInterrupt:
58723ea4f30SEduardo Habkost            break
58823ea4f30SEduardo Habkost
58923ea4f30SEduardo Habkost        if f:
59023ea4f30SEduardo Habkost            i, wl = checkResultWhitelist(f)
59123ea4f30SEduardo Habkost            dbg("testcase: %r, whitelist match: %r", t, wl)
59223ea4f30SEduardo Habkost            wl_stats.setdefault(i, []).append(f)
59323ea4f30SEduardo Habkost            level = wl.get('loglevel', logging.DEBUG)
59423ea4f30SEduardo Habkost            logFailure(f, level)
59523ea4f30SEduardo Habkost            if wl.get('fatal') or (args.strict and level >= logging.WARN):
59623ea4f30SEduardo Habkost                fatal_failures.append(f)
59723ea4f30SEduardo Habkost        else:
59823ea4f30SEduardo Habkost            dbg("success: %s", formatTestCase(t))
59923ea4f30SEduardo Habkost            if expected_match:
60023ea4f30SEduardo Habkost                logger.warn("Didn't fail as expected: %s", formatTestCase(t))
60123ea4f30SEduardo Habkost
60223ea4f30SEduardo Habkost    logger.info("Total: %d test cases", total)
60323ea4f30SEduardo Habkost    if skipped:
60423ea4f30SEduardo Habkost        logger.info("Skipped %d test cases", skipped)
60523ea4f30SEduardo Habkost
60623ea4f30SEduardo Habkost    if args.debug:
60723ea4f30SEduardo Habkost        stats = sorted([(len(wl_stats.get(i, [])), wl) for i, wl in enumerate(ERROR_WHITELIST)])
60823ea4f30SEduardo Habkost        for count, wl in stats:
60923ea4f30SEduardo Habkost            dbg("whitelist entry stats: %d: %r", count, wl)
61023ea4f30SEduardo Habkost
61123ea4f30SEduardo Habkost    if fatal_failures:
61223ea4f30SEduardo Habkost        for f in fatal_failures:
61323ea4f30SEduardo Habkost            t = f['testcase']
61423ea4f30SEduardo Habkost            logger.error("Fatal failure: %s", formatTestCase(t))
61523ea4f30SEduardo Habkost        logger.error("Fatal failures on some machine/device combinations")
61623ea4f30SEduardo Habkost        return 1
61723ea4f30SEduardo Habkost
61823ea4f30SEduardo Habkostif __name__ == '__main__':
61923ea4f30SEduardo Habkost    sys.exit(main())
620